about summary refs log tree commit diff
path: root/converter/other
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other')
-rw-r--r--converter/other/Makefile238
-rw-r--r--converter/other/README.JPEG397
-rwxr-xr-xconverter/other/anytopnm544
-rw-r--r--converter/other/bmepsoe.c539
-rw-r--r--converter/other/bmepsoe.h79
-rw-r--r--converter/other/bmptopnm.c1477
-rw-r--r--converter/other/cameratopam/COPYRIGHT35
-rw-r--r--converter/other/cameratopam/Makefile37
-rw-r--r--converter/other/cameratopam/bayer.h43
-rw-r--r--converter/other/cameratopam/camera.c1781
-rw-r--r--converter/other/cameratopam/camera.h131
-rw-r--r--converter/other/cameratopam/cameratopam.c906
-rw-r--r--converter/other/cameratopam/canon.c172
-rw-r--r--converter/other/cameratopam/canon.h13
-rw-r--r--converter/other/cameratopam/decode.c172
-rw-r--r--converter/other/cameratopam/decode.h22
-rw-r--r--converter/other/cameratopam/dng.c73
-rw-r--r--converter/other/cameratopam/dng.h2
-rw-r--r--converter/other/cameratopam/foveon.c790
-rw-r--r--converter/other/cameratopam/foveon.h14
-rw-r--r--converter/other/cameratopam/global_variables.h55
-rw-r--r--converter/other/cameratopam/identify.c1183
-rw-r--r--converter/other/cameratopam/identify.h11
-rw-r--r--converter/other/cameratopam/ljpeg.c141
-rw-r--r--converter/other/cameratopam/ljpeg.h17
-rw-r--r--converter/other/cameratopam/util.c83
-rw-r--r--converter/other/cameratopam/util.h16
-rw-r--r--converter/other/dithers.h91
-rw-r--r--converter/other/exif.c1030
-rw-r--r--converter/other/exif.h56
-rw-r--r--converter/other/fiasco/Makefile59
-rw-r--r--converter/other/fiasco/README.netpbm41
-rw-r--r--converter/other/fiasco/binerror.c143
-rw-r--r--converter/other/fiasco/binerror.h50
-rw-r--r--converter/other/fiasco/buttons.c510
-rw-r--r--converter/other/fiasco/buttons.h50
-rw-r--r--converter/other/fiasco/codec/Makefile27
-rw-r--r--converter/other/fiasco/codec/approx.c702
-rw-r--r--converter/other/fiasco/codec/approx.h30
-rw-r--r--converter/other/fiasco/codec/bintree.c94
-rw-r--r--converter/other/fiasco/codec/bintree.h43
-rw-r--r--converter/other/fiasco/codec/coder.c965
-rw-r--r--converter/other/fiasco/codec/coder.h24
-rw-r--r--converter/other/fiasco/codec/coeff.c369
-rw-r--r--converter/other/fiasco/codec/coeff.h61
-rw-r--r--converter/other/fiasco/codec/control.c276
-rw-r--r--converter/other/fiasco/codec/control.h33
-rw-r--r--converter/other/fiasco/codec/cwfa.h107
-rw-r--r--converter/other/fiasco/codec/decoder.c1532
-rw-r--r--converter/other/fiasco/codec/decoder.h70
-rw-r--r--converter/other/fiasco/codec/dfiasco.c398
-rw-r--r--converter/other/fiasco/codec/dfiasco.h38
-rw-r--r--converter/other/fiasco/codec/domain-pool.c986
-rw-r--r--converter/other/fiasco/codec/domain-pool.h75
-rw-r--r--converter/other/fiasco/codec/ip.c324
-rw-r--r--converter/other/fiasco/codec/ip.h37
-rw-r--r--converter/other/fiasco/codec/motion.c338
-rw-r--r--converter/other/fiasco/codec/motion.h35
-rw-r--r--converter/other/fiasco/codec/mwfa.c864
-rw-r--r--converter/other/fiasco/codec/mwfa.h44
-rw-r--r--converter/other/fiasco/codec/options.c894
-rw-r--r--converter/other/fiasco/codec/options.h80
-rw-r--r--converter/other/fiasco/codec/prediction.c629
-rw-r--r--converter/other/fiasco/codec/prediction.h36
-rw-r--r--converter/other/fiasco/codec/subdivide.c650
-rw-r--r--converter/other/fiasco/codec/subdivide.h33
-rw-r--r--converter/other/fiasco/codec/tiling.c239
-rw-r--r--converter/other/fiasco/codec/tiling.h40
-rw-r--r--converter/other/fiasco/codec/wfa.h141
-rw-r--r--converter/other/fiasco/codec/wfalib.c774
-rw-r--r--converter/other/fiasco/codec/wfalib.h66
-rw-r--r--converter/other/fiasco/config.h96
-rw-r--r--converter/other/fiasco/display.c422
-rw-r--r--converter/other/fiasco/display.h49
-rw-r--r--converter/other/fiasco/doc/README.LIB51
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_delete.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_new.3432
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_basisfile.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_chroma_quality.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_comment.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_frame_pattern.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_optimizations.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_prediction.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_progress_meter.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_quantization.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_smoothing.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_tiling.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_title.31
-rw-r--r--converter/other/fiasco/doc/fiasco_c_options_set_video_param.31
-rw-r--r--converter/other/fiasco/doc/fiasco_coder.3106
-rw-r--r--converter/other/fiasco/doc/fiasco_d_options.31
-rw-r--r--converter/other/fiasco/doc/fiasco_d_options_delete.31
-rw-r--r--converter/other/fiasco/doc/fiasco_d_options_new.3122
-rw-r--r--converter/other/fiasco/doc/fiasco_d_options_set_4_2_0_format.31
-rw-r--r--converter/other/fiasco/doc/fiasco_d_options_set_magnification.31
-rw-r--r--converter/other/fiasco/doc/fiasco_d_options_set_smoothing.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_delete.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_get_comment.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_get_frame.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_get_framerate.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_get_height.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_get_length.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_get_title.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_get_width.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_is_color.31
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_new.3194
-rw-r--r--converter/other/fiasco/doc/fiasco_decoder_write_frame.31
-rw-r--r--converter/other/fiasco/doc/fiasco_get_error_message.341
-rw-r--r--converter/other/fiasco/doc/fiasco_get_verbosity.31
-rw-r--r--converter/other/fiasco/doc/fiasco_image.31
-rw-r--r--converter/other/fiasco/doc/fiasco_image_delete.31
-rw-r--r--converter/other/fiasco/doc/fiasco_image_get_height.31
-rw-r--r--converter/other/fiasco/doc/fiasco_image_get_width.31
-rw-r--r--converter/other/fiasco/doc/fiasco_image_is_color.31
-rw-r--r--converter/other/fiasco/doc/fiasco_image_new.395
-rw-r--r--converter/other/fiasco/doc/fiasco_options.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_delete.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_new.3441
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_4_2_0_format.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_basisfile.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_chroma_quality.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_frame_pattern.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_magnification.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_optimizations.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_prediction.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_progress_meter.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_quantization.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_smoothing.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_tiling.31
-rw-r--r--converter/other/fiasco/doc/fiasco_options_set_video_param.31
-rw-r--r--converter/other/fiasco/doc/fiasco_renderer.31
-rw-r--r--converter/other/fiasco/doc/fiasco_renderer_delete.31
-rw-r--r--converter/other/fiasco/doc/fiasco_renderer_new.3125
-rw-r--r--converter/other/fiasco/doc/fiasco_renderer_render.31
-rw-r--r--converter/other/fiasco/doc/fiasco_set_verbosity.346
-rw-r--r--converter/other/fiasco/fiasco.h425
-rw-r--r--converter/other/fiasco/fiascotopnm.c477
-rw-r--r--converter/other/fiasco/getopt.c1002
-rw-r--r--converter/other/fiasco/getopt.h129
-rw-r--r--converter/other/fiasco/getopt1.c189
-rw-r--r--converter/other/fiasco/input/Makefile26
-rw-r--r--converter/other/fiasco/input/basis.c141
-rw-r--r--converter/other/fiasco/input/basis.h26
-rw-r--r--converter/other/fiasco/input/matrices.c644
-rw-r--r--converter/other/fiasco/input/matrices.h27
-rw-r--r--converter/other/fiasco/input/mc.c334
-rw-r--r--converter/other/fiasco/input/mc.h28
-rw-r--r--converter/other/fiasco/input/nd.c237
-rw-r--r--converter/other/fiasco/input/nd.h28
-rw-r--r--converter/other/fiasco/input/read.c499
-rw-r--r--converter/other/fiasco/input/read.h31
-rw-r--r--converter/other/fiasco/input/tree.c303
-rw-r--r--converter/other/fiasco/input/tree.h28
-rw-r--r--converter/other/fiasco/input/weights.c200
-rw-r--r--converter/other/fiasco/input/weights.h27
-rw-r--r--converter/other/fiasco/lib/Makefile33
-rw-r--r--converter/other/fiasco/lib/arith.c708
-rw-r--r--converter/other/fiasco/lib/arith.h122
-rw-r--r--converter/other/fiasco/lib/bit-io.c327
-rw-r--r--converter/other/fiasco/lib/bit-io.h58
-rw-r--r--converter/other/fiasco/lib/dither.c1892
-rw-r--r--converter/other/fiasco/lib/dither.h27
-rw-r--r--converter/other/fiasco/lib/error.c326
-rw-r--r--converter/other/fiasco/lib/error.h39
-rw-r--r--converter/other/fiasco/lib/image.c512
-rw-r--r--converter/other/fiasco/lib/image.h59
-rw-r--r--converter/other/fiasco/lib/list.c258
-rw-r--r--converter/other/fiasco/lib/list.h72
-rw-r--r--converter/other/fiasco/lib/macros.h70
-rw-r--r--converter/other/fiasco/lib/misc.c563
-rw-r--r--converter/other/fiasco/lib/misc.h98
-rw-r--r--converter/other/fiasco/lib/mvcode.c14
-rw-r--r--converter/other/fiasco/lib/mvcode.h6
-rw-r--r--converter/other/fiasco/lib/rpf.c223
-rw-r--r--converter/other/fiasco/lib/rpf.h47
-rw-r--r--converter/other/fiasco/lib/types.h38
-rw-r--r--converter/other/fiasco/output/Makefile26
-rw-r--r--converter/other/fiasco/output/matrices.c547
-rw-r--r--converter/other/fiasco/output/matrices.h28
-rw-r--r--converter/other/fiasco/output/mc.c250
-rw-r--r--converter/other/fiasco/output/mc.h28
-rw-r--r--converter/other/fiasco/output/nd.c244
-rw-r--r--converter/other/fiasco/output/nd.h27
-rw-r--r--converter/other/fiasco/output/tree.c176
-rw-r--r--converter/other/fiasco/output/tree.h27
-rw-r--r--converter/other/fiasco/output/weights.c200
-rw-r--r--converter/other/fiasco/output/weights.h27
-rw-r--r--converter/other/fiasco/output/write.c250
-rw-r--r--converter/other/fiasco/output/write.h28
-rw-r--r--converter/other/fiasco/params.c727
-rw-r--r--converter/other/fiasco/params.h61
-rw-r--r--converter/other/fiasco/pnmtofiasco.c411
-rw-r--r--converter/other/fiasco/system.fiascorc120
-rw-r--r--converter/other/fitstopnm.c494
-rw-r--r--converter/other/gemtopnm.c305
-rw-r--r--converter/other/giftopnm.c1460
-rw-r--r--converter/other/hdifftopam.c156
-rw-r--r--converter/other/infotopam.c543
-rw-r--r--converter/other/jbig/ANNOUNCE243
-rw-r--r--converter/other/jbig/Makefile47
-rw-r--r--converter/other/jbig/README.Netpbm12
-rw-r--r--converter/other/jbig/jbig.c2905
-rw-r--r--converter/other/jbig/jbig.doc721
-rw-r--r--converter/other/jbig/jbig.h267
-rw-r--r--converter/other/jbig/jbig_tab.c428
-rw-r--r--converter/other/jbig/jbigtopnm.c286
-rw-r--r--converter/other/jbig/pnmtojbig.c463
-rw-r--r--converter/other/jpeg2000/Makefile77
-rw-r--r--converter/other/jpeg2000/jpeg2ktopam.c498
-rw-r--r--converter/other/jpeg2000/libjasper/Makefile28
-rw-r--r--converter/other/jpeg2000/libjasper/Makefile.common41
-rw-r--r--converter/other/jpeg2000/libjasper/README17
-rw-r--r--converter/other/jpeg2000/libjasper/base/Makefile21
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_debug.c186
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_getopt.c217
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_image.c968
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_init.c200
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_malloc.c167
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_seq.c475
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_stream.c1204
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_string.c145
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_tvp.c286
-rw-r--r--converter/other/jpeg2000/libjasper/base/jas_version.c116
-rw-r--r--converter/other/jpeg2000/libjasper/base/partlist1
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_debug.h161
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_fix.h406
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_getopt.h178
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_image.h593
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_init.h128
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_malloc.h171
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_math.h164
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_seq.h348
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_stream.h498
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_string.h143
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_tvp.h198
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_types.h14
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig228
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jas_version.h167
-rw-r--r--converter/other/jpeg2000/libjasper/include/jasper/jasper.h137
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/Makefile19
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_cod.c928
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_cod.h347
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_dec.c649
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_dec.h134
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_enc.c414
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/partlist1
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/Makefile22
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_bs.c478
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_bs.h280
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_cod.h127
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_cs.c1614
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_cs.h812
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_dec.c2334
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_dec.h745
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_enc.c2624
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_enc.h695
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_fix.h193
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_flt.h129
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_math.c170
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_math.h155
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mct.c337
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mct.h160
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.c228
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h174
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mqdec.c339
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mqdec.h320
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c441
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.h285
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c1125
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.h235
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1cod.c537
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1cod.h344
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c954
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h137
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.c1008
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.h142
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.c733
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h348
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t2dec.c626
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t2dec.h144
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t2enc.c704
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_t2enc.h155
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_tagtree.c426
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_tagtree.h216
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_tsfb.c662
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_tsfb.h222
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_util.c243
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/jpc_util.h126
-rw-r--r--converter/other/jpeg2000/libjasper/jpc/partlist1
-rw-r--r--converter/other/jpeg2000/libjasper/partlist4
-rw-r--r--converter/other/jpeg2000/libjasper_compat.h24
-rw-r--r--converter/other/jpeg2000/pamtojpeg2k.c522
-rw-r--r--converter/other/jpegdatasource.c183
-rw-r--r--converter/other/jpegdatasource.h18
-rw-r--r--converter/other/jpegtopnm.c970
-rw-r--r--converter/other/pamrgbatopng.c150
-rw-r--r--converter/other/pamtodjvurle.c293
-rw-r--r--converter/other/pamtofits.c304
-rw-r--r--converter/other/pamtohdiff.c142
-rw-r--r--converter/other/pamtohtmltbl.c284
-rw-r--r--converter/other/pamtopfm.c304
-rw-r--r--converter/other/pamtopnm.c155
-rw-r--r--converter/other/pamtosvg/Makefile55
-rw-r--r--converter/other/pamtosvg/README109
-rw-r--r--converter/other/pamtosvg/autotrace.c220
-rw-r--r--converter/other/pamtosvg/autotrace.h258
-rw-r--r--converter/other/pamtosvg/bitmap.c116
-rw-r--r--converter/other/pamtosvg/bitmap.h53
-rw-r--r--converter/other/pamtosvg/curve.c314
-rw-r--r--converter/other/pamtosvg/curve.h160
-rw-r--r--converter/other/pamtosvg/epsilon-equal.c19
-rw-r--r--converter/other/pamtosvg/epsilon-equal.h20
-rw-r--r--converter/other/pamtosvg/exception.c55
-rw-r--r--converter/other/pamtosvg/exception.h43
-rw-r--r--converter/other/pamtosvg/fit.c1923
-rw-r--r--converter/other/pamtosvg/fit.h34
-rw-r--r--converter/other/pamtosvg/image-header.h19
-rw-r--r--converter/other/pamtosvg/image-proc.c516
-rw-r--r--converter/other/pamtosvg/image-proc.h42
-rw-r--r--converter/other/pamtosvg/logreport.c17
-rw-r--r--converter/other/pamtosvg/logreport.h28
-rw-r--r--converter/other/pamtosvg/message.h47
-rw-r--r--converter/other/pamtosvg/output-svg.c130
-rw-r--r--converter/other/pamtosvg/output-svg.h37
-rw-r--r--converter/other/pamtosvg/pamtosvg.c395
-rw-r--r--converter/other/pamtosvg/pamtosvg.test6
-rw-r--r--converter/other/pamtosvg/point.h8
-rw-r--r--converter/other/pamtosvg/pxl-outline.c1370
-rw-r--r--converter/other/pamtosvg/pxl-outline.h79
-rw-r--r--converter/other/pamtosvg/spline.c193
-rw-r--r--converter/other/pamtosvg/spline.h90
-rw-r--r--converter/other/pamtosvg/testgrid.svg5
-rw-r--r--converter/other/pamtosvg/testline.svg5
-rw-r--r--converter/other/pamtosvg/thin-image.c373
-rw-r--r--converter/other/pamtosvg/thin-image.h37
-rw-r--r--converter/other/pamtosvg/vector.c254
-rw-r--r--converter/other/pamtosvg/vector.h71
-rw-r--r--converter/other/pamtotga.c572
-rw-r--r--converter/other/pamtotiff.c1110
-rw-r--r--converter/other/pamtouil.c438
-rw-r--r--converter/other/pamtoxvmini.c250
-rw-r--r--converter/other/pbmtopgm.c80
-rw-r--r--converter/other/pclxl.h390
-rw-r--r--converter/other/pfmtopam.c395
-rw-r--r--converter/other/pgmtopbm.c723
-rw-r--r--converter/other/pgmtoppm.c153
-rw-r--r--converter/other/pm_tiff.h41
-rw-r--r--converter/other/pngtopnm.c1096
-rw-r--r--converter/other/pngtxt.c315
-rw-r--r--converter/other/pngtxt.h13
-rw-r--r--converter/other/pnmtoddif.c611
-rw-r--r--converter/other/pnmtojpeg.c1098
-rw-r--r--converter/other/pnmtopalm/LICENSE16
-rw-r--r--converter/other/pnmtopalm/Makefile35
-rw-r--r--converter/other/pnmtopalm/README57
-rw-r--r--converter/other/pnmtopalm/gen_palm_colormap.c24
-rw-r--r--converter/other/pnmtopalm/palm.h66
-rw-r--r--converter/other/pnmtopalm/palmcolor8.map235
-rw-r--r--converter/other/pnmtopalm/palmcolormap.c277
-rw-r--r--converter/other/pnmtopalm/palmgray1.map4
-rw-r--r--converter/other/pnmtopalm/palmgray2.map6
-rw-r--r--converter/other/pnmtopalm/palmgray4.map8
-rw-r--r--converter/other/pnmtopalm/palmtopnm.c1131
-rw-r--r--converter/other/pnmtopalm/pnmtopalm.c1235
-rw-r--r--converter/other/pnmtopclxl.c1204
-rwxr-xr-xconverter/other/pnmtoplainpnm3
-rw-r--r--converter/other/pnmtopng.README101
-rw-r--r--converter/other/pnmtopng.c2745
-rw-r--r--converter/other/pnmtops.c1323
-rw-r--r--converter/other/pnmtorast.c310
-rw-r--r--converter/other/pnmtorle.c267
-rw-r--r--converter/other/pnmtosgi.c354
-rw-r--r--converter/other/pnmtosir.c146
-rw-r--r--converter/other/pnmtotiffcmyk.c1000
-rw-r--r--converter/other/pnmtoxwd.c505
-rw-r--r--converter/other/ppmtopgm.c95
-rw-r--r--converter/other/pstopnm.c899
-rwxr-xr-xconverter/other/pstopnm.csh301
-rw-r--r--converter/other/rast.c465
-rw-r--r--converter/other/rast.h111
-rw-r--r--converter/other/rasttopnm.c263
-rw-r--r--converter/other/rla.h45
-rw-r--r--converter/other/rlatopam.c433
-rw-r--r--converter/other/rletopnm.c497
-rw-r--r--converter/other/sgi.h33
-rw-r--r--converter/other/sgitopnm.c463
-rw-r--r--converter/other/sirtopnm.c95
-rw-r--r--converter/other/svgtopam.c940
-rw-r--r--converter/other/tiff.c468
-rw-r--r--converter/other/tifftopnm.c1062
-rw-r--r--converter/other/x10wd.h32
-rw-r--r--converter/other/x11wd.h82
-rw-r--r--converter/other/xwdtopnm.c1280
-rw-r--r--converter/other/zeisstopnm.c187
396 files changed, 115093 insertions, 0 deletions
diff --git a/converter/other/Makefile b/converter/other/Makefile
new file mode 100644
index 00000000..4585c45d
--- /dev/null
+++ b/converter/other/Makefile
@@ -0,0 +1,238 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+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
+
+SUBDIRS = jbig pnmtopalm jpeg2000 cameratopam pamtosvg
+ifneq ($(BUILD_FIASCO), N)
+  SUBDIRS += fiasco
+endif
+
+INCLUDES = -I$(SRCDIR)/util 
+ifneq ($(TIFFLIB),NONE)
+  ifneq ($(TIFFHDR_DIR)x,x)
+    INCLUDES += -I$(TIFFHDR_DIR)
+  endif
+endif
+
+ifeq ($(shell libpng-config --version),)
+  ifneq ($(PNGLIB),NONE)
+    HAVE_PNGLIB = Y
+    ifneq ($(PNGHDR_DIR)x,x)
+      INCLUDES += -I$(PNGHDR_DIR)
+    endif
+    ifneq ($(ZHDR_DIR)x,x)
+      INCLUDES += -I$(ZHDR_DIR)
+    endif
+  endif
+else
+  HAVE_PNGLIB = Y
+  INCLUDES += $(shell libpng-config --cflags)
+endif
+
+ifneq ($(JPEGLIB),NONE)
+  ifneq ($(JPEGHDR_DIR)x,x)
+    INCLUDES += -I$(JPEGHDR_DIR)
+  endif
+endif
+ifneq ($(URTLIB),NONE)
+  ifneq ($(URTHDR_DIR)x,x)
+    INCLUDES += -I$(URTHDR_DIR)
+  endif
+endif
+ifneq ($(XML2_LIBS),NONE)
+  ifneq ($(XML2_CFLAGS),NONE)
+    INCLUDES += $(XML2_CFLAGS)
+  endif
+endif
+
+ifeq ($(TIFFLIB),NONE)
+  TIFF_PREREQ_MISSING = Y
+endif
+
+TIFFLIB_EXTRALIBS =
+ifeq ($(TIFFLIB_NEEDS_JPEG),Y)
+  ifeq ($(JPEGLIB),NONE)
+    TIFF_PREREQ_MISSING = Y
+  else
+    TIFFLIB_EXTRALIBS += $(JPEGLIB)
+  endif
+endif
+ifeq ($(TIFFLIB_NEEDS_Z),Y)
+  ifeq ($(ZLIB),NONE)
+    TIFF_PREREQ_MISSING = Y
+  else
+    TIFFLIB_EXTRALIBS += $(ZLIB)
+  endif
+endif
+
+PORTBINARIES =  bmptopnm fitstopnm \
+		gemtopnm giftopnm hdifftopam infotopam \
+		pamtodjvurle pamtofits \
+		pamtohdiff pamtohtmltbl pamtopfm pamtopnm pamtouil \
+		pamtoxvmini \
+		pbmtopgm pfmtopam \
+	        pgmtopbm pgmtoppm ppmtopgm pnmtoddif \
+		pnmtopclxl \
+		pnmtosgi pnmtosir pamtotga pnmtoxwd pstopnm \
+		rlatopam sgitopnm sirtopnm xwdtopnm zeisstopnm
+
+BINARIES = $(PORTBINARIES) pnmtorast rasttopnm
+
+ifeq ($(HAVE_PNGLIB),Y)
+  BINARIES += pnmtopng pngtopnm pamrgbatopng
+endif
+ifneq ($(JPEGLIB),NONE)
+  BINARIES += jpegtopnm pnmtojpeg
+endif
+ifneq ($(TIFF_PREREQ_MISSING),Y)
+  BINARIES += tifftopnm pamtotiff pnmtotiffcmyk
+endif
+ifneq ($(URTLIB),NONE)
+  BINARIES += rletopnm pnmtorle
+endif
+ifneq ($(ZLIB),NONE)
+  BINARIES += pnmtops
+endif
+
+ifneq ($(XML2_LIBS),NONE)
+  BINARIES += svgtopam
+endif 
+
+MERGEBINARIES = $(BINARIES)
+
+EXTRA_OBJECTS = exif.o rast.o pngtxt.o bmepsoe.o
+ifneq ($(JPEGLIB),NONE)
+  EXTRA_OBJECTS += jpegdatasource.o
+endif
+ifneq (($TIFF_PREREQ_MISSING),Y)
+  EXTRA_OBJECTS += tiff.o
+endif
+
+OBJECTS = $(BINARIES:%=%.o) $(EXTRA_OBJECTS)
+MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2) $(EXTRA_OBJECTS)
+
+
+SCRIPTS = anytopnm pnmtoplainpnm
+
+.PHONY: all
+all:	$(BINARIES) $(SUBDIRS:%=%/all)
+
+include $(SRCDIR)/Makefile.common
+
+ifeq ($(NEED_RUNTIME_PATH),Y)
+  LIBOPTR = -runtime
+else
+  LIBOPTR =
+endif
+
+LIBOPTS_TIFF = $(shell $(LIBOPT) $(NETPBMLIB) \
+  $(LIBOPTR) $(TIFFLIB) $(TIFFLIB_EXTRALIBS))
+
+tifftopnm pamtotiff pnmtotiffcmyk: %: %.o tiff.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $@.o tiff.o \
+	  $(LIBOPTS_TIFF) $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
+
+ifeq ($(shell libpng-config --version),)
+  PNGLIB_LIBOPTS = $(shell $(LIBOPT) $(LIBOPTR) $(PNGLIB) $(ZLIB))
+else
+  PNGLIB_LIBOPTS = $(shell libpng-config --ldflags)
+endif
+
+pngtopnm: %: %.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $@.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) \
+	  $(PNGLIB_LIBOPTS) $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
+
+pnmtopng: %: %.o pngtxt.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $@.o pngtxt.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) \
+	  $(PNGLIB_LIBOPTS) $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
+
+pamrgbatopng: %: %.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $@.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) $(PNGLIB_LIBOPTS) \
+	  $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
+
+jpegtopnm: %: %.o jpegdatasource.o exif.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $< jpegdatasource.o exif.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIB)) \
+	  $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD) 
+
+pnmtojpeg: %: %.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $@.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR) $(JPEGLIB)) \
+	  $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
+
+svgtopam: %: %.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $@.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR)) \
+	  $(XML2_LIBS) $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
+
+# 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)
+endif
+
+rletopnm pnmtorle: %: %.o $(NETPBMLIB) $(URTLIBDEP) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $@.o \
+	  $(shell $(LIBOPT) $(URTLIB) $(NETPBMLIB)) \
+	  $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
+
+pnmtops: %: %.o bmepsoe.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $@.o bmepsoe.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB) $(ZLIB)) \
+	  $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
+
+pnmtorast rasttopnm: %: %.o rast.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $@.o rast.o \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) \
+	  $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
+
+bmptopnm.o bmptopnm.o2: bmp.h
+
+pamtotga.o pamtotga.o2: tga.h
+
+install.bin: install.bin.local
+.PHONY: install.bin.local
+install.bin.local: $(PKGDIR)/bin
+# Remember that $(SYMLINK) might just be a copy command.
+# backward compatibility: program used to be named pnmnoraw
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) pnmtoplainpnm$(EXE) pnmnoraw
+# backward compatibility: program used to be gemtopbm
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) gemtopnm$(EXE) gemtopbm
+# In October 2001, pnmtojpeg replaced ppmtojpeg
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) pnmtojpeg$(EXE) ppmtojpeg
+# In March 2002, bmptopnm replaced bmptoppm
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) bmptopnm$(EXE) bmptoppm
+# In May 2002, pamtouil replaced ppmtouil
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) pamtouil$(EXE) ppmtouil
+# In March 2005, we realized that pamtopnm obviates pnmtopnm
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) pamtopnm$(EXE) pnmtopnm
+# In October 2005, pamtofits replaced pnmtofits
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) pamtofits$(EXE) pnmtofits
+ifneq ($(TIFF_PREREQ_MISSING),Y)
+# In October 2005, pamtotiff replaced pnmtotiff
+	cd $(PKGDIR)/bin ; \
+	$(SYMLINK) pamtotiff$(EXE) pnmtotiff
+endif
\ No newline at end of file
diff --git a/converter/other/README.JPEG b/converter/other/README.JPEG
new file mode 100644
index 00000000..5d2d941c
--- /dev/null
+++ b/converter/other/README.JPEG
@@ -0,0 +1,397 @@
+THIS IS THE README FILE FROM THE JPEG LIBRARY, 2000.03.06.  IT IS INCLUDED
+VERBATIM, INCLUDING ITS COPYRIGHT AND LICENSE NOTICES, IN THE NETPBM 
+PACKAGE AS ONE OF THE TERMS UNDER WHICH THE INDEPENDENT JPEG GROUP GRANTED
+PERMISSION TO BRYAN HENDERSON TODAY TO DISTRIBUTE THE PPMTOJPEG AND 
+JPEGTOPPM COMPONENTS OF NETPBM, WHICH ARE DERIVED FROM THE CJPEG AND DJPEG
+PROGRAMS IN THE JPEG LIBRARY PACKAGE.
+
+AS PROVIDED BY THE LICENSE GIVEN TO BRYAN, BRYAN PROPAGATES THE SAME
+LICENSE TO YOU, WITH RESPECT TO PPMTOJPEG AND JPEGTOPPM.
+
+
+
+The Independent JPEG Group's JPEG software
+==========================================
+
+README for release 6b of 27-Mar-1998
+====================================
+
+This distribution contains the sixth public release of the Independent JPEG
+Group's free JPEG software.  You are welcome to redistribute this software and
+to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
+
+Serious users of this software (particularly those incorporating it into
+larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to
+our electronic mailing list.  Mailing list members are notified of updates
+and have a chance to participate in technical discussions, etc.
+
+This software is the work of Tom Lane, Philip Gladstone, Jim Boucher,
+Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi,
+Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG
+Group.
+
+IJG is not affiliated with the official ISO JPEG standards committee.
+
+
+DOCUMENTATION ROADMAP
+=====================
+
+This file contains the following sections:
+
+OVERVIEW            General description of JPEG and the IJG software.
+LEGAL ISSUES        Copyright, lack of warranty, terms of distribution.
+REFERENCES          Where to learn more about JPEG.
+ARCHIVE LOCATIONS   Where to find newer versions of this software.
+RELATED SOFTWARE    Other stuff you should get.
+FILE FORMAT WARS    Software *not* to get.
+TO DO               Plans for future IJG releases.
+
+Other documentation files in the distribution are:
+
+User documentation:
+  install.doc       How to configure and install the IJG software.
+  usage.doc         Usage instructions for cjpeg, djpeg, jpegtran,
+                    rdjpgcom, and wrjpgcom.
+  *.1               Unix-style man pages for programs (same info as usage.doc).
+  wizard.doc        Advanced usage instructions for JPEG wizards only.
+  change.log        Version-to-version change highlights.
+Programmer and internal documentation:
+  libjpeg.doc       How to use the JPEG library in your own programs.
+  example.c         Sample code for calling the JPEG library.
+  structure.doc     Overview of the JPEG library's internal structure.
+  filelist.doc      Road map of IJG files.
+  coderules.doc     Coding style rules --- please read if you contribute code.
+
+Please read at least the files install.doc and usage.doc.  Useful information
+can also be found in the JPEG FAQ (Frequently Asked Questions) article.  See
+ARCHIVE LOCATIONS below to find out where to obtain the FAQ article.
+
+If you want to understand how the JPEG code works, we suggest reading one or
+more of the REFERENCES, then looking at the documentation files (in roughly
+the order listed) before diving into the code.
+
+
+OVERVIEW
+========
+
+This package contains C software to implement JPEG image compression and
+decompression.  JPEG (pronounced "jay-peg") is a standardized compression
+method for full-color and gray-scale images.  JPEG is intended for compressing
+"real-world" scenes; line drawings, cartoons and other non-realistic images
+are not its strong suit.  JPEG is lossy, meaning that the output image is not
+exactly identical to the input image.  Hence you must not use JPEG if you
+have to have identical output bits.  However, on typical photographic images,
+very good compression levels can be obtained with no visible change, and
+remarkably high compression levels are possible if you can tolerate a
+low-quality image.  For more details, see the references, or just experiment
+with various compression settings.
+
+This software implements JPEG baseline, extended-sequential, and progressive
+compression processes.  Provision is made for supporting all variants of these
+processes, although some uncommon parameter settings aren't implemented yet.
+For legal reasons, we are not distributing code for the arithmetic-coding
+variants of JPEG; see LEGAL ISSUES.  We have made no provision for supporting
+the hierarchical or lossless processes defined in the standard.
+
+We provide a set of library routines for reading and writing JPEG image files,
+plus two sample applications "cjpeg" and "djpeg", which use the library to
+perform conversion between JPEG and some other popular image file formats.
+The library is intended to be reused in other applications.
+
+In order to support file conversion and viewing software, we have included
+considerable functionality beyond the bare JPEG coding/decoding capability;
+for example, the color quantization modules are not strictly part of JPEG
+decoding, but they are essential for output to colormapped file formats or
+colormapped displays.  These extra functions can be compiled out of the
+library if not required for a particular application.  We have also included
+"jpegtran", a utility for lossless transcoding between different JPEG
+processes, and "rdjpgcom" and "wrjpgcom", two simple applications for
+inserting and extracting textual comments in JFIF files.
+
+The emphasis in designing this software has been on achieving portability and
+flexibility, while also making it fast enough to be useful.  In particular,
+the software is not intended to be read as a tutorial on JPEG.  (See the
+REFERENCES section for introductory material.)  Rather, it is intended to
+be reliable, portable, industrial-strength code.  We do not claim to have
+achieved that goal in every aspect of the software, but we strive for it.
+
+We welcome the use of this software as a component of commercial products.
+No royalty is required, but we do ask for an acknowledgement in product
+documentation, as described under LEGAL ISSUES.
+
+
+LEGAL ISSUES
+============
+
+In plain English:
+
+1. We don't promise that this software works.  (But if you find any bugs,
+   please let us know!)
+2. You can use this software for whatever you want.  You don't have to pay us.
+3. You may not pretend that you wrote this software.  If you use it in a
+   program, you must acknowledge somewhere in your documentation that
+   you've used the IJG code.
+
+In legalese:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose.  This software is provided "AS IS", and you,
+its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-1998, Thomas G. Lane.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+software (or portions thereof) for any purpose, without fee, subject to these
+conditions:
+(1) If any part of the source code for this software is distributed, then this
+README file must be included, with this copyright and no-warranty notice
+unaltered; and any additions, deletions, or changes to the original files
+must be clearly indicated in accompanying documentation.
+(2) If only executable code is distributed, then the accompanying
+documentation must state that "this software is based in part on the work of
+the Independent JPEG Group".
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library.  If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived from
+it.  This software may be referred to only as "the Independent JPEG Group's
+software".
+
+We specifically permit and encourage the use of this software as the basis of
+commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+
+
+ansi2knr.c is included in this distribution by permission of L. Peter Deutsch,
+sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA.
+ansi2knr.c is NOT covered by the above copyright and conditions, but instead
+by the usual distribution terms of the Free Software Foundation; principally,
+that you must include source code if you redistribute it.  (See the file
+ansi2knr.c for full details.)  However, since ansi2knr.c is not needed as part
+of any program generated from the IJG code, this does not limit you more than
+the foregoing paragraphs do.
+
+The Unix configuration script "configure" was produced with GNU Autoconf.
+It is copyright by the Free Software Foundation but is freely distributable.
+The same holds for its supporting scripts (config.guess, config.sub,
+ltconfig, ltmain.sh).  Another support script, install-sh, is copyright
+by M.I.T. but is also freely distributable.
+
+It appears that the arithmetic coding option of the JPEG spec is covered by
+patents owned by IBM, AT&T, and Mitsubishi.  Hence arithmetic coding cannot
+legally be used without obtaining one or more licenses.  For this reason,
+support for arithmetic coding has been removed from the free JPEG software.
+(Since arithmetic coding provides only a marginal gain over the unpatented
+Huffman mode, it is unlikely that very many implementations will support it.)
+So far as we are aware, there are no patent restrictions on the remaining
+code.
+
+The IJG distribution formerly included code to read and write GIF files.
+To avoid entanglement with the Unisys LZW patent, GIF reading support has
+been removed altogether, and the GIF writer has been simplified to produce
+"uncompressed GIFs".  This technique does not use the LZW algorithm; the
+resulting GIF files are larger than usual, but are readable by all standard
+GIF decoders.
+
+We are required to state that
+    "The Graphics Interchange Format(c) is the Copyright property of
+    CompuServe Incorporated.  GIF(sm) is a Service Mark property of
+    CompuServe Incorporated."
+
+
+REFERENCES
+==========
+
+We highly recommend reading one or more of these references before trying to
+understand the innards of the JPEG software.
+
+The best short technical introduction to the JPEG compression algorithm is
+	Wallace, Gregory K.  "The JPEG Still Picture Compression Standard",
+	Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
+(Adjacent articles in that issue discuss MPEG motion picture compression,
+applications of JPEG, and related topics.)  If you don't have the CACM issue
+handy, a PostScript file containing a revised version of Wallace's article is
+available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz.  The file (actually
+a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
+omits the sample images that appeared in CACM, but it includes corrections
+and some added material.  Note: the Wallace article is copyright ACM and IEEE,
+and it may not be used for commercial purposes.
+
+A somewhat less technical, more leisurely introduction to JPEG can be found in
+"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by
+M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1.  This book provides
+good explanations and example C code for a multitude of compression methods
+including JPEG.  It is an excellent source if you are comfortable reading C
+code but don't know much about data compression in general.  The book's JPEG
+sample code is far from industrial-strength, but when you are ready to look
+at a full implementation, you've got one here...
+
+The best full description of JPEG is the textbook "JPEG Still Image Data
+Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published
+by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.  Price US$59.95, 638 pp.
+The book includes the complete text of the ISO JPEG standards (DIS 10918-1
+and draft DIS 10918-2).  This is by far the most complete exposition of JPEG
+in existence, and we highly recommend it.
+
+The JPEG standard itself is not available electronically; you must order a
+paper copy through ISO or ITU.  (Unless you feel a need to own a certified
+official copy, we recommend buying the Pennebaker and Mitchell book instead;
+it's much cheaper and includes a great deal of useful explanatory material.)
+In the USA, copies of the standard may be ordered from ANSI Sales at (212)
+642-4900, or from Global Engineering Documents at (800) 854-7179.  (ANSI
+doesn't take credit card orders, but Global does.)  It's not cheap: as of
+1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7%
+shipping/handling.  The standard is divided into two parts, Part 1 being the
+actual specification, while Part 2 covers compliance testing methods.  Part 1
+is titled "Digital Compression and Coding of Continuous-tone Still Images,
+Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
+10918-1, ITU-T T.81.  Part 2 is titled "Digital Compression and Coding of
+Continuous-tone Still Images, Part 2: Compliance testing" and has document
+numbers ISO/IEC IS 10918-2, ITU-T T.83.
+
+Some extensions to the original JPEG standard are defined in JPEG Part 3,
+a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84.  IJG
+currently does not support any Part 3 extensions.
+
+The JPEG standard does not specify all details of an interchangeable file
+format.  For the omitted details we follow the "JFIF" conventions, revision
+1.02.  A copy of the JFIF spec is available from:
+	Literature Department
+	C-Cube Microsystems, Inc.
+	1778 McCarthy Blvd.
+	Milpitas, CA 95035
+	phone (408) 944-6300,  fax (408) 944-6314
+A PostScript version of this document is available by FTP at
+ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz.  There is also a plain text
+version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing
+the figures.
+
+The TIFF 6.0 file format specification can be obtained by FTP from
+ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz.  The JPEG incorporation scheme
+found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
+IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
+Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
+(Compression tag 7).  Copies of this Note can be obtained from ftp.sgi.com or
+from ftp://ftp.uu.net/graphics/jpeg/.  It is expected that the next revision
+of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
+Although IJG's own code does not support TIFF/JPEG, the free libtiff library
+uses our library to implement TIFF/JPEG per the Note.  libtiff is available
+from ftp://ftp.sgi.com/graphics/tiff/.
+
+
+ARCHIVE LOCATIONS
+=================
+
+The "official" archive site for this software is ftp.uu.net (Internet
+address 192.48.96.9).  The most recent released version can always be found
+there in directory graphics/jpeg.  This particular version will be archived
+as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz.  If you don't have
+direct Internet access, UUNET's archives are also available via UUCP; contact
+help@uunet.uu.net for information on retrieving files that way.
+
+Numerous Internet sites maintain copies of the UUNET files.  However, only
+ftp.uu.net is guaranteed to have the latest official version.
+
+You can also obtain this software in DOS-compatible "zip" archive format from
+the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or
+on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12
+"JPEG Tools".  Again, these versions may sometimes lag behind the ftp.uu.net
+release.
+
+The JPEG FAQ (Frequently Asked Questions) article is a useful source of
+general information about JPEG.  It is updated constantly and therefore is
+not included in this distribution.  The FAQ is posted every two weeks to
+Usenet newsgroups comp.graphics.misc, news.answers, and other groups.
+It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/
+and other news.answers archive sites, including the official news.answers
+archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.
+If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu
+with body
+	send usenet/news.answers/jpeg-faq/part1
+	send usenet/news.answers/jpeg-faq/part2
+
+
+RELATED SOFTWARE
+================
+
+Numerous viewing and image manipulation programs now support JPEG.  (Quite a
+few of them use this library to do so.)  The JPEG FAQ described above lists
+some of the more popular free and shareware viewers, and tells where to
+obtain them on Internet.
+
+If you are on a Unix machine, we highly recommend Jef Poskanzer's free
+PBMPLUS software, which provides many useful operations on PPM-format image
+files.  In particular, it can convert PPM images to and from a wide range of
+other formats, thus making cjpeg/djpeg considerably more useful.  The latest
+version is distributed by the NetPBM group, and is available from numerous
+sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/.
+Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is;
+you are likely to have difficulty making it work on any non-Unix machine.
+
+A different free JPEG implementation, written by the PVRG group at Stanford,
+is available from ftp://havefun.stanford.edu/pub/jpeg/.  This program
+is designed for research and experimentation rather than production use;
+it is slower, harder to use, and less portable than the IJG code, but it
+is easier to read and modify.  Also, the PVRG code supports lossless JPEG,
+which we do not.  (On the other hand, it doesn't do progressive JPEG.)
+
+
+FILE FORMAT WARS
+================
+
+Some JPEG programs produce files that are not compatible with our library.
+The root of the problem is that the ISO JPEG committee failed to specify a
+concrete file format.  Some vendors "filled in the blanks" on their own,
+creating proprietary formats that no one else could read.  (For example, none
+of the early commercial JPEG implementations for the Macintosh were able to
+exchange compressed files.)
+
+The file format we have adopted is called JFIF (see REFERENCES).  This format
+has been agreed to by a number of major commercial JPEG vendors, and it has
+become the de facto standard.  JFIF is a minimal or "low end" representation.
+We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF
+Technical Note #2) for "high end" applications that need to record a lot of
+additional data about an image.  TIFF/JPEG is fairly new and not yet widely
+supported, unfortunately.
+
+The upcoming JPEG Part 3 standard defines a file format called SPIFF.
+SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should
+be able to read the most common variant of SPIFF.  SPIFF has some technical
+advantages over JFIF, but its major claim to fame is simply that it is an
+official standard rather than an informal one.  At this point it is unclear
+whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto
+standard.  IJG intends to support SPIFF once the standard is frozen, but we
+have not decided whether it should become our default output format or not.
+(In any case, our decoder will remain capable of reading JFIF indefinitely.)
+
+Various proprietary file formats incorporating JPEG compression also exist.
+We have little or no sympathy for the existence of these formats.  Indeed,
+one of the original reasons for developing this free software was to help
+force convergence on common, open format standards for JPEG files.  Don't
+use a proprietary file format!
+
+
+TO DO
+=====
+
+The major thrust for v7 will probably be improvement of visual quality.
+The current method for scaling the quantization tables is known not to be
+very good at low Q values.  We also intend to investigate block boundary
+smoothing, "poor man's variable quantization", and other means of improving
+quality-vs-file-size performance without sacrificing compatibility.
+
+In future versions, we are considering supporting some of the upcoming JPEG
+Part 3 extensions --- principally, variable quantization and the SPIFF file
+format.
+
+As always, speeding things up is of great interest.
+
+Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net.
diff --git a/converter/other/anytopnm b/converter/other/anytopnm
new file mode 100755
index 00000000..6c56b5ef
--- /dev/null
+++ b/converter/other/anytopnm
@@ -0,0 +1,544 @@
+#!/bin/sh
+#
+# anytopnm - attempt to convert an unknown type of image file to a P?M file.
+#
+# 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.
+
+
+
+putInputIntoTempfile() {
+
+    # $1 is the input file specification
+    # $2 is the temporary file name
+    
+    rm -f "$2"
+    if [ "$1" = "-" ] ; then
+            cat > "$2"
+    else
+        # We'd like to do a -e here to test the existence of the filesystem
+        # object per se, and thus give a more specific error message.  But
+        # some systems don't have -e.
+        if [ ! -f "$1" ] ; then
+            echo "$progname: '$1' does not exist or is not a file" 1>&2
+            exit 1
+            fi
+        
+        if [ ! -r "$1" ] ; then
+            echo "$progname: '$1' is not readable" 1>&2
+            exit 1
+            fi
+        
+        if [ -z "$1" ] ; then
+            echo "$progname: '$1' is empty" 1>&2
+            exit 1
+            fi
+        
+        cat < "$1" > "$2"
+        fi
+}
+
+
+
+setMimeType() {
+    # $1 is the file name
+
+    # Christos Zoulas's current 'file' (see Freshmeat) has the --mime option.
+
+    file --mime /dev/null >/dev/null 2>/dev/null
+    if [ $? -eq 0 ]; then
+        # Now that we know the --mime option exists, use it.
+        mimeType=`file --mime "$1" | cut -d: -f2- | cut -c2-`
+    else
+        # file --mime failed; we don't know why, but we assume it's because it
+        # is a traditional 'file' program that doesn't have a --mime option.
+    mimeType="unknown"
+    fi
+}
+
+
+
+computeTypeFromMimeType () {
+
+# $1 is the mime type string
+    
+    case "$1" in
+
+        image/jpeg )
+            filetype="jfif"
+            ;;
+        image/gif )
+            filetype="gif"
+            ;;
+        image/tiff )
+            filetype="tiff"
+            ;;
+        image/bmp )
+            filetype="bmp"
+            ;;
+        image/x-ms-bmp )
+            filetype="bmp"
+            ;;
+        image/png )
+            filetype="png"
+            ;;
+        image/x-portable-bitmap | image/x-portable-pixmap | \
+                image/x-portable-greymap)
+            filetype="pnm"
+            ;;
+        image/x-xpm )
+            filetype="xpm"
+            ;;
+        * )
+            filetype=unknown
+            ;;
+        esac
+}
+
+
+
+computeTypeFromTypeDescription () {
+
+# $1 is the full description from 'file' of the file type
+
+    case "$1" in
+    
+        *PBM* | *PGM* | *PPM* )
+            filetype=pnm
+            ;;
+    
+        *JPEG* | *JFIF* )
+            filetype=jfif
+            ;;
+    
+        *PNG* )
+            filetype=png
+            ;;
+    
+        *GIF* )
+            filetype=gif
+            ;;
+    
+        *TIFF* )
+            filetype=tiff
+            ;;
+    
+        *PC*bitmap*data* )
+            filetype=bmp
+            ;;
+        
+        *uuencoded* )
+            filetype=uuencoded
+            ;;
+    
+        *bzip2*compressed*data* )
+            filetype=bzip2
+            ;;
+    
+        *bzip*compressed*data* )
+            filetype=bzip
+            ;;
+        
+        *gzip*compressed*data* )
+            filetype=gzip
+            ;;
+    
+        *compress* )
+            filetype=compress
+            ;;
+    
+        *btoa* )
+            filetype=btoa
+            ;;
+    
+        *Sun* | *rasterfile* )
+            filetype=rast
+            ;;
+    
+        *IFF*ILBM* )
+            filetype=ilbm
+            ;;
+    
+        *Lisp* )
+            filetype=lispm
+            ;;
+    
+        *PC*Paintbrush* )
+            filetype=pcx
+            ;;
+    
+        *Bennet* )
+            filetype=ybm
+            ;;
+    
+        *pixmap*image*text* )
+            filetype=xpm
+            ;;
+    
+        # This has to come after all other 'text' files, or you may be
+        # disappointed.
+        *text* )
+            filetype=text
+            ;;
+    
+        *MicroDesign* )
+            filetype=mda
+            ;;
+    
+        * )
+            filetype=unknown
+            ;;
+        esac
+}
+
+
+
+computeTypeFromFilenameExtension () {
+# $1 is the filename extension (".gif", etc.)
+
+    case "$1" in
+
+        *.pbm | *.pbm.* | *.pgm | *.pgm.* | *.ppm | *.ppm.* )
+            filetype=pnm
+            ;;
+        *.JPEG | *.jpeg | *.jpg | *.JPG )
+            filetype=jfif
+            ;;
+        *.gif | *.gif.* )
+            filetype=gif
+            ;;
+        *.png | *.PNG )
+            filetype=png
+            ;;
+        *.tif | *.tif.* | *.tiff | *.tiff.* )
+            filetype=tiff
+            ;;
+        *.bmp )
+            filetype=bmp
+            ;;
+        *.x | *.x.* | *.xbm | *.xbm.* | *.x10bm | *.x10bm.* | \
+            *.x11bm | *.x11bm.* | *.bitmap | *.bitmap.* )
+            filetype=xbm
+            ;;
+        *.r | *.r.* | *.rast | *.rast.* )
+            filetype=rast
+            ;;
+        *.mac | *.mac.* | *.macp | *.macp.* )
+            filetype=macp
+            ;;
+        *.g3 | *.g3.* | *.fax | *.fax.* )
+            filetype=g3
+            ;;
+        *.xwd | *.xwd.* | *.x10wd | *.x10wd.* \
+                | *.x11wd | *.x11wd.* )
+            filetype=xwd
+            ;;
+        *.brush | *.brush.* )
+            filetype=brush
+            ;;
+        *.img | *.img.* )
+            filetype=gem
+            ;;
+        *.pcx | *.pcx.* )
+            filetype=pcx
+            ;;
+        *.pic | *.pic.* | *.pict | *.pict.* | *.pict2 | *.pict2.* )
+            filetype=pict
+            ;;
+        *.fs | *.fs.* | *.face | *.face.* )
+            filetype=fs
+            ;;
+        *.hips | *.hips.* )
+            filetype=hips
+            ;;
+        *.fits | *.fits.* )
+            filetype=fits
+            ;;
+        *.iff | *.iff.* | *.ilbm | *.ilbm.* )
+            filetype=ilbm
+            ;;
+        *.lispm | *.lispm.* )
+            filetype=lispm
+            ;;
+        *.mtv | *.mtv.* )
+            filetype=mtv
+            ;;
+        *.qrt | *.qrt.* )
+            filetype=qrt
+            ;;
+        *.tga | *.tga.* | *.targa | *.targa.* )
+            filetype=tga
+            ;;
+        *.xim | *.xim.* )
+            filetype=xim
+            ;;
+        *.xpm | *.xpm.* | *.xpm2 | *.xpm2.* )
+            filetype=xpm
+            ;;
+        *.pi1 | *.pi1.* )
+            filetype=pi1
+            ;;
+        *.pi3 | *.pi3.* )
+            filetype=pi3
+            ;;
+        *.spu | *.spu.* )
+            filetype=spu
+            ;;
+        *.spc | *.spc.* )
+            filetype=spc
+            ;;
+        *.ybm | *.ybm.* | *.face | *.face.* )
+            filetype=ybm
+            ;;
+        *.mda | *.mdp )
+            filetype=mda
+            ;;
+        * )
+            filetype=unknown
+            ;;
+        esac
+}
+
+
+
+determineType () {
+
+# $1 is the name of the file that contains the subject file's contents
+# $2 is the mime type or "unknown"
+# $3 is the type description from 'file'
+
+    if [ "$2" = "unknown" ]; then
+        filetype="unknown"
+    else
+        computeTypeFromMimeType "$2"
+        fi
+
+    if [ "$filetype" = "unknown" ]; then
+        computeTypeFromTypeDescription "$3"
+        fi
+
+    if [ "$filetype" = "unknown" ]; then
+        computeTypeFromFilenameExtension "$4"
+        fi
+}
+
+
+
+convertIt () {
+# Based on the file type computed, do the conversion
+
+# $1 is the input file name
+# $2 is our file type code
+
+case "$2" in
+
+    pnm )
+        cat "$file"
+        ;;
+
+    uuencoded )
+        newfile="$tempdir/atn.decode.$$"
+        rm -f "$newfile"
+        (echo begin 600 $newfile; sed 1d < "$file") | uudecode
+        anytopnm "$newfile"
+        ;;
+
+    bzip2 )
+        bzip2 -dk < "$file" | anytopnm -
+        ;;
+
+    bzip )
+        bzip -dk < "$file" | anytopnm -
+        ;;
+
+    gzip )
+        gzip --decompress --to-stdout < "$file" | anytopnm -
+        ;;
+
+    compress )
+        uncompress -c < "$file" | anytopnm -
+        ;;
+
+    btoa )
+        atob < "$file" | anytopnm -
+        ;;
+
+    rast )
+        rasttopnm "$file"
+        ;;
+
+    gif )
+        giftopnm "$file"
+        ;;
+
+    tiff )
+        tifftopnm "$file"
+        ;;
+
+    ilbm )
+        ilbmtoppm "$file"
+        ;;
+
+    lispm )
+        lispmtopgm "$file"
+        ;;
+
+    pcx )
+        pcxtoppm "$file"
+        ;;
+
+    ybm )
+        ybmtopbm "$file"
+        ;;
+
+    xpm )
+        xpmtoppm < "$file"
+        ;;
+
+    # This has to come after all other 'text' files, or you may be
+    # disappointed.
+    text )
+        pbmtext -builtin fixed < "$file"
+        ;;
+
+    jfif )
+        jpegtopnm "$file"
+        ;;
+
+    png )
+        pngtopnm "$file"
+        ;;
+
+    mda )
+        mdatopbm -d -- "$file"
+        ;;
+
+    bmp )
+        bmptoppm "$file"
+        ;;
+    
+    xbm )
+        xbmtopbm "$file"
+        ;;
+    macp )
+        macptopbm "$file"
+        ;;
+    g3 )
+        g3topbm "$file"
+        ;;
+    xwd )
+        xwdtopnm "$file"
+        ;;
+    brush )
+        brushtopbm "$file"
+        ;;
+    img )
+        gemtopbm "$file"
+        ;;
+    pcx ) 
+        pcxtoppm "$file"
+        ;;
+    pict )
+        picttoppm "$file"
+        ;;
+    fs )
+        fstopgm "$file"
+        ;;
+    hips )
+        hipstopgm "$file"
+        ;;
+    fits )
+        fitstopnm "$file"
+        ;;
+    mtv )
+        mtvtoppm "$file"
+        ;;
+    qrt )
+        qrttoppm "$file"
+        ;;
+    tga )
+        tgatoppm "$file"
+        ;;
+    xim )
+        ximtoppm "$file"
+        ;;
+    pi1 )
+        pi1toppm "$file"
+        ;;
+    pi3 )
+        pi3topbm "$file"
+        ;;
+    spu )
+        sputoppm "$file"
+        ;;
+    spc )
+        spctoppm "$file"
+        ;;
+    * )
+        echo "$progname: INTERNAL ERROR.  Illegal value of filetype variable"
+        exit 1
+        ;;
+
+    esac
+}
+
+
+
+###############################################################################
+#                                MAINLINE
+###############################################################################
+
+progname=$0
+
+if [ $# -gt 1 ] ; then
+    echo "Too many arguments: $#.  The only valid argument is the" \
+         "input file name." 1>&2
+    exit 1
+elif [ $# -eq 1 ] ; then
+    inputFile="$1"
+else
+    inputFile="-"
+fi
+
+tempdir="${TMPDIR-/tmp}/anytopnm.$$"
+mkdir $tempdir || { echo "Could not create temporary file. Exiting."; exit 1;}
+chmod 700 $tempdir
+
+trap 'rm -rf $tempdir' 0
+
+# Take out all spaces
+# Find the filename extension for last-ditch efforts later
+
+# We used to do this, but it doesn't work with all Awks.  The sed below
+# is universal.  2005.11.02.
+#fileExtension=`echo "$inputFile" | \
+#               $AWK '{gsub(" ","");gsub(".*\\\\.",".");print}'`
+
+fileExtension=`echo "$inputFile" | sed 's/ //;s/.*\././g'`
+
+file="$tempdir/atn.stdin.$$"
+
+putInputIntoTempfile "$inputFile" "$file"
+
+setMimeType "$file"
+
+typeDescription=`file "$file" | cut -d: -f2- | cut -c2`
+
+determineType "$file" "$mimeType" "$typeDescription" "$fileExtension"
+
+if [ "$filetype" = "unknown" ]; then
+    echo "$progname: unknown file type.  " \
+        "'file' says mime type is '$mimeType', " 1>&2
+    echo "type description is '$typeDescription'" 1>&2
+    exit 1
+    fi
+
+convertIt $file $filetype
+
+exit 0
diff --git a/converter/other/bmepsoe.c b/converter/other/bmepsoe.c
new file mode 100644
index 00000000..cdb52779
--- /dev/null
+++ b/converter/other/bmepsoe.c
@@ -0,0 +1,539 @@
+/* 
+ * 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 *o, int final)
+{
+  Bytef *iptr, *optr, *xptr;
+  uLong  is, os, xs;
+  int err, must_continue;
+  
+  iptr = o->fl_i_buffer; optr = o->fl_o_buffer;
+  is = o->fl_i_size; os = o->fl_o_size;
+  
+  if(iptr && optr && is && os) {
+    is = o->fl_i_used;
+    if(is) {
+      (o->flate_stream).next_in = iptr;
+      (o->flate_stream).avail_in = is;
+      if(final) { 
+    must_continue = 1;
+    while(must_continue) {
+      (o->flate_stream).next_out = optr;
+      (o->flate_stream).avail_out = os;
+      must_continue = 0;
+      err = deflate(&(o->flate_stream), Z_FINISH);
+      switch(err) {
+        case Z_STREAM_END: { 
+              xptr = optr;
+          
+          xs = os - ((o->flate_stream).avail_out);
+          while(xs--) {
+        after_flate_add(o, (*(xptr++)));
+          }
+        } break;
+        case Z_OK : {
+          must_continue = 1;
+              xptr = optr;
+          
+          xs = os - ((o->flate_stream).avail_out);
+          while(xs--) {
+        after_flate_add(o, (*(xptr++)));
+          }
+        } break;
+        default : { 
+        } break;
+      }
+    }
+      } else { 
+    must_continue = 1;
+    while(must_continue) {
+      must_continue = 0;
+      (o->flate_stream).avail_out = os; (o->flate_stream).next_out = optr;
+      err = deflate(&(o->flate_stream), 0);
+      switch(err) {
+        case Z_OK: {
+          if((o->flate_stream).avail_in) {
+        must_continue = 1;
+          }
+          
+          xptr = optr; xs = os - ((o->flate_stream).avail_out);
+          while(xs--) {
+        after_flate_add(o, (*(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 *o, int b)
+{
+  
+  if((o->mode) & OE_RL) {
+    rl_add(o,b);
+  } else {
+    after_rl_add(o,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 *o, int b)
+{
+  
+  o->bit_value = 2 * o->bit_value + (b ? 1 : 0);
+  o->bit_consumed = o->bit_consumed + 1;
+  if(o->bit_consumed >= 8) {
+    o->bit_consumed = 0;
+    internal_byte_add(o, (o->bit_value));
+    o->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 *o, int b)
+{
+  
+  if(o->bit_consumed) {
+    int testval,i;
+    testval = 128;
+    for(i = 0; i < 8; i++) {
+      if(b & testval) {
+    oe_bit_add(o,1);
+      } else {
+    oe_bit_add(o,0);
+      }
+      testval = testval / 2;
+    }
+  } else {
+    internal_byte_add(o,b);
+  }
+  
+}
+
+void oe_byte_flush(Output_Encoder *o)
+{
+  
+  oe_bit_flush(o);
+  
+}
diff --git a/converter/other/bmepsoe.h b/converter/other/bmepsoe.h
new file mode 100644
index 00000000..99c59f77
--- /dev/null
+++ b/converter/other/bmepsoe.h
@@ -0,0 +1,79 @@
+/* 
+ * 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 <stdio.h>
+
+#include <zlib.h>
+
+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
new file mode 100644
index 00000000..3ba1d77c
--- /dev/null
+++ b/converter/other/bmptopnm.c
@@ -0,0 +1,1477 @@
+/*****************************************************************************
+                                    bmptopnm.c
+******************************************************************************
+ 
+ Bmptopnm - Converts from a Microsoft Windows or OS/2 .BMP file to a
+ PBM, PGM, or PPM file.
+
+ This program was formerly called Bmptoppm (and generated only PPM output).
+ The name was changed in March 2002.
+
+ Copyright (C) 1992 by David W. Sanderson.
+ 
+ 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 <string.h>
+#include <limits.h>
+#include <assert.h>
+
+#include "pnm.h"
+#include "shhopt.h"
+#include "nstring.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
+    */
+
+enum rowOrder {BOTTOMUP, TOPDOWN};
+
+struct bitPosition {
+    /* mask and shift count to describe a set of bits in a binary value.
+
+       Example: if 16 bits are laid out as XRRRRRGGGGGBBBBB then the shift
+       count for the R component is 10 and the mask is 0000000000011111.
+    */
+    unsigned int shift;
+        /* How many bits right you have to shift the value to get the subject
+           bits in the least significant bit positions.
+        */
+    unsigned int mask;
+        /* Has one bits in positions where the subject bits are after
+           shifting.
+        */
+};
+
+struct pixelformat {
+    /* The format of a pixel representation from the raster.  i.e. which 
+       bits apply to red, green, blue, and transparency 
+    */
+    struct bitPosition red;
+    struct bitPosition blu;
+    struct bitPosition grn;
+    struct bitPosition trn;
+    
+    bool conventionalBgr;
+        /* This means that the above bit positions are just the conventional
+           BGR format -- one byte Blue, one byte Green, one byte Red,
+           no alpha.  Though it's totally redundant with the members above,
+           this member speeds up computation:  We've never actually seen
+           a BMP file that doesn't use conventional BGR, and it doesn't
+           require any masking or shifting at all to interpret.
+        */
+};
+
+struct bmpInfoHeader {
+    enum rowOrder rowOrder;
+    int cols;
+    int rows;
+    unsigned int cBitCount;
+        /* Number of bits in the BMP file that each pixel occupies. */
+    enum bmpClass class;
+    bool bitFields;
+        /* The raster values are arranged in arbitrary bit fields as
+           described by the "mask" values in the header, rather than
+           fixed formats.
+        */
+    int cmapsize;
+        /* Size in bytes of the colormap (palette) in the BMP file */
+    unsigned int imageSize;
+        /* Size in bytes of the image data.  We only reference this 
+           when the image is compressed. */    
+    unsigned short cPlanes;
+    unsigned long int compression;
+    struct pixelformat pixelformat;
+};
+
+
+
+struct cmdline_info {
+    /* 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 */
+};
+
+static const char *ifname;
+
+
+
+static void
+parse_command_line(int argc, char ** argv,
+                   struct cmdline_info *cmdline_p) {
+/*----------------------------------------------------------------------------
+   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.
+         */
+    optStruct2 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;
+
+    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. */
+
+    if (argc-1 == 0) 
+        cmdline_p->input_filespec = "-";
+    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];
+
+}
+
+
+
+static const char er_read[] = "%s: read error";
+
+static int
+GetByte(FILE * const fp) {
+
+    int             v;
+
+    if ((v = getc(fp)) == EOF)
+        pm_error(er_read, ifname);
+
+    return v;
+}
+
+
+
+static short
+GetShort(FILE * const fp) {
+
+    short           v;
+
+    if (pm_readlittleshort(fp, &v) == -1)
+        pm_error(er_read, ifname);
+
+    return v;
+}
+
+static short
+GetBigShort(FILE * const fp) {
+
+    short           v;
+
+    if (pm_readbigshort(fp, &v) == -1)
+        pm_error(er_read, ifname);
+
+    return v;
+}
+
+
+
+static long
+GetLong(FILE * const fp) {
+
+    long v;
+
+    if (pm_readlittlelong(fp, &v) == -1)
+        pm_error(er_read, ifname);
+
+    return v;
+}
+
+
+
+typedef struct {
+    long dummy[12];
+} cieXyzTriple;
+
+static cieXyzTriple
+GetCieXyzTriple(FILE * const fp) {
+
+    cieXyzTriple v;
+    unsigned int i;
+
+    for (i = 0; i < 12; ++i) 
+        if (pm_readlittlelong(fp, &v.dummy[i]) == -1)
+            pm_error(er_read, ifname);
+
+    return v;
+}
+
+
+
+static void
+readOffBytes(FILE * const fp, unsigned int const nbytes) {
+/*----------------------------------------------------------------------------
+   Read 'nbytes' from file 'fp'.  Abort program if read error.
+-----------------------------------------------------------------------------*/
+    int i;
+    
+    for(i = 0; i < nbytes; ++i) {
+        int rc;
+        rc = getc(fp);
+        if (rc == EOF)
+            pm_error(er_read, ifname);
+    }
+}
+
+
+
+static void
+BMPreadfileheader(FILE *         const ifP, 
+                  unsigned int * const bytesReadP, 
+                  unsigned int * const offBitsP) {
+
+    unsigned short  xHotSpot;
+    unsigned short  yHotSpot;
+    unsigned long   offBits;
+    unsigned long int fileSize;
+
+
+    if (GetByte(ifP) != 'B')
+        pm_error("'%s' is not a BMP file.  (It doesn't start with 'BM')",
+                 ifname);
+    if (GetByte(ifP) != 'M')
+        pm_error("'%s' is not a BMP file.  (It doesn't start with 'BM')",
+                 ifname);
+
+
+    fileSize = GetLong(ifP);  /* This is not always reliable. */
+    xHotSpot  = GetShort(ifP);
+    yHotSpot  = GetShort(ifP);
+    offBits   = GetLong(ifP);
+
+    *offBitsP = offBits;
+
+    *bytesReadP = 14;
+}
+
+
+
+static void
+readOs2InfoHeader(FILE *                 const ifP,
+                  struct bmpInfoHeader * const headerP) {
+
+    headerP->class = C_OS2;
+
+    headerP->cols = GetShort(ifP);
+    headerP->rows = GetShort(ifP);
+    headerP->rowOrder = BOTTOMUP;
+    headerP->cPlanes = GetShort(ifP);
+    headerP->cBitCount = GetShort(ifP);
+    /* 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
+       the same for Windows BMP, so we interpret cBitCount > 8 the
+       same as for Windows.
+    */
+    if (headerP->cBitCount <= 8)
+        headerP->cmapsize = 1 << headerP->cBitCount;
+    else if (headerP->cBitCount == 24)
+        headerP->cmapsize = 0;
+    /* There is a 16 bit truecolor format, but we don't know how the
+       bits are divided among red, green, and blue, so we can't handle it.
+    */
+    else
+        pm_error("Unrecognized bits per pixel in OS/2 BMP file header: %d",
+                 headerP->cBitCount);
+                 
+    headerP->compression = COMP_RGB;
+    
+    pm_message("OS/2 BMP, %dx%dx%d",
+               headerP->cols, headerP->rows, headerP->cBitCount);
+}
+
+
+
+static void
+readWindowsBasic40ByteInfoHeader(FILE *                 const ifP,
+                                 struct bmpInfoHeader * const headerP) {
+/*----------------------------------------------------------------------------
+   Read from the file stream 'ifP' the basic BMP Info header.  This does
+   not include any Info header extension.  The Info header is the data
+   that comes after the BMP file header.
+
+   Return the information from the info header as *headerP.
+-----------------------------------------------------------------------------*/
+    int colorsimportant;   /* ColorsImportant value from header */
+    int colorsused;        /* ColorsUsed value from header */
+
+    headerP->class = C_WIN;
+
+    headerP->cols = GetLong(ifP);
+    {
+        long const cy = GetLong(ifP);
+        if (cy < 0) {
+            headerP->rowOrder = TOPDOWN;
+            headerP->rows = - cy;
+        } else {
+            headerP->rowOrder = BOTTOMUP;
+            headerP->rows = cy;
+        }
+    }
+    headerP->cPlanes = GetShort(ifP);
+    headerP->cBitCount = GetShort(ifP);
+ 
+    {
+        unsigned long int const compression = GetLong(ifP);
+
+        headerP->bitFields = (compression == COMP_BITFIELDS);
+    
+        if (compression != COMP_RGB && compression != COMP_BITFIELDS &&
+            compression != COMP_RLE4 && compression != COMP_RLE8 ) 
+            pm_error("Input is compressed.  Unsupported encoding method.\n"
+                     "Compression type code = %ld", compression);
+                     
+        if ( (compression == COMP_RLE4 || compression == COMP_RLE8) &&
+              headerP->rowOrder == TOPDOWN )                        
+            pm_error("Invalid BMP header.  Top-down images cannot be compressed.");
+
+        if ( (compression == COMP_RLE4 && headerP->cBitCount !=4) ||
+             (compression == COMP_RLE8 && headerP->cBitCount !=8) )                        
+            pm_error("Invalid BMP header.\n" 
+                     "Compression type (%s) disagrees with number of bits per pixel (%u).",
+                      compression == COMP_RLE4 ? "RLE4" : "RLE8",
+                      headerP->cBitCount);
+
+        headerP->compression = compression;             
+    }
+    /* And read the rest of the junk in the 40 byte header */
+    headerP->imageSize = GetLong(ifP);   /* ImageSize */
+    GetLong(ifP);   /* XpixelsPerMeter */
+    GetLong(ifP);   /* YpixelsPerMeter */
+    colorsused = GetLong(ifP);   /* ColorsUsed */
+    /* See comments in bmp.h for info about the definition of the following
+       word and its relationship to the color map size (*pcmapsize).
+    */
+    colorsimportant = GetLong(ifP);  /* ColorsImportant */
+
+    if (headerP->cBitCount <= 8) {
+        if (colorsused != 0) {
+            if (colorsused > 1 << headerP->cBitCount)
+                pm_error("Invalid BMP header.  Says %u bits per pixel, "
+                         "but %d colors used", 
+                         headerP->cBitCount, colorsused);
+            else
+                headerP->cmapsize = colorsused;
+        } else 
+            headerP->cmapsize = 1 << headerP->cBitCount;
+    } else if (headerP->cBitCount == 24 || 
+               headerP->cBitCount == 16 || 
+               headerP->cBitCount == 32)
+        headerP->cmapsize = 0;
+    else
+        pm_error("Unrecognized bits per pixel in Windows BMP file header: %d",
+                 headerP->cBitCount);
+}
+
+
+
+static unsigned int
+lsbZeroCount(unsigned int const mask)
+/*----------------------------------------------------------------------------
+   Return the number of consecutive zeroes in the mask 'mask', starting with
+   the least significant bit and going up.  E.g. for 0x20, it would be 5.
+   
+   Use GCC built-in when available.
+-----------------------------------------------------------------------------*/
+
+#if ( defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 304) )
+{
+      return ( mask==0 ? sizeof(mask)*8 : __builtin_ctz(mask) );
+}
+#else
+{
+      unsigned int i=0;
+    
+      while (((mask >> i) & 0x1) == 0 && i < sizeof(mask)*8)
+        ++i;
+
+      return i;
+
+}
+#endif
+
+
+static struct bitPosition
+bitPositionFromMask(long const bmpMask) {
+    struct bitPosition retval;
+
+    retval.shift = lsbZeroCount(bmpMask);
+    retval.mask  = bmpMask >> retval.shift;
+
+    return retval;
+}
+
+
+
+static void
+computeConventionalBgr(struct pixelformat * const fP,
+                       unsigned int         const bitCount) {
+
+    switch (bitCount) {
+    case 24:
+        fP->conventionalBgr =
+            fP->red.shift ==  0 && fP->red.mask == 0xFF &&
+            fP->grn.shift ==  8 && fP->grn.mask == 0xFF &&
+            fP->blu.shift == 16 && fP->blu.mask == 0xFF &&
+            fP->trn.mask == 0
+            ;
+        break;
+    case 32:
+        fP->conventionalBgr =
+            fP->red.shift ==  8  && fP->red.mask == 0xFF &&
+            fP->grn.shift == 16  && fP->grn.mask == 0xFF &&
+            fP->blu.shift == 24  && fP->blu.mask == 0xFF &&
+            fP->trn.mask == 0
+            ;
+        break;
+    default:
+        fP->conventionalBgr = FALSE;
+    }
+}
+
+
+
+static struct pixelformat
+defaultPixelformat(unsigned int const bitCount) {
+
+    struct pixelformat retval;
+
+    switch (bitCount) {
+    case 16:
+        retval.conventionalBgr = FALSE;
+        retval.red.shift = 10;
+        retval.grn.shift = 5;
+        retval.blu.shift = 0;
+        retval.trn.shift = 0;
+        retval.red.mask = 0x1f;  /* 5 bits */
+        retval.grn.mask = 0x1f;  /* 5 bits */
+        retval.blu.mask = 0x1f;  /* 5 bits */
+        retval.trn.mask = 0;
+        break;
+    case 24:
+    case 32:
+        retval.conventionalBgr = TRUE;
+        retval.red.shift = 16;
+        retval.grn.shift = 8;
+        retval.blu.shift = 0;
+        retval.trn.shift = 0;
+        retval.red.mask = 0xff;  /* 8 bits */
+        retval.grn.mask = 0xff;  /* 8 bits */
+        retval.blu.mask = 0xff;  /* 8 bits */
+        retval.trn.mask = 0;
+        break;
+    default:
+        /* colormapped - masks are undefined */
+        break;
+    }
+
+    return retval;
+}
+
+
+
+static void
+readV4InfoHeaderExtension(FILE *                 const ifP, 
+                          struct bmpInfoHeader * const headerP) {
+
+    if (headerP->bitFields) {
+        headerP->pixelformat.red = bitPositionFromMask(GetLong(ifP));
+        headerP->pixelformat.grn = bitPositionFromMask(GetLong(ifP));
+        headerP->pixelformat.blu = bitPositionFromMask(GetLong(ifP));
+        headerP->pixelformat.trn = bitPositionFromMask(GetLong(ifP));
+
+        computeConventionalBgr(&headerP->pixelformat, headerP->cBitCount);
+    } else
+        headerP->pixelformat = defaultPixelformat(headerP->cBitCount);
+
+    GetLong(ifP);  /* Color space */
+    GetCieXyzTriple(ifP);  /* Endpoints */
+    GetLong(ifP);  /* GammaRed */
+    GetLong(ifP);  /* GammaGreen */
+    GetLong(ifP);  /* GammaBlue */
+} 
+
+
+
+static void
+defaultV4InfoHeaderExtension(struct bmpInfoHeader * const headerP) {
+
+    headerP->pixelformat = defaultPixelformat(headerP->cBitCount);
+
+}
+
+
+
+static void
+readWindowsInfoHeader(FILE *                 const ifP, 
+                      unsigned int           const cInfoHeaderSize,
+                      struct bmpInfoHeader * const headerP) {
+
+    /* There are 3 major formats of Windows
+       BMP, identified by the 3 info header lengths.  The original
+       one is 40 bytes.  The "V4 header" is 108 bytes and was
+       new with Windows 95 and NT 4.0.  The "V5 header" is 124 bytes
+       and was new with Windows 98 and Windows 2000.
+    */
+    readWindowsBasic40ByteInfoHeader(ifP, headerP);
+
+    if (cInfoHeaderSize >= 108) 
+        readV4InfoHeaderExtension(ifP, headerP);
+    else 
+        defaultV4InfoHeaderExtension(headerP);
+
+    if (cInfoHeaderSize >= 124) {
+        /* Read off the V5 info header extension. */
+        GetLong(ifP);  /* Intent */
+        GetLong(ifP);  /* ProfileData */
+        GetLong(ifP);  /* ProfileSize */
+        GetLong(ifP);  /* Reserved */
+    }
+
+    pm_message("Windows BMP, %dx%dx%d",
+               headerP->cols, headerP->rows, headerP->cBitCount);
+}
+
+
+
+static void
+BMPreadinfoheader(FILE *                 const ifP, 
+                  unsigned int *         const bytesReadP,
+                  struct bmpInfoHeader * const headerP) {
+
+    unsigned int const cInfoHeaderSize = GetLong(ifP);
+
+    switch (cInfoHeaderSize) {
+    case 12:
+        readOs2InfoHeader(ifP, headerP);
+        break;
+    case 40: 
+    case 108:
+    case 124:
+        readWindowsInfoHeader(ifP, cInfoHeaderSize, headerP);
+        break;
+    default:
+        pm_error("%s: unknown Info Header size: %u bytes", 
+                 ifname, cInfoHeaderSize);
+        break;
+    }
+    *bytesReadP = cInfoHeaderSize;
+}
+
+
+
+static void
+BMPreadcolormap(FILE *         const ifP, 
+                int            const class, 
+                xel **         const colormapP, 
+                int            const cmapsize,
+                unsigned int * const bytesReadP) {
+/*----------------------------------------------------------------------------
+   Read the color map from the present position in the input BMP file
+   *ifP.
+
+   The map has 'cmapsize' entries in it.  cmapsize == 0 means there is
+   no color map.
+
+   We return a color map as *colormapP.  If there is no color map in the
+   BMP, this is just an arbitrary color map.
+ 
+   'class' is the class of BMP image - Windows or OS/2.
+-----------------------------------------------------------------------------*/
+
+    int i;
+
+    xel * colormap;
+    unsigned int bytesRead;
+
+    colormap = pnm_allocrow(MAX(1,cmapsize));
+    
+    bytesRead = 0;  /* initial value */
+
+    for (i = 0; i < cmapsize; ++i) {
+        /* There is a document that says the bytes are ordered R,G,B,Z,
+           but in practice it appears to be the following instead:
+        */
+        unsigned int r, g, b;
+        
+        b = GetByte(ifP);
+        g = GetByte(ifP);
+        r = GetByte(ifP);
+
+        PNM_ASSIGN(colormap[i], r, g, b);
+
+        bytesRead += 3;
+
+        if (class == C_WIN) {
+            GetByte(ifP);
+            bytesRead += 1;
+        }
+    }
+    *colormapP = colormap;
+    *bytesReadP = bytesRead;
+}
+
+
+
+static void
+extractBitFields(unsigned int       const rasterval,
+                 struct pixelformat const pixelformat,
+                 pixval             const maxval,
+                 pixval *           const rP,
+                 pixval *           const gP,
+                 pixval *           const bP,
+                 pixval *           const aP) {
+
+    unsigned int const rbits = 
+        (rasterval >> pixelformat.red.shift) & pixelformat.red.mask;
+    unsigned int const gbits = 
+        (rasterval >> pixelformat.grn.shift) & pixelformat.grn.mask;
+    unsigned int const bbits = 
+        (rasterval >> pixelformat.blu.shift) & pixelformat.blu.mask;
+    unsigned int const abits = 
+        (rasterval >> pixelformat.trn.shift) & pixelformat.trn.mask;
+    
+    *rP = (unsigned int) rbits * maxval / pixelformat.red.mask;
+    *gP = (unsigned int) gbits * maxval / pixelformat.blu.mask;
+    *bP = (unsigned int) bbits * maxval / pixelformat.grn.mask;
+    *aP = (unsigned int) abits * maxval / pixelformat.trn.mask;
+}        
+
+
+
+static void
+convertRow16(unsigned char      const bmprow[],
+             xel                      xelrow[],
+             int                const cols,
+             struct pixelformat const pixelformat) {
+    /* It's truecolor.  */
+
+    unsigned int col;
+    unsigned int cursor;
+    cursor = 0;
+    for (col=0; col < cols; ++col) {
+        unsigned short const rasterval = (unsigned short)
+            bmprow[cursor+1] << 8 | bmprow[cursor+0];
+
+        pixval r, g, b, a;
+
+        extractBitFields(rasterval, pixelformat, 255, &r, &g, &b, &a);
+
+        PNM_ASSIGN(xelrow[col], r, g, b);
+        
+        cursor += 2;
+    }
+}
+
+
+
+static void
+convertRow24(unsigned char      const bmprow[],
+             xel                      xelrow[],
+             int                const cols,
+             struct pixelformat const pixelformat) {
+    
+    /* It's truecolor */
+    /* There is a document that gives a much different format for
+       24 bit BMPs.  But this seems to be the de facto standard, and is,
+       with a little ambiguity and contradiction resolved, defined in the
+       Microsoft BMP spec.
+    */
+
+    unsigned int col;
+    unsigned int cursor;
+    
+    cursor = 0;
+    for (col = 0; col < cols; ++col) {
+        pixval r, g, b, a;
+
+        if (pixelformat.conventionalBgr) {
+            r = bmprow[cursor+2];
+            g = bmprow[cursor+1];
+            b = bmprow[cursor+0];
+            a = 0;
+        } else {
+            unsigned int const rasterval = 
+                (bmprow[cursor+0] << 16) +
+                (bmprow[cursor+1] << 8) +
+                (bmprow[cursor+2] << 0);
+            
+            extractBitFields(rasterval, pixelformat, 255, &r, &g, &b, &a);
+        }
+        PNM_ASSIGN(xelrow[col], r, g, b);
+        cursor += 3;
+    }
+} 
+
+
+
+static void
+convertRow32(unsigned char      const bmprow[],
+             xel                      xelrow[],
+             int                const cols,
+             struct pixelformat const pixelformat) {
+    
+    /* It's truecolor */
+
+    unsigned int col;
+    unsigned int cursor;
+    cursor = 0;
+    for (col = 0; col < cols; ++col) {
+        pixval r, g, b, a;
+
+        if (pixelformat.conventionalBgr) {
+            /* bmprow[cursor+3] is just padding */
+            r = bmprow[cursor+2];
+            g = bmprow[cursor+1];
+            b = bmprow[cursor+0];
+            a = 0;
+        } else {
+            unsigned int const rasterval = 
+                (bmprow[cursor+0] << 24) +
+                (bmprow[cursor+1] << 16) +
+                (bmprow[cursor+2] << 8) +
+                (bmprow[cursor+3] << 0);
+            
+            extractBitFields(rasterval, pixelformat, 255, &r, &g, &b, &a);
+        }
+
+        PNM_ASSIGN(xelrow[col], 
+                   bmprow[cursor+2], bmprow[cursor+1], bmprow[cursor+0]);
+        cursor += 4;
+    }
+} 
+
+
+
+static void
+convertRow(unsigned char      const bmprow[], 
+           xel                      xelrow[],
+           int                const cols, 
+           unsigned int       const cBitCount, 
+           struct pixelformat const pixelformat,
+           xel                const colormap[]
+           ) {
+/*----------------------------------------------------------------------------
+   Convert a row in raw BMP raster format bmprow[] to a row of xels xelrow[].
+
+   Use maxval 255 for the output xels.
+
+   The BMP image has 'cBitCount' bits per pixel.
+
+   If the image is colormapped, colormap[] is the colormap
+   (colormap[i] is the color with color index i).
+-----------------------------------------------------------------------------*/
+    if (cBitCount == 24) 
+        convertRow24(bmprow, xelrow, cols, pixelformat);
+    else if (cBitCount == 16) 
+        convertRow16(bmprow, xelrow, cols, pixelformat);
+    else if (cBitCount == 32) 
+        convertRow32(bmprow, xelrow, cols, pixelformat);
+    else if (cBitCount == 8) {            
+        /* It's a whole byte colormap index */
+        unsigned int col;
+        for (col = 0; col < cols; ++col)
+            xelrow[col] = colormap[bmprow[col]];
+    } else if (cBitCount < 8) {
+        /* It's a bit field color index */
+        unsigned char const mask = ( 1 << cBitCount ) - 1;
+
+        unsigned int col;
+
+        for (col = 0; col < cols; ++col) {
+            unsigned int const cursor = (col*cBitCount)/8;
+            unsigned int const shift = 8 - ((col*cBitCount) % 8) - cBitCount;
+            unsigned int const index = 
+                (bmprow[cursor] & (mask << shift)) >> shift;
+            xelrow[col] = colormap[index];
+        }
+    } else
+        pm_error("Internal error: invalid cBitCount in convertRow()");
+}
+
+
+
+static unsigned char **
+allocBMPraster(unsigned int const rows, unsigned int const bytesPerRow) {
+
+    unsigned int const storageSize = 
+        rows * sizeof(unsigned char *) + rows * bytesPerRow;        
+    unsigned char ** BMPraster;
+    unsigned int row;
+    unsigned char * startOfRows;
+
+    /* The raster array consists of an array of pointers to the rows
+       followed by the rows of bytes, in a single allocated chunk of storage.
+    */
+
+    if (UINT_MAX / (bytesPerRow + sizeof(unsigned char *)) < rows)
+        pm_error("raster is ridiculously large.");
+
+    BMPraster = (unsigned char **) malloc(storageSize);
+
+    if (BMPraster == NULL)
+        pm_error("Unable to allocate %u bytes for the BMP raster\n",
+                 storageSize);
+
+    startOfRows = (unsigned char *)(BMPraster + rows);
+
+    for (row = 0; row < rows; ++row) 
+        BMPraster[row] = startOfRows + row * bytesPerRow;
+
+    return BMPraster;
+}
+
+
+
+static void
+readrow(FILE *           const ifP,
+        unsigned int     const row,
+        unsigned int     const bytesPerRow,
+        unsigned char ** const BMPraster,
+        unsigned int *   const bytesReadP) {
+
+    size_t bytesRead;
+
+    assert(bytesPerRow > 0);
+    
+    bytesRead = fread(BMPraster[row], 1, bytesPerRow, ifP);
+
+    if (bytesRead < bytesPerRow) {
+        if (feof(ifP))
+            pm_error("End of file reading row %u of BMP raster.", row);
+        else 
+            pm_error("Error reading BMP raster.  Errno=%d (%s)",
+                     errno, strerror(errno));
+    }
+    *bytesReadP += bytesRead;
+}
+ 
+
+
+static void
+nibbleAlign(unsigned char * const ptr,
+            unsigned int    const nibbles){
+/*----------------------------------------------------------------------------
+  Shift data pointed by ptr one half byte toward the MSB (to the left).
+ 
+  Example:
+ 
+  (Numbers in hex, 8 nibbles)
+            5F 13 7E 89 A1
+   becomes  51 37 E8 9A 10
+-----------------------------------------------------------------------------*/
+    unsigned int const fullByteCount = (nibbles-1) / 2;
+    unsigned int i;
+              
+    ptr[0] = ptr[0] & ptr[1] >> 4;
+                                    
+    for (i = 0; i < fullByteCount; ++i)
+        ptr[i+1] = ptr[i+1] << 4 & ptr[i+2] >> 4;
+    
+    if (nibbles % 2 == 1)   /* if there is a final odd nibble */
+        ptr[fullByteCount+1] <<= 4; /* shift it a half byte */
+}
+
+
+           
+enum rleStatus { ABS_MODE, ENC_MODE, END_OF_ROW, END_OF_BMP, DELTA };
+
+static enum rleStatus
+readRLEcode(FILE *          const ifP,
+            unsigned int *  const cntP,
+            unsigned char * const codeP) {
+
+    unsigned short s;
+    enum rleStatus retval;
+    
+    s = GetBigShort(ifP);
+    
+    if      (s == 0) retval = END_OF_ROW;
+    else if (s == 1) retval = END_OF_BMP;
+    else if (s == 2) retval = DELTA;
+    else if (s < 256) {
+        if (cntP)
+            *cntP = s & 0xff;
+        retval = ABS_MODE;
+    } else {
+        if (cntP && codeP) {
+            *cntP  = (s >> 8) & 0xff;
+            *codeP = s & 0xff;
+        }
+        retval = ENC_MODE;
+    }
+    return retval;
+}
+
+
+
+static void
+readrowRLE(FILE *           const ifP,
+           unsigned int     const row,
+           unsigned int     const cols,
+           bool             const lastrow,
+           unsigned long    const compression,
+           unsigned char ** const BMPraster,
+           unsigned int  *  const bytesReadP) {
+
+    bool const RLE4 = (compression == COMP_RLE4);
+    int  const pixelsPerRowMargin = RLE4 ? cols % 2 : 0;
+
+    char const err_decode[] = 
+        "Error while decoding compressed BMP image.  "
+        "%s.  Row: %u  Pixel: %u" ; 
+     
+    unsigned int totalBytesRead;
+    unsigned int pixelsRead;
+
+    /* There are RLE4 images with rows coded up the byte boundary, resulting
+       in each row one pixel larger than the column length stated in the
+       BMP info header (header.cols) when the column length is odd.
+       pixelsPerRowMargin is a "wart" to provide for this case.
+    */
+
+    totalBytesRead = 0;  /* Initial value */
+    pixelsRead = 0;      /* Initial value */
+
+    while (TRUE) {
+        unsigned int n;
+            /* decompressed bytes already read; current write point */ 
+        unsigned int cnt;
+        unsigned char code;
+
+        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 i; 
+
+            if (pixelsRead + cnt > cols + pixelsPerRowMargin)
+                pm_error(err_decode,  "Too many pixels in encoded mode",
+                         row, pixelsRead ); 
+                 
+            for (i = 0; i < byteCnt; ++i)
+                BMPraster[row][n+i] = code;
+                 
+            if (RLE4 && pixelsRead % 2 == 1)
+                /* previous read ended odd */
+                nibbleAlign(&BMPraster[row][n-1], cnt); 
+            
+            pixelsRead += cnt;
+            totalBytesRead += 2;
+        } break;
+        
+        case ABS_MODE: {
+            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;
+
+            if (pixelsRead + cnt > cols + pixelsPerRowMargin)
+                pm_error(err_decode,  "Too many pixels in absolute mode",
+                         row, pixelsRead); 
+
+            cmpBytesRead = fread(&BMPraster[row][n], 
+                                 sizeof(char), bytesToRead, ifP);
+
+            if (cmpBytesRead < bytesToRead) {
+                if (feof(ifP))
+                    pm_error("End of file reading row %u "
+                             "of compressed BMP raster.", row);
+                else 
+                    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); 
+    
+            pixelsRead += cnt;
+            totalBytesRead += cmpBytesRead + 2;
+        } break;
+            
+        case END_OF_ROW: {
+            if (cols == pixelsRead ||
+                cols + pixelsPerRowMargin == pixelsRead) {
+                if (!lastrow) {
+                    *bytesReadP += totalBytesRead + 2;
+                    return;
+                } else if (readRLEcode(ifP, NULL, NULL) == END_OF_BMP) { 
+                    *bytesReadP += totalBytesRead +4;
+                    return;
+                } else
+                    /* lastrow and END_OF_BITMAP not detected */
+                    pm_error(err_decode,  "End of bitmap not marked",
+                             row, pixelsRead ); 
+            } else
+                pm_error(err_decode,  "Premature end of row",
+                         row, pixelsRead);
+        } break;  
+
+        case END_OF_BMP: {
+            if (lastrow && (cols == pixelsRead ||
+                            cols + pixelsPerRowMargin == pixelsRead)){
+                *bytesReadP += totalBytesRead + 2;
+                return;
+            } else
+                pm_error(err_decode,  "Premature end of bitmap",
+                         row, pixelsRead );
+        } break;
+
+        case DELTA: {
+            pm_error(err_decode,
+                     "Delta code in compressed BMP image.  "
+                     "This program does not process deltas.",
+                     row, pixelsRead);
+        } break;
+         
+        default:
+            pm_error("Internal error processing RLE code in row %u", row);
+        }
+   }
+}
+
+
+
+static void
+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, 
+              unsigned int *    const bytesReadP) {
+
+    unsigned int const bytesPerRow =
+        (compression == COMP_RLE4) ? cols / 2 + 2 :
+        (compression == COMP_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;
+
+    BMPraster = allocBMPraster(rows, bytesPerRow);
+
+    *bytesReadP = 0;
+
+    /* row order BOTTOMUP is by far the most common case - the bottom 
+       line is first in the file, the top line last.
+       
+       We have never actually seen TOPDOWN, except in a Microsoft spec
+    */
+    
+    switch(compression){
+    case COMP_RGB:
+    case COMP_BITFIELDS: {
+        unsigned int i;
+        for (i = 0; i < rows; ++i)
+            readrow(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, 
+                    bytesPerRow, BMPraster, bytesReadP);
+    } break;
+    case COMP_RLE4: 
+    case COMP_RLE8: {
+        unsigned int i;
+        /* Read all rows except last */
+        for (i = 0; i < rows - 1; ++i){
+            readrowRLE(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, 
+                       cols, FALSE, compression, BMPraster, bytesReadP);
+        }
+        /* Read last row */
+        readrowRLE(ifP, rowOrder == TOPDOWN ? i : rows - i - 1, 
+                   cols, TRUE,  compression, BMPraster, bytesReadP);
+    } break;             
+    default:       
+        pm_error("The BMP specifies a compression scheme we don't "
+                 "recognize.  Code= %lu", compression);
+    }
+
+    *BMPrasterP = BMPraster;
+}
+
+
+
+static void
+reportHeader(struct bmpInfoHeader const header,
+             unsigned int         const offBits) {
+             
+    pm_message("BMP image header says:");
+    pm_message("  Class of BMP: %s", 
+               header.class == C_WIN ? "Windows" : 
+               header.class == C_OS2 ? "OS/2" :
+               "???");
+    pm_message("  Width: %d pixels", header.cols);
+    pm_message("  Height: %d pixels", header.rows);
+    pm_message("  Depth: %d planes", header.cPlanes);
+    pm_message("  Row order: %s", 
+               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("  Colors in color map: %d", header.cmapsize);
+}        
+
+
+
+static void
+analyzeColors(xel          const colormap[],
+              unsigned int const cmapsize,
+              xelval       const maxval,
+              bool *       const grayPresentP,
+              bool *       const colorPresentP) {
+    
+    if (cmapsize == 0) {
+        /* No colormap, and we're not about to search the entire raster,
+           so we just assume it's full color 
+        */
+        *colorPresentP = TRUE;
+        *grayPresentP = TRUE;
+    } else {
+        unsigned int i;
+
+        *colorPresentP = FALSE;  /* initial assumption */
+        *grayPresentP = FALSE;   /* initial assumption */
+        for (i = 0; i < cmapsize; ++i) {
+            if (PPM_ISGRAY(colormap[i])) {
+                if (PPM_GETR(colormap[i]) != 0 &&
+                    PPM_GETR(colormap[i]) != maxval)
+                    *grayPresentP = TRUE;
+            } else
+                *colorPresentP = TRUE;
+        }
+    }
+}
+
+
+
+static void
+warnIfOffBitsWrong(struct bmpInfoHeader const BMPheader,
+                   unsigned int         const offBits) {
+
+    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), "
+                   "but that there are %u bytes of information before "
+                   "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));
+    }
+}
+
+
+
+static void
+readColorMap(FILE *               const ifP,
+             struct bmpInfoHeader const BMPheader,
+             xel **               const colorMapP,
+             unsigned int *       const posP) {
+
+    unsigned int 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, 
+           unsigned int *       const posP) {
+
+    unsigned int 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 void
+readBmp(FILE *               const ifP, 
+        unsigned char ***    const BMPrasterP, 
+        int *                const colsP, 
+        int *                const rowsP,
+        bool *               const grayPresentP, 
+        bool *               const colorPresentP,
+        unsigned int *       const cBitCountP, 
+        struct pixelformat * const pixelformatP,
+        xel **               const colormapP,
+        bool                 const verbose) {
+
+    xel * colormap;  /* malloc'ed */
+    unsigned int pos;
+        /* Current byte position in the BMP file */
+
+    /* The following are all information from the BMP headers */
+    
+    unsigned int offBits;
+        /* Byte offset into file of raster */
+    struct bmpInfoHeader BMPheader;
+
+    pos = 0;  /* Starting at the beginning ... */
+    { 
+        unsigned int bytesRead;
+        BMPreadfileheader(ifP, &bytesRead, &offBits);
+        pos += bytesRead;
+    }
+    {
+        unsigned int bytesRead;
+        BMPreadinfoheader(ifP, &bytesRead, &BMPheader);
+        if (verbose)
+            pm_message("Read %u bytes of header", bytesRead);
+        pos += bytesRead;
+    }
+
+    if (verbose) 
+        reportHeader(BMPheader, offBits);
+
+    warnIfOffBitsWrong(BMPheader, offBits);
+
+    readColorMap(ifP, BMPheader, &colormap, &pos);
+
+    analyzeColors(colormap, BMPheader.cmapsize, bmpMaxval, 
+                  grayPresentP, colorPresentP);
+
+    readOffBytes(ifP, offBits - pos);
+
+    pos = offBits;
+
+    readRaster(ifP, BMPheader, BMPrasterP, &pos);
+
+    warnIfBadFileSize(BMPheader, pos);
+    
+    if (fgetc(ifP) != EOF)
+        pm_message("warning: some image data remains unread.");
+    
+    *colsP        = BMPheader.cols;
+    *rowsP        = BMPheader.rows;
+    *cBitCountP   = BMPheader.cBitCount;
+    *pixelformatP = BMPheader.pixelformat;
+    *colormapP    = colormap;
+}
+
+
+
+static void
+writeRasterGen(unsigned char **   const BMPraster,
+               int                const cols, 
+               int                const rows, 
+               int                const format,
+               unsigned int       const cBitCount, 
+               struct pixelformat const pixelformat,
+               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 
+  dimensions 'cols' by 'rows' and format 'format', with maxval 255.
+
+  The BMP image has 'cBitCount' bits per pixel, arranged in format
+  'pixelformat'.
+
+  If the image is colormapped, colormap[] is the colormap
+  (colormap[i] is the color with color index i).
+  
+  writeRasterPbm() is faster for a PBM image.
+-----------------------------------------------------------------------------*/
+    xel * xelrow;
+    unsigned int row;
+
+    xelrow = pnm_allocrow(cols);
+
+    for (row = 0; row < rows; ++row) {
+        convertRow(BMPraster[row], xelrow, cols, cBitCount, pixelformat,
+                   colormap);
+        pnm_writepnmrow(stdout, xelrow, cols, bmpMaxval, format, FALSE);
+    }
+    pnm_freerow(xelrow);
+}
+
+
+
+static void
+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 
+  dimensions 'cols' by 'rows'.
+
+  The BMP image has 'cBitCount' bits per pixel, arranged in format
+  'pixelformat'.
+
+  The image must be colormapped; colormap[] is the colormap
+  (colormap[i] is the color with color index i).  We cannot handle the
+  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.
+-----------------------------------------------------------------------------*/
+    unsigned int const charBits = (sizeof(unsigned char) * 8);
+        /* Number of bits in a character */
+    unsigned int const colChars = pbm_packed_bytes(cols);
+    
+    int row;
+    enum colorFormat {BlackWhite, WhiteBlack};
+    enum colorFormat colorformat;
+                  
+    if (PPM_GETR(colormap[0]) > 0)
+        colorformat = WhiteBlack;
+    else                  
+        colorformat = BlackWhite;
+        
+    for (row=0; row < rows; ++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_writepbmrow_packed(stdout, bitrow, cols, FALSE);
+    }
+}
+
+
+
+int
+main(int argc, char ** argv) {
+
+    struct cmdline_info cmdline;
+    FILE * ifP;
+    int outputType;
+
+    bool grayPresent, colorPresent;
+        /* These tell whether the image contains shades of gray other than
+           black and white and whether it has colors other than black, white,
+           and gray.
+        */
+    int cols, rows;
+    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
+           though the bottom row comes first in the BMP format.
+        */
+    unsigned int cBitCount;
+        /* Number of bits in BMP raster for each pixel */
+    struct pixelformat pixelformat;
+        /* Format of the raster bits for a single pixel */
+    xel * colormap;
+        /* Malloc'ed colormap (palette) from the BMP.  Contents of map
+           undefined if not a colormapped BMP.
+         */
+
+    pnm_init(&argc, argv);
+
+    parse_command_line(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.input_filespec);
+    if (streq(cmdline.input_filespec, "-"))
+        ifname = "Standard Input";
+    else 
+        ifname = cmdline.input_filespec;
+
+    readBmp(ifP, &BMPraster, &cols, &rows, &grayPresent, &colorPresent, 
+            &cBitCount, &pixelformat, &colormap,
+            cmdline.verbose);
+    pm_close(ifP);
+
+    if (colorPresent) {
+        outputType = PPM_TYPE;
+        pm_message("WRITING PPM IMAGE");
+    } else if (grayPresent) {
+        outputType = PGM_TYPE;
+        pm_message("WRITING PGM IMAGE");
+    } else {
+        outputType = PBM_TYPE;
+        pm_message("WRITING PBM IMAGE");
+    }
+    
+    if (outputType == PBM_TYPE  && cBitCount == 1){
+        pbm_writepbminit(stdout, cols, rows, FALSE);
+        writeRasterPbm(BMPraster, cols, rows, colormap);
+    } else {
+        pnm_writepnminit(stdout, cols, rows, bmpMaxval, outputType, FALSE);
+        writeRasterGen(BMPraster, cols, rows, outputType, cBitCount,
+                       pixelformat, colormap); 
+    }
+    free(colormap);
+    free(BMPraster);
+
+    return 0;
+}
+
+
diff --git a/converter/other/cameratopam/COPYRIGHT b/converter/other/cameratopam/COPYRIGHT
new file mode 100644
index 00000000..efc77975
--- /dev/null
+++ b/converter/other/cameratopam/COPYRIGHT
@@ -0,0 +1,35 @@
+Cameratopam is derived from Dave Coffin's Dcraw program.
+
+Bryan Henderson derived it in April 2005.  Bryan mainly just split it up
+into manageable pieces and replaced the parts that generate Netpbm formats
+and the command line parser.
+
+Dcraw and therefore Cameratopam is Copyright 1997-2005 by Dave Coffin,
+dcoffin a cybercom o net, and Dave licenses it to the public freely,
+except that the Foveon code (in foveon.c in Netpbm) is copyrighted by
+someone else (I don't know who).
+
+Dave licenses his copyright to the public freely, with the words, "Any
+code not declared GPL is free for all uses."  Only the code in
+foveon.c in Netpbm was declared GPL in Dave's work.
+
+The foveon code is licensed to the public by its unknown copyright owner
+under GPL.
+
+The Netpbm maintainer distributes the entire Cameratopam package under
+GPL.
+
+Dave's distribution to Bryan may be a copyright violation, but
+strangely enough, Bryan's distribution to others is not.  I.e.  you DO
+have license from every copyright owner to do GPL-compatible things
+with this code.
+
+The problem with Dave's distribution is that he combined the Foveon
+code and his code into a single work and distributed it with GPL terms
+applying only to the Foveon code.  The combined work may be a
+derivative work of the Foveon code and therefore cannot be distributed
+with the permission of the Foveon copyright owner, who gives that
+permission only on the condition that the distributor license the
+entire derivative work under GPL.  Dave did not do that.  He did not,
+for example, prohibit Bryan from distributing Dave's part of the code
+in object code only format.
diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile
new file mode 100644
index 00000000..c50c9176
--- /dev/null
+++ b/converter/other/cameratopam/Makefile
@@ -0,0 +1,37 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/cameratopam
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+ifneq ($(JPEGLIB),NONE)
+  ifneq ($(JPEGHDR_DIR)x,x)
+    INCLUDES += -I$(JPEGHDR_DIR)
+    CFLAGS += -DHAVE_JPEG
+  endif
+endif
+
+include $(BUILDDIR)/Makefile.config
+
+
+.PHONY: all
+all: cameratopam
+
+OBJECTS = util.o identify.o cameratopam.o camera.o foveon.o decode.o \
+	canon.o ljpeg.o dng.o
+
+MERGE_OBJECTS =
+
+BINARIES = cameratopam
+MERGEBINARIES = 
+SCRIPTS = 
+
+include $(SRCDIR)/Makefile.common
+
+cameratopam: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
+	$(LD) -o $@ $(LDFLAGS) \
+          $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR)) \
+	  $(MATHLIB) $(LDLIBS) \
+	  $(RPATH) $(LADD)
+
diff --git a/converter/other/cameratopam/bayer.h b/converter/other/cameratopam/bayer.h
new file mode 100644
index 00000000..7ac06ec3
--- /dev/null
+++ b/converter/other/cameratopam/bayer.h
@@ -0,0 +1,43 @@
+/*
+   In order to inline this calculation, I make the risky
+   assumption that all filter patterns can be described
+   by a repeating pattern of eight rows and two columns
+
+   Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2
+ */
+#define FC(row,col) \
+    (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)
+
+#define BAYER(row,col) \
+    image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)]
+
+/*
+    PowerShot 600   PowerShot A50   PowerShot Pro70 Pro90 & G1
+    0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4:
+
+      0 1 2 3 4 5     0 1 2 3 4 5     0 1 2 3 4 5     0 1 2 3 4 5
+    0 G M G M G M   0 C Y C Y C Y   0 Y C Y C Y C   0 G M G M G M
+    1 C Y C Y C Y   1 M G M G M G   1 M G M G M G   1 Y C Y C Y C
+    2 M G M G M G   2 Y C Y C Y C   2 C Y C Y C Y
+    3 C Y C Y C Y   3 G M G M G M   3 G M G M G M
+            4 C Y C Y C Y   4 Y C Y C Y C
+    PowerShot A5    5 G M G M G M   5 G M G M G M
+    0x1e4e1e4e: 6 Y C Y C Y C   6 C Y C Y C Y
+            7 M G M G M G   7 M G M G M G
+      0 1 2 3 4 5
+    0 C Y C Y C Y
+    1 G M G M G M
+    2 C Y C Y C Y
+    3 M G M G M G
+
+   All RGB cameras use one of these Bayer grids:
+
+    0x16161616: 0x61616161: 0x49494949: 0x94949494:
+
+      0 1 2 3 4 5     0 1 2 3 4 5     0 1 2 3 4 5     0 1 2 3 4 5
+    0 B G B G B G   0 G R G R G R   0 G B G B G B   0 R G R G R G
+    1 G R G R G R   1 B G B G B G   1 R G R G R G   1 G B G B G B
+    2 B G B G B G   2 G R G R G R   2 G B G B G B   2 R G R G R G
+    3 G R G R G R   3 B G B G B G   3 R G R G R G   3 G B G B G B
+ */
+
diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c
new file mode 100644
index 00000000..98d6d37a
--- /dev/null
+++ b/converter/other/cameratopam/camera.c
@@ -0,0 +1,1781 @@
+#define _BSD_SOURCE
+    /* Make sure strcasecmp is in string.h */
+#define _XOPEN_SOURCE
+    /* Make sure putenv is in stdlib.h */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+
+#ifdef HAVE_JPEG
+#include <jpeglib.h>
+#endif
+
+#include "pm.h"
+#include "mallocvar.h"
+
+#include "global_variables.h"
+#include "util.h"
+#include "decode.h"
+#include "bayer.h"
+#include "ljpeg.h"
+#include "dng.h"
+
+#include "camera.h"
+
+#if HAVE_INT64
+   typedef int64_t INT64;
+   static bool const have64BitArithmetic = true;
+#else
+   /* We define INT64 to something that lets the code compile, but we
+      should not execute any INT64 code, because it will get the wrong
+      result.
+   */
+   typedef int INT64;
+   static bool const have64BitArithmetic = false;
+#endif
+
+#ifndef LONG_BIT
+#define LONG_BIT (8 * sizeof (long))
+#endif
+
+#define FORC3 for (c=0; c < 3; c++)
+#define FORC4 for (c=0; c < colors; c++)
+
+static void 
+merror (const void *ptr, const char *where) 
+{
+    if (ptr == NULL)
+        pm_error ("Out of memory in %s", 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)++;
+    }
+  if (fuji_secondary && use_secondary) (*rp)--;
+}
+
+void
+adobe_dng_load_raw_lj()
+{
+  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 (&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;
+    }
+    free (jh.row);
+  }
+}
+
+
+
+void
+adobe_dng_load_raw_nc()
+{
+    unsigned short *pixel, *rp;
+    int row, col;
+
+    pixel = calloc (raw_width * tiff_samples, sizeof *pixel);
+    merror (pixel, "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);
+    }
+    free (pixel);
+}
+
+
+
+static int nikon_curve_offset;
+
+void
+nikon_compressed_load_raw(void)
+{
+    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
+    };
+    int csize, row, col, i, diff;
+    unsigned short vpred[4], hpred[2], *curve;
+
+    init_decoder();
+    make_decoder (nikon_tree, 0);
+
+    fseek (ifp, nikon_curve_offset, SEEK_SET);
+    read_shorts (ifp, vpred, 4);
+    csize = get2(ifp);
+    curve = calloc (csize, sizeof *curve);
+    merror (curve, "nikon_compressed_load_raw()");
+    read_shorts (ifp, curve, csize);
+
+    fseek (ifp, data_offset, SEEK_SET);
+    getbits(ifp, -1);
+
+    for (row=0; row < height; row++)
+        for (col=0; col < raw_width; col++)
+        {
+            diff = ljpeg_diff (first_decode);
+            if (col < 2) {
+                i = 2*(row & 1) + (col & 1);
+                vpred[i] += diff;
+                hpred[col] = vpred[i];
+            } else
+                hpred[col & 1] += diff;
+            if ((unsigned) (col-left_margin) >= width) continue;
+            diff = hpred[col & 1];
+            if (diff >= csize) diff = csize-1;
+            BAYER(row,col-left_margin) = curve[diff];
+        }
+    maximum = curve[csize-1];
+    free (curve);
+}
+
+void
+nikon_load_raw()
+{
+  int irow, row, col, i;
+
+  getbits(ifp, -1);
+  for (irow=0; irow < height; irow++) {
+    row = irow;
+    if (model[0] == 'E') {
+      row = irow * 2 % height + irow / (height/2);
+      if (row == 1 && atoi(model+1) < 5000) {
+    fseek (ifp, 0, SEEK_END);
+    fseek (ifp, ftell(ifp)/2, SEEK_SET);
+    getbits(ifp, -1);
+      }
+    }
+    for (col=0; col < raw_width; col++) {
+      i = getbits(ifp, 12);
+      if ((unsigned) (col-left_margin) < width)
+    BAYER(row,col-left_margin) = i;
+      if (tiff_data_compression == 34713 && (col % 10) == 9)
+    getbits(ifp, 8);
+    }
+  }
+}
+
+/*
+   Figure out if a NEF file is compressed.  These fancy heuristics
+   are only needed for the D100, thanks to a bug in some cameras
+   that tags all images as "compressed".
+ */
+int
+nikon_is_compressed()
+{
+  unsigned char test[256];
+  int i;
+
+  if (tiff_data_compression != 34713)
+    return 0;
+  if (strcmp(model,"D100"))
+    return 1;
+  fseek (ifp, data_offset, SEEK_SET);
+  fread (test, 1, 256, ifp);
+  for (i=15; i < 256; i+=16)
+    if (test[i]) return 1;
+  return 0;
+}
+
+/*
+   Returns 1 for a Coolpix 990, 0 for a Coolpix 995.
+ */
+int
+nikon_e990()
+{
+  int i, histo[256];
+  const unsigned char often[] = { 0x00, 0x55, 0xaa, 0xff };
+
+  memset (histo, 0, sizeof histo);
+  fseek (ifp, 2064*1540*3/4, SEEK_SET);
+  for (i=0; i < 2000; i++)
+    histo[fgetc(ifp)]++;
+  for (i=0; i < 4; i++)
+    if (histo[often[i]] > 400)
+      return 1;
+  return 0;
+}
+
+/*
+   Returns 1 for a Coolpix 2100, 0 for anything else.
+ */
+int
+nikon_e2100()
+{
+  unsigned char t[12];
+  int i;
+
+  fseek (ifp, 0, SEEK_SET);
+  for (i=0; i < 1024; i++) {
+    fread (t, 1, 12, ifp);
+    if (((t[2] & t[4] & t[7] & t[9]) >> 4
+    & t[1] & t[6] & t[8] & t[11] & 3) != 3)
+      return 0;
+  }
+  return 1;
+}
+
+/*
+   Separates a Pentax Optio 33WR from a Nikon E3700.
+ */
+int
+pentax_optio33()
+{
+  int i, sum[] = { 0, 0 };
+  unsigned char tail[952];
+
+  fseek (ifp, -sizeof tail, SEEK_END);
+  fread (tail, 1, sizeof tail, ifp);
+  for (i=0; i < sizeof tail; i++)
+    sum[(i>>2) & 1] += tail[i];
+  return sum[0] < sum[1]*4;
+}
+
+/*
+   Separates a Minolta DiMAGE Z2 from a Nikon E4300.
+ */
+int
+minolta_z2()
+{
+  int i;
+  char tail[424];
+
+  fseek (ifp, -sizeof tail, SEEK_END);
+  fread (tail, 1, sizeof tail, ifp);
+  for (i=0; i < sizeof tail; i++)
+    if (tail[i]) return 1;
+  return 0;
+}
+
+void
+nikon_e2100_load_raw()
+{
+  unsigned char   data[3432], *dp;
+  unsigned short pixel[2288], *pix;
+  int row, col;
+
+  for (row=0; row <= height; row+=2) {
+    if (row == height) {
+      fseek (ifp, ((width==1616) << 13) - (-ftell(ifp) & -2048), SEEK_SET);
+      row = 1;
+    }
+    fread (data, 1, width*3/2, ifp);
+    for (dp=data, pix=pixel; pix < pixel+width; dp+=12, pix+=8) {
+      pix[0] = (dp[2] >> 4) + (dp[ 3] << 4);
+      pix[1] = (dp[2] << 8) +  dp[ 1];
+      pix[2] = (dp[7] >> 4) + (dp[ 0] << 4);
+      pix[3] = (dp[7] << 8) +  dp[ 6];
+      pix[4] = (dp[4] >> 4) + (dp[ 5] << 4);
+      pix[5] = (dp[4] << 8) +  dp[11];
+      pix[6] = (dp[9] >> 4) + (dp[10] << 4);
+      pix[7] = (dp[9] << 8) +  dp[ 8];
+    }
+    for (col=0; col < width; col++)
+      BAYER(row,col) = (pixel[col] & 0xfff);
+  }
+}
+
+void
+nikon_e950_load_raw()
+{
+  int irow, row, col;
+
+  getbits(ifp, -1);
+  for (irow=0; irow < height; irow++) {
+    row = irow * 2 % height;
+    for (col=0; col < width; col++)
+      BAYER(row,col) = getbits(ifp, 10);
+    for (col=28; col--; )
+      getbits(ifp, 8);
+  }
+  maximum = 0x3dd;
+}
+
+/*
+   The Fuji Super CCD is just a Bayer grid rotated 45 degrees.
+ */
+void
+fuji_s2_load_raw()
+{
+  unsigned short pixel[2944];
+  int row, col, r, c;
+
+  fseek (ifp, (2944*24+32)*2, SEEK_CUR);
+  for (row=0; row < 2144; row++) {
+    read_shorts(ifp, pixel, 2944);
+    for (col=0; col < 2880; col++) {
+      r = row + ((col+1) >> 1);
+      c = 2143 - row + (col >> 1);
+      BAYER(r,c) = pixel[col];
+    }
+  }
+}
+
+void
+fuji_s3_load_raw()
+{
+  unsigned short pixel[4352];
+  int row, col, r, c;
+
+  fseek (ifp, (4352*2+32)*2, SEEK_CUR);
+  for (row=0; row < 1440; row++) {
+    read_shorts(ifp, pixel, 4352);
+    for (col=0; col < 4288; col++) {
+      r = 2143 + row - (col >> 1);
+      c = row + ((col+1) >> 1);
+      BAYER(r,c) = pixel[col];
+    }
+  }
+}
+
+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];
+    }
+  }
+}
+
+void
+fuji_s5000_load_raw()
+{
+  fseek (ifp, (1472*4+24)*2, SEEK_CUR);
+  fuji_common_load_raw (1472, 1423, 2152);
+}
+
+void
+fuji_s7000_load_raw()
+{
+  fuji_common_load_raw (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()
+{
+  unsigned short pixel[2944];
+  int row, col, r, c, val;
+
+  for (row=0; row < 2168; row++) {
+    read_shorts(ifp, pixel, 2944);
+    for (col=0; col < 1440; col++) {
+      r = 1439 - col + (row >> 1);
+      c = col + ((row+1) >> 1);
+      val = pixel[col+16 + use_secondary*1472];
+      BAYER(r,c) = val;
+    }
+  }
+}
+
+void
+rollei_load_raw()
+{
+  unsigned char pixel[10];
+  unsigned iten=0, isix, i, buffer=0, row, col, todo[16];
+
+  isix = raw_width * raw_height * 5 / 8;
+  while (fread (pixel, 1, 10, ifp) == 10) {
+    for (i=0; i < 10; i+=2) {
+      todo[i]   = iten++;
+      todo[i+1] = pixel[i] << 8 | pixel[i+1];
+      buffer    = pixel[i] >> 2 | buffer << 6;
+    }
+    for (   ; i < 16; i+=2) {
+      todo[i]   = isix++;
+      todo[i+1] = buffer >> (14-i)*5;
+    }
+    for (i=0; i < 16; i+=2) {
+      row = todo[i] / raw_width - top_margin;
+      col = todo[i] % raw_width - left_margin;
+      if (row < height && col < width)
+    BAYER(row,col) = (todo[i+1] & 0x3ff);
+    }
+  }
+  maximum = 0x3ff;
+}
+
+void
+phase_one_load_raw()
+{
+  int row, col, a, b;
+  unsigned short *pixel, akey, bkey;
+
+  fseek (ifp, 8, SEEK_CUR);
+  fseek (ifp, get4(ifp) + 296, SEEK_CUR);
+  akey = get2(ifp);
+  bkey = get2(ifp);
+  fseek (ifp, data_offset + 12 + top_margin*raw_width*2, SEEK_SET);
+  pixel = calloc (raw_width, sizeof *pixel);
+  merror (pixel, "phase_one_load_raw()");
+  for (row=0; row < height; row++) {
+    read_shorts(ifp, pixel, raw_width);
+    for (col=0; col < raw_width; col+=2) {
+      a = pixel[col+0] ^ akey;
+      b = pixel[col+1] ^ bkey;
+      pixel[col+0] = (b & 0xaaaa) | (a & 0x5555);
+      pixel[col+1] = (a & 0xaaaa) | (b & 0x5555);
+    }
+    for (col=0; col < width; col++)
+      BAYER(row,col) = pixel[col+left_margin];
+  }
+  free (pixel);
+}
+
+void
+ixpress_load_raw()
+{
+  unsigned short pixel[4090];
+  int row, col;
+
+  order = 0x4949;
+  fseek (ifp, 304 + 6*2*4090, SEEK_SET);
+  for (row=height; --row >= 0; ) {
+    read_shorts(ifp, pixel, 4090);
+    for (col=0; col < width; col++)
+      BAYER(row,col) = pixel[width-1-col];
+  }
+}
+
+void
+leaf_load_raw()
+{
+  unsigned short *pixel;
+  int r, c, row, col;
+
+  pixel = calloc (raw_width, sizeof *pixel);
+  merror (pixel, "leaf_load_raw()");
+  for (r=0; r < height-32; r+=32)
+    FORC3 for (row=r; row < r+32; row++) {
+      read_shorts(ifp, pixel, raw_width);
+      for (col=0; col < width; col++)
+    image[row*width+col][c] = pixel[col];
+    }
+  free (pixel);
+}
+
+/*
+   For this function only, raw_width is in bytes, not pixels!
+ */
+void
+packed_12_load_raw()
+{
+  int row, col;
+
+  getbits(ifp, -1);
+  for (row=0; row < height; row++) {
+    for (col=0; col < width; col++)
+      BAYER(row,col) = getbits(ifp, 12);
+    for (col = width*3/2; col < raw_width; col++)
+      getbits(ifp, 8);
+  }
+}
+
+void
+unpacked_load_raw()
+{
+  unsigned short *pixel;
+  int row, col;
+
+  pixel = calloc (raw_width, sizeof *pixel);
+  merror (pixel, "unpacked_load_raw()");
+  for (row=0; row < height; row++) {
+    read_shorts(ifp, pixel, raw_width);
+    for (col=0; col < width; col++)
+      BAYER(row,col) = pixel[col];
+  }
+  free (pixel);
+}
+
+void
+olympus_e300_load_raw()
+{
+  unsigned char  *data,  *dp;
+  unsigned short *pixel, *pix;
+  int dwide, row, col;
+
+  dwide = raw_width * 16 / 10;
+  data = malloc (dwide + raw_width*2);
+  merror (data, "olympus_e300_load_raw()");
+  pixel = (unsigned short *) (data + dwide);
+  for (row=0; row < height; row++) {
+    fread (data, 1, dwide, ifp);
+    for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) {
+      if (((dp-data) & 15) == 15) dp++;
+      pix[0] = dp[1] << 8 | dp[0];
+      pix[1] = dp[2] << 4 | dp[1] >> 4;
+    }
+    for (col=0; col < width; col++)
+      BAYER(row,col) = (pixel[col] & 0xfff);
+  }
+  free (data);
+}
+
+void
+olympus_cseries_load_raw()
+{
+  int irow, row, col;
+
+  for (irow=0; irow < height; irow++) {
+    row = irow * 2 % height + irow / (height/2);
+    if (row < 2) {
+      fseek (ifp, data_offset - row*(-width*height*3/4 & -2048), SEEK_SET);
+      getbits(ifp, -1);
+    }
+    for (col=0; col < width; col++)
+      BAYER(row,col) = getbits(ifp, 12);
+  }
+}
+
+void
+eight_bit_load_raw()
+{
+  unsigned char *pixel;
+  int row, col;
+
+  pixel = calloc (raw_width, sizeof *pixel);
+  merror (pixel, "eight_bit_load_raw()");
+  for (row=0; row < height; row++) {
+    fread (pixel, 1, raw_width, ifp);
+    for (col=0; col < width; col++)
+      BAYER(row,col) = pixel[col];
+  }
+  free (pixel);
+  maximum = 0xff;
+}
+
+void
+casio_qv5700_load_raw()
+{
+  unsigned char  data[3232],  *dp;
+  unsigned short pixel[2576], *pix;
+  int row, col;
+
+  for (row=0; row < height; row++) {
+    fread (data, 1, 3232, ifp);
+    for (dp=data, pix=pixel; dp < data+3220; dp+=5, pix+=4) {
+      pix[0] = (dp[0] << 2) + (dp[1] >> 6);
+      pix[1] = (dp[1] << 4) + (dp[2] >> 4);
+      pix[2] = (dp[2] << 6) + (dp[3] >> 2);
+      pix[3] = (dp[3] << 8) + (dp[4]     );
+    }
+    for (col=0; col < width; col++)
+      BAYER(row,col) = (pixel[col] & 0x3ff);
+  }
+  maximum = 0x3fc;
+}
+
+void
+nucore_load_raw()
+{
+  unsigned short *pixel;
+  int irow, row, col;
+
+  pixel = calloc (width, 2);
+  merror (pixel, "nucore_load_raw()");
+  for (irow=0; irow < height; irow++) {
+    read_shorts(ifp, pixel, width);
+    row = irow/2 + height/2 * (irow & 1);
+    for (col=0; col < width; col++)
+      BAYER(row,col) = pixel[col];
+  }
+  free (pixel);
+}
+
+static int  radc_token (int tree)
+{
+  int t;
+  static struct decode *dstart[18], *dindex;
+  static const int *s, source[] = {
+    1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8,
+    1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8,
+    2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8,
+    2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8,
+    2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8,
+    2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8,
+    2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8,
+    2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8,
+    2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4,
+    2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8,
+    1,0, 2,2, 2,-2,
+    1,-3, 1,3,
+    2,-17, 2,-5, 2,5, 2,17,
+    2,-7, 2,2, 2,9, 2,18,
+    2,-18, 2,-9, 2,-2, 2,7,
+    2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79,
+    2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76,
+    2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37
+  };
+
+  if (free_decode == first_decode)
+    for (s=source, t=0; t < 18; t++) {
+      dstart[t] = free_decode;
+      s = make_decoder_int (s, 0);
+    }
+  if (tree == 18) {
+    if (model[2] == '4')
+      return (getbits(ifp, 5) << 3) + 4; /* DC40 */
+    else
+      return (getbits(ifp, 6) << 2) + 2; /* DC50 */
+  }
+  for (dindex = dstart[tree]; dindex->branch[0]; )
+    dindex = dindex->branch[getbits(ifp, 1)];
+  return dindex->leaf;
+}
+
+#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--)
+
+#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \
+: (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];
+
+  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;
+        }
+          }
+        } 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() {}
+#else
+
+static boolean
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+  static char jpeg_buffer[4096];
+  size_t nbytes;
+
+  nbytes = fread (jpeg_buffer, 1, 4096, ifp);
+  swab (jpeg_buffer, jpeg_buffer, nbytes);
+  cinfo->src->next_input_byte = jpeg_buffer;
+  cinfo->src->bytes_in_buffer = nbytes;
+  return TRUE;
+}
+
+void
+kodak_jpeg_load_raw()
+{
+  struct jpeg_decompress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  JSAMPARRAY buf;
+  JSAMPLE (*pixel)[3];
+  int row, col;
+
+  cinfo.err = jpeg_std_error (&jerr);
+  jpeg_create_decompress (&cinfo);
+  jpeg_stdio_src (&cinfo, ifp);
+  cinfo.src->fill_input_buffer = fill_input_buffer;
+  jpeg_read_header (&cinfo, TRUE);
+  jpeg_start_decompress (&cinfo);
+  if ((cinfo.output_width      != width  ) ||
+      (cinfo.output_height*2   != height ) ||
+      (cinfo.output_components != 3      )) {
+    pm_error ("incorrect JPEG dimensions");
+  }
+  buf = (*cinfo.mem->alloc_sarray)
+        ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1);
+
+  while (cinfo.output_scanline < cinfo.output_height) {
+    row = cinfo.output_scanline * 2;
+    jpeg_read_scanlines (&cinfo, buf, 1);
+    pixel = (void *) buf[0];
+    for (col=0; col < width; col+=2) {
+      BAYER(row+0,col+0) = pixel[col+0][1] << 1;
+      BAYER(row+1,col+1) = pixel[col+1][1] << 1;
+      BAYER(row+0,col+1) = pixel[col][0] + pixel[col+1][0];
+      BAYER(row+1,col+0) = pixel[col][2] + pixel[col+1][2];
+    }
+  }
+  jpeg_finish_decompress (&cinfo);
+  jpeg_destroy_decompress (&cinfo);
+  maximum = 0xff << 1;
+}
+
+#endif
+
+void
+kodak_dc120_load_raw()
+{
+  static const int mul[4] = { 162, 192, 187,  92 };
+  static const int add[4] = {   0, 636, 424, 212 };
+  unsigned char pixel[848];
+  int row, shift, col;
+
+  for (row=0; row < height; row++) {
+    fread (pixel, 848, 1, ifp);
+    shift = row * mul[row & 3] + add[row & 3];
+    for (col=0; col < width; col++)
+      BAYER(row,col) = (unsigned short) pixel[(col + shift) % 848];
+  }
+  maximum = 0xff;
+}
+
+void
+kodak_dc20_coeff (float const juice)
+{
+  static const float my_coeff[3][4] =
+  { {  2.25,  0.75, -1.75, -0.25 },
+    { -0.25,  0.75,  0.75, -0.25 },
+    { -0.25, -1.75,  0.75,  2.25 } };
+  static const float flat[3][4] =
+  { {  1, 0,   0,   0 },
+    {  0, 0.5, 0.5, 0 },
+    {  0, 0,   0,   1 } };
+  int r, g;
+
+  for (r=0; r < 3; r++)
+    for (g=0; g < 4; g++)
+      coeff[r][g] = my_coeff[r][g] * juice + flat[r][g] * (1-juice);
+  use_coeff = 1;
+}
+
+void
+kodak_easy_load_raw()
+{
+  unsigned char *pixel;
+  unsigned row, col, icol;
+
+  if (raw_width > width)
+    black = 0;
+  pixel = calloc (raw_width, sizeof *pixel);
+  merror (pixel, "kodak_easy_load_raw()");
+  for (row=0; row < height; row++) {
+    fread (pixel, 1, raw_width, ifp);
+    for (col=0; col < raw_width; col++) {
+      icol = col - left_margin;
+      if (icol < width)
+    BAYER(row,icol) = (unsigned short) curve[pixel[col]];
+      else
+    black += curve[pixel[col]];
+    }
+  }
+  free (pixel);
+  if (raw_width > width)
+    black /= (raw_width - width) * height;
+  if (!strncmp(model,"DC2",3))
+    black = 0;
+  maximum = curve[0xff];
+}
+
+void
+kodak_compressed_load_raw()
+{
+  unsigned char c, blen[256];
+  unsigned short raw[6];
+  unsigned row, col, len, save, i, israw=0, bits=0, pred[2];
+  INT64 bitbuf=0;
+  int diff;
+
+  assert(have64BitArithmetic);
+
+  for (row=0; row < height; row++)
+    for (col=0; col < width; col++)
+    {
+      if ((col & 255) == 0) {       /* Get the bit-lengths of the */
+    len = width - col;      /* next 256 pixel values      */
+    if (len > 256) len = 256;
+    save = ftell(ifp);
+    for (israw=i=0; i < len; i+=2) {
+      c = fgetc(ifp);
+      if ((blen[i+0] = c & 15) > 12 ||
+          (blen[i+1] = c >> 4) > 12 )
+        israw = 1;
+    }
+    bitbuf = bits = pred[0] = pred[1] = 0;
+    if (len % 8 == 4) {
+      bitbuf  = fgetc(ifp) << 8;
+      bitbuf += fgetc(ifp);
+      bits = 16;
+    }
+    if (israw)
+      fseek (ifp, save, SEEK_SET);
+      }
+      if (israw) {          /* If the data is not compressed */
+    switch (col & 7) {
+      case 0:
+        read_shorts(ifp, raw, 6);
+        diff = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12;
+        break;
+      case 1:
+        diff = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12;
+        break;
+      default:
+        diff = raw[(col & 7) - 2] & 0xfff;
+    }
+      } else {              /* If the data is compressed */
+    len = blen[col & 255];      /* Number of bits for this pixel */
+    if (bits < len) {       /* Got enough bits in the buffer? */
+      for (i=0; i < 32; i+=8)
+        bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+      bits += 32;
+    }
+    diff = bitbuf & (0xffff >> (16-len));  /* Pull bits from buffer */
+    bitbuf >>= len;
+    bits -= len;
+    if ((diff & (1 << (len-1))) == 0)
+      diff -= (1 << len) - 1;
+    pred[col & 1] += diff;
+    diff = pred[col & 1];
+      }
+      BAYER(row,col) = curve[diff];
+    }
+}
+
+void
+kodak_yuv_load_raw()
+{
+  unsigned char c, blen[384];
+  unsigned row, col, len, bits=0;
+  INT64 bitbuf=0;
+  int i, li=0, si, diff, six[6], y[4], cb=0, cr=0, rgb[3];
+  unsigned short *ip;
+
+  assert(have64BitArithmetic);
+
+  for (row=0; row < height; row+=2)
+    for (col=0; col < width; col+=2) {
+      if ((col & 127) == 0) {
+    len = (width - col + 1) * 3 & -4;
+    if (len > 384) len = 384;
+    for (i=0; i < len; ) {
+      c = fgetc(ifp);
+      blen[i++] = c & 15;
+      blen[i++] = c >> 4;
+    }
+    li = bitbuf = bits = y[1] = y[3] = cb = cr = 0;
+    if (len % 8 == 4) {
+      bitbuf  = fgetc(ifp) << 8;
+      bitbuf += fgetc(ifp);
+      bits = 16;
+    }
+      }
+      for (si=0; si < 6; si++) {
+    len = blen[li++];
+    if (bits < len) {
+      for (i=0; i < 32; i+=8)
+        bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+      bits += 32;
+    }
+    diff = bitbuf & (0xffff >> (16-len));
+    bitbuf >>= len;
+    bits -= len;
+    if ((diff & (1 << (len-1))) == 0)
+      diff -= (1 << len) - 1;
+    six[si] = diff;
+      }
+      y[0] = six[0] + y[1];
+      y[1] = six[1] + y[0];
+      y[2] = six[2] + y[3];
+      y[3] = six[3] + y[2];
+      cb  += six[4];
+      cr  += six[5];
+      for (i=0; i < 4; i++) {
+    ip = image[(row+(i >> 1))*width + col+(i & 1)];
+    rgb[0] = y[i] + cr;
+    rgb[1] = y[i];
+    rgb[2] = y[i] + cb;
+    FORC3 if (rgb[c] > 0) ip[c] = curve[rgb[c]];
+      }
+    }
+  maximum = 0xe74;
+}
+
+static void  sony_decrypt (unsigned *data, int len, int start, int key)
+{
+  static uint32_t pad[128];
+  unsigned int p;
+
+  if (start) {
+    for (p=0; p < 4; p++)
+      pad[p] = key = key * 48828125 + 1;
+    pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31;
+    for (p=4; p < 127; p++)
+      pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31;
+
+    /* Convert to big-endian */
+
+    for (p=0; p < 127; p++) {
+        union {
+            unsigned char bytes[4];
+            uint32_t word;
+        } u;
+
+        u.bytes[0] = pad[p] >> 24;
+        u.bytes[1] = pad[p] >> 16;
+        u.bytes[2] = pad[p] >>  8;
+        u.bytes[3] = pad[p] >>  0;
+        
+        pad[p] = u.word;
+    }
+  }
+  while (len--)
+    *data++ ^= pad[p++ & 0x7f] = pad[(p+1) & 0x7f] ^ pad[(p+65) & 0x7f];
+}
+
+void
+sony_load_raw()
+{
+  unsigned char head[40];
+  struct pixel {
+      unsigned char bytes[2];
+  };
+  struct pixel * pixelrow;
+  unsigned i, key, row, col;
+
+  fseek (ifp, 200896, SEEK_SET);
+  fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR);
+  order = 0x4d4d;
+  key = get4(ifp);
+  fseek (ifp, 164600, SEEK_SET);
+  fread (head, 1, 40, ifp);
+  sony_decrypt ((void *) head, 10, 1, key);
+  for (i=26; i-- > 22; )
+    key = key << 8 | head[i];
+  fseek (ifp, data_offset, SEEK_SET);
+  MALLOCARRAY(pixelrow, raw_width);
+  merror (pixelrow, "sony_load_raw()");
+  for (row=0; row < height; row++) {
+    fread (pixelrow, 2, raw_width, ifp);
+    sony_decrypt ((void *) pixelrow, raw_width/2, !row, key);
+    for (col=9; col < left_margin; col++)
+      black += pixelrow[col].bytes[0] * 256 + pixelrow[col].bytes[1];
+    for (col=0; col < width; col++)
+      BAYER(row,col) =
+          pixelrow[col+left_margin].bytes[0] * 256 +
+          pixelrow[col+left_margin].bytes[1];
+  }
+  free (pixelrow);
+  if (left_margin > 9)
+    black /= (left_margin-9) * height;
+  maximum = 0x3ff0;
+}
+
+void
+parse_minolta(FILE * const ifp)
+{
+  int save, tag, len, offset, high=0, wide=0;
+
+  fseek (ifp, 4, SEEK_SET);
+  offset = get4(ifp) + 8;
+  while ((save=ftell(ifp)) < offset) {
+    tag = get4(ifp);
+    len = get4(ifp);
+    switch (tag) {
+      case 0x505244:                /* PRD */
+    fseek (ifp, 8, SEEK_CUR);
+    high = get2(ifp);
+    wide = get2(ifp);
+    break;
+      case 0x574247:                /* WBG */
+    get4(ifp);
+    camera_red  = get2(ifp);
+    camera_red /= get2(ifp);
+    camera_blue = get2(ifp);
+    camera_blue = get2(ifp) / camera_blue;
+    break;
+      case 0x545457:                /* TTW */
+    parse_tiff(ifp, ftell(ifp));
+    }
+    fseek (ifp, save+len+8, SEEK_SET);
+  }
+  raw_height = high;
+  raw_width  = wide;
+  data_offset = offset;
+}
+
+/*
+   CIFF block 0x1030 contains an 8x8 white sample.
+   Load this into white[][] for use in scale_colors().
+ */
+static void  ciff_block_1030()
+{
+  static const unsigned short key[] = { 0x410, 0x45f3 };
+  int i, bpp, row, col, vbits=0;
+  unsigned long bitbuf=0;
+
+  get2(ifp);
+  if (get4(ifp) != 0x80008) return;
+  if (get4(ifp) == 0) return;
+  bpp = get2(ifp);
+  if (bpp != 10 && bpp != 12) return;
+  for (i=row=0; row < 8; row++)
+    for (col=0; col < 8; col++) {
+      if (vbits < bpp) {
+    bitbuf = bitbuf << 16 | (get2(ifp) ^ key[i++ & 1]);
+    vbits += 16;
+      }
+      white[row][col] =
+    bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp);
+      vbits -= bpp;
+    }
+}
+
+/*
+   Parse a CIFF file, better known as Canon CRW format.
+ */
+void 
+parse_ciff(FILE * const ifp, 
+           int    const offset, 
+           int    const length)
+{
+  int tboff, nrecs, i, type, len, roff, aoff, save, wbi=-1;
+  static const int remap[] = { 1,2,3,4,5,1 };
+  static const int remap_10d[] = { 0,1,3,4,5,6,0,0,2,8 };
+  static const int remap_s70[] = { 0,1,2,9,4,3,6,7,8,9,10,0,0,0,7,0,0,8 };
+  unsigned short key[] = { 0x410, 0x45f3 };
+
+  if (strcmp(model,"Canon PowerShot G6") &&
+      strcmp(model,"Canon PowerShot S70") &&
+      strcmp(model,"Canon PowerShot Pro1"))
+    key[0] = key[1] = 0;
+  fseek (ifp, offset+length-4, SEEK_SET);
+  tboff = get4(ifp) + offset;
+  fseek (ifp, tboff, SEEK_SET);
+  nrecs = get2(ifp);
+  for (i = 0; i < nrecs; i++) {
+    type = get2(ifp);
+    len  = get4(ifp);
+    roff = get4(ifp);
+    aoff = offset + roff;
+    save = ftell(ifp);
+    if (type == 0x080a) {       /* Get the camera make and model */
+      fseek (ifp, aoff, SEEK_SET);
+      fread (make, 64, 1, ifp);
+      fseek (ifp, aoff+strlen(make)+1, SEEK_SET);
+      fread (model, 64, 1, ifp);
+    }
+    if (type == 0x102a) {       /* Find the White Balance index */
+      fseek (ifp, aoff+14, SEEK_SET);   /* 0=auto, 1=daylight, 2=cloudy ... */
+      wbi = get2(ifp);
+      if (((!strcmp(model,"Canon EOS DIGITAL REBEL") ||
+        !strcmp(model,"Canon EOS 300D DIGITAL"))) && wbi == 6)
+    wbi++;
+    }
+    if (type == 0x102c) {       /* Get white balance (G2) */
+      if (!strcmp(model,"Canon PowerShot G1") ||
+      !strcmp(model,"Canon PowerShot Pro90 IS")) {
+    fseek (ifp, aoff+120, SEEK_SET);
+    white[0][1] = get2(ifp);
+    white[0][0] = get2(ifp);
+    white[1][0] = get2(ifp);
+    white[1][1] = get2(ifp);
+      } else {
+    fseek (ifp, aoff+100, SEEK_SET);
+    goto common;
+      }
+    }
+    if (type == 0x0032) {       /* Get white balance (D30 & G3) */
+      if (!strcmp(model,"Canon EOS D30")) {
+    fseek (ifp, aoff+72, SEEK_SET);
+common:
+    camera_red   = get2(ifp) ^ key[0];
+    camera_red   =(get2(ifp) ^ key[1]) / camera_red;
+    camera_blue  = get2(ifp) ^ key[0];
+    camera_blue /= get2(ifp) ^ key[1];
+      } else if (!strcmp(model,"Canon PowerShot G6") ||
+         !strcmp(model,"Canon PowerShot S70")) {
+    fseek (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET);
+    goto common;
+      } else if (!strcmp(model,"Canon PowerShot Pro1")) {
+    fseek (ifp, aoff+96 + wbi*8, SEEK_SET);
+    goto common;
+      } else {
+    fseek (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET);
+    if (!camera_red)
+      goto common;
+      }
+    }
+    if (type == 0x10a9) {       /* Get white balance (D60) */
+      if (!strcmp(model,"Canon EOS 10D"))
+    wbi = remap_10d[wbi];
+      fseek (ifp, aoff+2 + wbi*8, SEEK_SET);
+      camera_red  = get2(ifp);
+      camera_red /= get2(ifp);
+      camera_blue = get2(ifp);
+      camera_blue = get2(ifp) / camera_blue;
+    }
+    if (type == 0x1030 && (wbi == 6 || wbi == 15)) {
+      fseek (ifp, aoff, SEEK_SET);  /* Get white sample */
+      ciff_block_1030();
+    }
+    if (type == 0x1031) {       /* Get the raw width and height */
+      fseek (ifp, aoff+2, SEEK_SET);
+      raw_width  = get2(ifp);
+      raw_height = get2(ifp);
+    }
+    if (type == 0x180e) {       /* Get the timestamp */
+      fseek (ifp, aoff, SEEK_SET);
+      timestamp = get4(ifp);
+    }
+    if (type == 0x580e)
+      timestamp = len;
+    if (type == 0x1810) {       /* Get the rotation */
+      fseek (ifp, aoff+12, SEEK_SET);
+      flip = get4(ifp);
+    }
+    if (type == 0x1835) {       /* Get the decoder table */
+      fseek (ifp, aoff, SEEK_SET);
+      crw_init_tables (get4(ifp));
+    }
+    if (type >> 8 == 0x28 || type >> 8 == 0x30) /* Get sub-tables */
+      parse_ciff(ifp, aoff, len);
+    fseek (ifp, save, SEEK_SET);
+  }
+  if (wbi == 0 && !strcmp(model,"Canon EOS D30"))
+    camera_red = -1;            /* Use my auto WB for this photo */
+}
+
+void
+parse_rollei(FILE * const ifp)
+{
+  char line[128], *val;
+  int tx=0, ty=0;
+  struct tm t;
+  time_t ts;
+
+  fseek (ifp, 0, SEEK_SET);
+  do {
+    fgets (line, 128, ifp);
+    if ((val = strchr(line,'=')))
+      *val++ = 0;
+    else
+      val = line + strlen(line);
+    if (!strcmp(line,"DAT"))
+      sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year);
+    if (!strcmp(line,"TIM"))
+      sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec);
+    if (!strcmp(line,"HDR"))
+      data_offset = atoi(val);
+    if (!strcmp(line,"X  "))
+      raw_width = atoi(val);
+    if (!strcmp(line,"Y  "))
+      raw_height = atoi(val);
+    if (!strcmp(line,"TX "))
+      tx = atoi(val);
+    if (!strcmp(line,"TY "))
+      ty = atoi(val);
+  } while (strncmp(line,"EOHD",4));
+  t.tm_year -= 1900;
+  t.tm_mon -= 1;
+  putenv((char*)"TZ=");
+  if ((ts = mktime(&t)) > 0)
+    timestamp = ts;
+  data_offset += tx * ty * 2;
+  strcpy (make, "Rollei");
+  strcpy (model,"d530flex");
+}
+
+
+
+void
+parse_mos(FILE * const ifp, 
+          int    const offset)
+{
+    char data[40];
+    int skip, from, i, neut[4];
+
+    fseek (ifp, offset, SEEK_SET);
+    while (1) {
+        fread (data, 1, 8, ifp);
+        if (strcmp(data,"PKTS")) break;
+        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);
+            camera_red  = (float) neut[2] / neut[1];
+            camera_blue = (float) neut[2] / neut[3];
+        }
+        parse_mos(ifp, from);
+        fseek (ifp, skip+from, SEEK_SET);
+    }
+}
+
+void
+nikon_e950_coeff()
+{
+  int r, g;
+  static const float my_coeff[3][4] =
+  { { -1.936280,  1.800443, -1.448486,  2.584324 },
+    {  1.405365, -0.524955, -0.289090,  0.408680 },
+    { -1.204965,  1.082304,  2.941367, -1.818705 } };
+
+  for (r=0; r < 3; r++)
+    for (g=0; g < 4; g++)
+      coeff[r][g] = my_coeff[r][g];
+  use_coeff = 1;
+}
+
+
+
+static double getrat()
+{
+  double num = get4(ifp);
+  return num / get4(ifp);
+}
+
+
+
+static void 
+parse_makernote(FILE * const ifp)
+{
+  unsigned base=0, offset=0, entries, tag, type, len, save;
+  static const int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
+  short sorder;
+  char buf[10];
+/*
+   The MakerNote might have its own TIFF header (possibly with
+   its own byte-order!), or it might just be a table.
+ */
+  sorder = order;
+  fread (buf, 1, 10, ifp);
+  if (!strncmp (buf,"KC" ,2) ||     /* these aren't TIFF format */
+      !strncmp (buf,"MLY",3)) return;
+  if (!strcmp (buf,"Nikon")) {
+    base = ftell(ifp);
+    order = get2(ifp);
+    if (get2(ifp) != 42) goto quit;
+    offset = get4(ifp);
+    fseek (ifp, offset-8, SEEK_CUR);
+  } else if (!strncmp (buf,"FUJIFILM",8) ||
+         !strcmp  (buf,"Panasonic")) {
+    order = 0x4949;
+    fseek (ifp,  2, SEEK_CUR);
+  } else if (!strcmp (buf,"OLYMP") ||
+         !strcmp (buf,"LEICA") ||
+         !strcmp (buf,"EPSON"))
+    fseek (ifp, -2, SEEK_CUR);
+  else if (!strcmp (buf,"AOC") ||
+       !strcmp (buf,"QVC"))
+    fseek (ifp, -4, SEEK_CUR);
+  else fseek (ifp, -10, SEEK_CUR);
+
+  entries = get2(ifp);
+  while (entries--) {
+    tag  = get2(ifp);
+    type = get2(ifp);
+    len  = get4(ifp);
+    save = ftell(ifp);
+    if (len * size[type < 13 ? type:0] > 4)
+      fseek (ifp, get4(ifp)+base, SEEK_SET);
+
+    if (tag == 0xc && len == 4) {
+      camera_red  = getrat();
+      camera_blue = getrat();
+    }
+    if (tag == 0x14 && len == 2560 && type == 7) {
+      fseek (ifp, 1248, SEEK_CUR);
+      goto get2_256;
+    }
+    if (strstr(make,"PENTAX")) {
+      if (tag == 0x1b) tag = 0x1018;
+      if (tag == 0x1c) tag = 0x1017;
+    }
+    if (tag == 0x8c)
+      nikon_curve_offset = ftell(ifp) + 2112;
+    if (tag == 0x96)
+      nikon_curve_offset = ftell(ifp) + 2;
+    if (tag == 0x97) {
+      if (!strcmp(model,"NIKON D100 ")) {
+    fseek (ifp, 72, SEEK_CUR);
+    camera_red  = get2(ifp) / 256.0;
+    camera_blue = get2(ifp) / 256.0;
+      } else if (!strcmp(model,"NIKON D2H")) {
+    fseek (ifp, 10, SEEK_CUR);
+    goto get2_rggb;
+      } else if (!strcmp(model,"NIKON D70")) {
+    fseek (ifp, 20, SEEK_CUR);
+    camera_red  = get2(ifp);
+    camera_red /= get2(ifp);
+    camera_blue = get2(ifp);
+    camera_blue/= get2(ifp);
+      }
+    }
+    if (tag == 0xe0 && len == 17) {
+      get2(ifp);
+      raw_width  = get2(ifp);
+      raw_height = get2(ifp);
+    }
+    if (tag == 0x200 && len == 4)
+      black = (get2(ifp)+get2(ifp)+get2(ifp)+get2(ifp))/4;
+    if (tag == 0x201 && len == 4) {
+      camera_red  = get2(ifp);
+      camera_red /= get2(ifp);
+      camera_blue = get2(ifp);
+      camera_blue = get2(ifp) / camera_blue;
+    }
+    if (tag == 0x401 && len == 4) {
+      black = (get4(ifp)+get4(ifp)+get4(ifp)+get4(ifp))/4;
+    }
+    if (tag == 0xe80 && len == 256 && type == 7) {
+      fseek (ifp, 48, SEEK_CUR);
+      camera_red  = get2(ifp) * 508 * 1.078 / 0x10000;
+      camera_blue = get2(ifp) * 382 * 1.173 / 0x10000;
+    }
+    if (tag == 0xf00 && len == 614 && type == 7) {
+      fseek (ifp, 188, SEEK_CUR);
+      goto get2_256;
+    }
+    if (tag == 0x1017)
+      camera_red  = get2(ifp) / 256.0;
+    if (tag == 0x1018)
+      camera_blue = get2(ifp) / 256.0;
+    if (tag == 0x2011 && len == 2) {
+get2_256:
+      order = 0x4d4d;
+      camera_red  = get2(ifp) / 256.0;
+      camera_blue = get2(ifp) / 256.0;
+    }
+    if (tag == 0x4001) {
+      fseek (ifp, strstr(model,"EOS-1D") ? 68:50, SEEK_CUR);
+get2_rggb:
+      camera_red  = get2(ifp);
+      camera_red /= get2(ifp);
+      camera_blue = get2(ifp);
+      camera_blue = get2(ifp) / camera_blue;
+    }
+    fseek (ifp, save+4, SEEK_SET);
+  }
+quit:
+  order = sorder;
+}
+
+
+
+static void
+get_timestamp(FILE * const ifp)
+{
+/*
+   Since the TIFF DateTime string has no timezone information,
+   assume that the camera's clock was set to Universal Time.
+ */
+  struct tm t;
+  time_t ts;
+
+  if (fscanf (ifp, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon,
+    &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6)
+    return;
+  t.tm_year -= 1900;
+  t.tm_mon -= 1;
+  putenv((char*)"TZ=UTC");   /* Remove this to assume local time */
+  if ((ts = mktime(&t)) > 0)
+    timestamp = ts;
+}
+
+static void 
+parse_exif(FILE * const ifp, int base)
+{
+  int entries, tag, type, len, val, save;
+
+  entries = get2(ifp);
+  while (entries--) {
+    tag  = get2(ifp);
+    type = get2(ifp);
+    len  = get4(ifp);
+    val  = get4(ifp);
+    save = ftell(ifp);
+    fseek (ifp, base+val, SEEK_SET);
+    if (tag == 0x9003 || tag == 0x9004)
+      get_timestamp(ifp);
+    if (tag == 0x927c) {
+      if (!strncmp(make,"SONY",4))
+    data_offset = base+val+len;
+      else
+    parse_makernote(ifp);
+    }
+    fseek (ifp, save, SEEK_SET);
+  }
+}
+
+static int 
+parse_tiff_ifd(FILE * const ifp, int base, int level)
+{
+  unsigned entries, tag, type, len, plen=16, save;
+  int done=0, use_cm=0, cfa, i, j, c;
+  static const int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
+  char software[64];
+  static const int flip_map[] = { 0,1,3,2,4,6,7,5 };
+  unsigned char cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256];
+  unsigned short scale[4];
+  double dblack, cc[4][4], cm[4][3];
+  double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 };
+
+  for (j=0; j < 4; j++)
+    for (i=0; i < 4; i++)
+      cc[j][i] = i == j;
+  entries = get2(ifp);
+  if (entries > 512) return 1;
+  while (entries--) {
+    tag  = get2(ifp);
+    type = get2(ifp);
+    len  = get4(ifp);
+    save = ftell(ifp);
+    if (tag > 50700 && tag < 50800) done = 1;
+    if (len * size[type < 13 ? type:0] > 4)
+      fseek (ifp, get4(ifp)+base, SEEK_SET);
+    switch (tag) {
+      case 0x11:
+    camera_red  = get4(ifp) / 256.0;
+    break;
+      case 0x12:
+    camera_blue = get4(ifp) / 256.0;
+    break;
+      case 0x100:           /* ImageWidth */
+    if (strcmp(make,"Canon") || level)
+      raw_width = type==3 ? get2(ifp) : get4(ifp);
+    break;
+      case 0x101:           /* ImageHeight */
+    if (strcmp(make,"Canon") || level)
+      raw_height = type==3 ? get2(ifp) : get4(ifp);
+    break;
+      case 0x102:           /* Bits per sample */
+    fuji_secondary = len == 2;
+    if (level) maximum = (1 << get2(ifp)) - 1;
+    break;
+      case 0x103:           /* Compression */
+    tiff_data_compression = get2(ifp);
+    break;
+      case 0x106:           /* Kodak color format */
+    kodak_data_compression = get2(ifp);
+    break;
+      case 0x10f:           /* Make */
+    fgets (make, 64, ifp);
+    break;
+      case 0x110:           /* Model */
+    fgets (model, 64, ifp);
+    break;
+      case 0x111:           /* StripOffset */
+    data_offset = get4(ifp);
+    break;
+      case 0x112:           /* Orientation */
+    flip = flip_map[(get2(ifp)-1) & 7];
+    break;
+      case 0x115:           /* SamplesPerPixel */
+    tiff_samples = get2(ifp);
+    break;
+      case 0x131:           /* Software tag */
+    fgets (software, 64, ifp);
+    if (!strncmp(software,"Adobe",5))
+      make[0] = 0;
+    break;
+      case 0x132:           /* DateTime tag */
+    get_timestamp(ifp);
+    break;
+      case 0x144:           /* TileOffsets */
+    if (level) {
+      data_offset = ftell(ifp);
+    } else {
+      strcpy (make, "Leaf");
+      data_offset = get4(ifp);
+    }
+    break;
+      case 0x14a:           /* SubIFD tag */
+    if (len > 2 && !is_dng && !strcmp(make,"Kodak"))
+        len = 2;
+    while (len--) {
+      i = ftell(ifp);
+      fseek (ifp, get4(ifp)+base, SEEK_SET);
+      if (parse_tiff_ifd(ifp, base, level+1)) break;
+      fseek (ifp, i+4, SEEK_SET);
+    }
+    break;
+      case 33405:           /* Model2 */
+    fgets (model2, 64, ifp);
+    break;
+      case 33422:           /* CFAPattern */
+    if ((plen=len) > 16) plen = 16;
+    fread (cfa_pat, 1, plen, ifp);
+    for (colors=cfa=i=0; i < plen; i++) {
+      colors += !(cfa & (1 << cfa_pat[i]));
+      cfa |= 1 << cfa_pat[i];
+    }
+    if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3);   /* CMY */
+    if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4);   /* GMCY */
+    goto guess_cfa_pc;
+      case 34665:           /* EXIF tag */
+    fseek (ifp, get4(ifp)+base, SEEK_SET);
+    parse_exif(ifp, base);
+    break;
+      case 50706:           /* DNGVersion */
+    is_dng = 1;
+    if (flip == 7) flip = 4;    /* Adobe didn't read the TIFF spec. */
+    break;
+      case 50710:           /* CFAPlaneColor */
+    if (len > 4) len = 4;
+    colors = len;
+    fread (cfa_pc, 1, colors, ifp);
+guess_cfa_pc:
+    FORC4 tab[cfa_pc[c]] = c;
+    for (i=16; i--; )
+      filters = filters << 2 | tab[cfa_pat[i % plen]];
+    break;
+      case 50711:           /* CFALayout */
+    if (get2(ifp) == 2) {
+      fuji_width = (raw_width+1)/2;
+      filters = 0x49494949;
+    }
+    break;
+      case 0x123:
+      case 0x90d:
+      case 50712:           /* LinearizationTable */
+    if (len > 0x1000)
+        len = 0x1000;
+    read_shorts(ifp, curve, len);
+    for (i=len; i < 0x1000; i++)
+      maximum = curve[i] = curve[i-1];
+    break;
+      case 50714:           /* BlackLevel */
+      case 50715:           /* BlackLevelDeltaH */
+      case 50716:           /* BlackLevelDeltaV */
+    for (dblack=i=0; i < len; i++)
+      dblack += getrat();
+    black += dblack/len + 0.5;
+    break;
+      case 50717:           /* WhiteLevel */
+    maximum = get2(ifp);
+    break;
+      case 50718:           /* DefaultScale */
+    for (i=0; i < 4; i++)
+      scale[i] = get4(ifp);
+    if (scale[1]*scale[2] == 2*scale[0]*scale[3]) ymag = 2;
+    break;
+      case 50721:           /* ColorMatrix1 */
+      case 50722:           /* ColorMatrix2 */
+    FORC4 for (j=0; j < 3; j++)
+      cm[c][j] = getrat();
+    use_cm = 1;
+    break;
+      case 50723:           /* CameraCalibration1 */
+      case 50724:           /* CameraCalibration2 */
+    for (i=0; i < colors; i++)
+      FORC4 cc[i][c] = getrat();    
+      case 50727:           /* AnalogBalance */
+    FORC4 ab[c] = getrat();
+    break;
+      case 50728:           /* AsShotNeutral */
+    FORC4 asn[c] = getrat();
+    break;
+      case 50729:           /* AsShotWhiteXY */
+    xyz[0] = getrat();
+    xyz[1] = getrat();
+    xyz[2] = 1 - xyz[0] - xyz[1];
+    }
+    fseek (ifp, save+4, SEEK_SET);
+  }
+  for (i=0; i < colors; i++)
+    FORC4 cc[i][c] *= ab[i];
+  if (use_cm)
+    dng_coeff (cc, cm, xyz);
+  if (asn[0])
+    FORC4 pre_mul[c] = 1 / asn[c];
+  if (!use_cm)
+    FORC4 pre_mul[c] /= cc[c][c];
+
+  if (is_dng || level) return done;
+
+  if ((raw_height & 1) && !strncmp (make,"OLYMPUS",7))
+       raw_height++;
+
+  if (make[0] == 0 && raw_width == 680 && raw_height == 680) {
+    strcpy (make, "Imacon");
+    strcpy (model,"Ixpress");
+  }
+  return done;
+}
+
+void
+parse_tiff(FILE * const ifp, int base)
+{
+  int doff;
+
+  fseek (ifp, base, SEEK_SET);
+  order = get2(ifp);
+  if (order != 0x4949 && order != 0x4d4d) return;
+  get2(ifp);
+  while ((doff = get4(ifp))) {
+    fseek (ifp, doff+base, SEEK_SET);
+    if (parse_tiff_ifd(ifp, base, 0)) break;
+  }
+  if (!is_dng && !strncmp(make,"Kodak",5)) {
+    fseek (ifp, 12+base, SEEK_SET);
+    parse_tiff_ifd(ifp, base, 2);
+  }
+}
+
+
+
+/*
+   Many cameras have a "debug mode" that writes JPEG and raw
+   at the same time.  The raw file has no header, so try to
+   to open the matching JPEG file and read its metadata.
+ */
+void
+parse_external_jpeg(const char * const ifname)
+{
+    const char *file, *ext;
+    char * jfile;
+    char * jext;
+    char * jname;
+
+    ext  = strrchr (ifname, '.');
+    file = strrchr (ifname, '/');
+    if (!file) file = strrchr (ifname, '\\');
+    if (!file) file = ifname-1;
+    file++;
+    if (strlen(ext) != 4 || ext-file != 8) return;
+    jname = malloc (strlen(ifname) + 1);
+    merror (jname, "parse_external()");
+    strcpy (jname, ifname);
+    jfile = jname + (file - ifname);
+    jext  = jname + (ext  - ifname);
+    if (strcasecmp (ext, ".jpg")) {
+        strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg");
+        memcpy (jfile, file+4, 4);
+        memcpy (jfile+4, file, 4);
+    } else
+        while (isdigit(*--jext)) {
+            if (*jext != '9') {
+                (*jext)++;
+                break;
+            }
+            *jext = '0';
+        }
+    if (strcmp (jname, ifname)) {
+        FILE * ifP;
+        ifP = fopen (jname, "rb");
+        if (ifP) {
+            if (verbose)
+                pm_message ("Reading metadata from %s...", jname);
+            parse_tiff(ifP, 12);
+            fclose (ifP);
+        }
+    }
+    if (!timestamp)
+        pm_message ( "Failed to read metadata from %s", jname);
+    free (jname);
+}
+
diff --git a/converter/other/cameratopam/camera.h b/converter/other/cameratopam/camera.h
new file mode 100644
index 00000000..a1e884cf
--- /dev/null
+++ b/converter/other/cameratopam/camera.h
@@ -0,0 +1,131 @@
+#include <stdio.h>
+
+void 
+parse_ciff(FILE * const ifp,
+           int    const offset,
+           int    const length);
+
+void
+parse_external_jpeg(const char * const ifname);
+
+void
+parse_tiff(FILE * const ifp, int base);
+
+void
+parse_minolta(FILE * const ifp);
+
+void
+parse_rollei(FILE * const ifp);
+
+void
+parse_mos(FILE * const ifp,
+          int    const offset);
+
+void
+adobe_dng_load_raw_lj(void);
+
+void
+adobe_dng_load_raw_nc(void);
+
+int
+nikon_is_compressed(void);
+
+void
+nikon_compressed_load_raw(void);
+
+void
+nikon_e950_load_raw(void);
+
+void
+nikon_e950_coeff(void);
+
+int
+nikon_e990(void);
+
+int
+nikon_e2100(void);
+
+void
+nikon_e2100_load_raw(void);
+
+int
+minolta_z2(void);
+
+void
+fuji_s2_load_raw(void);
+
+void
+fuji_s3_load_raw(void);
+
+void
+fuji_s5000_load_raw(void);
+
+void
+unpacked_load_raw(void);
+
+void
+fuji_s7000_load_raw(void);
+
+void
+fuji_f700_load_raw(void);
+
+void
+packed_12_load_raw(void);
+
+void
+eight_bit_load_raw(void);
+
+void
+phase_one_load_raw(void);
+
+void
+ixpress_load_raw(void);
+
+void
+leaf_load_raw(void);
+
+void
+olympus_e300_load_raw(void);
+
+void
+olympus_cseries_load_raw(void);
+
+void
+sony_load_raw(void);
+
+void
+kodak_easy_load_raw(void);
+
+void
+kodak_compressed_load_raw(void);
+
+void
+kodak_yuv_load_raw(void);
+
+void
+kodak_dc20_coeff (float const juice);
+
+void
+kodak_radc_load_raw(void);
+
+void
+kodak_jpeg_load_raw(void);
+
+void
+kodak_dc120_load_raw(void);
+
+void
+rollei_load_raw(void);
+
+void
+casio_qv5700_load_raw(void);
+
+void
+nucore_load_raw(void);
+
+void
+nikon_load_raw(void);
+
+int
+pentax_optio33(void);
+
diff --git a/converter/other/cameratopam/cameratopam.c b/converter/other/cameratopam/cameratopam.c
new file mode 100644
index 00000000..92773c91
--- /dev/null
+++ b/converter/other/cameratopam/cameratopam.c
@@ -0,0 +1,906 @@
+/*
+   This is derived from Dave Coffin's raw photo decoder, dcraw.c,
+   Copyright 1997-2005 by Dave Coffin, dcoffin a cybercom o net.
+
+   See the COPYRIGHT file in the same directory as this file for
+   information on copyright and licensing.
+ */
+
+
+#define _BSD_SOURCE 1   /* Make sure string.h contains strcasecmp() */
+#define _XOPEN_SOURCE  /* Make sure unistd.h contains swab() */
+
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __CYGWIN__
+#include <io.h>
+#endif
+#ifdef WIN32
+  #include <winsock2.h>
+  #pragma comment(lib, "ws2_32.lib")
+  #define strcasecmp stricmp
+  typedef __int64 INT64;
+  static bool const have64BitArithmetic = true;
+#else
+  #include <unistd.h>
+#endif
+
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "pam.h"
+
+#include "global_variables.h"
+#include "util.h"
+#include "decode.h"
+#include "identify.h"
+#include "bayer.h"
+#include "foveon.h"
+#include "dng.h"
+
+#if HAVE_INT64
+   typedef int64_t INT64;
+   static bool const have64BitArithmetic = true;
+#else
+   /* We define INT64 to something that lets the code compile, but we
+      should not execute any INT64 code, because it will get the wrong
+      result.  */
+   typedef int INT64;
+   static bool const have64BitArithmetic = false;
+#endif
+
+/*
+   All global variables are defined here, and all functions that
+   access them are prefixed with "CLASS".  Note that a thread-safe
+   C++ class cannot have non-const static local variables.
+ */
+FILE * ifp;
+short order;
+char make[64], model[70], model2[64], *meta_data;
+time_t timestamp;
+int data_offset, meta_offset, meta_length;
+int tiff_data_compression, kodak_data_compression;
+int raw_height, raw_width, top_margin, left_margin;
+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 zero_after_ff;
+unsigned filters;
+unsigned short (*image)[4], white[8][8], curve[0x1000];
+int fuji_secondary;
+float cam_mul[4], pre_mul[4], coeff[3][4];
+int histogram[3][0x2000];
+jmp_buf failure;
+bool use_secondary;
+bool verbose;
+
+#ifdef USE_LCMS
+#include <lcms.h>
+int profile_offset, profile_length;
+#endif
+
+#define CLASS
+
+#define FORC3 for (c=0; c < 3; c++)
+#define FORC4 for (c=0; c < colors; c++)
+
+static void CLASS merror (const void *ptr, const char *where)
+{
+    if (ptr == NULL)
+        pm_error ("Out of memory in %s", where);
+}
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFileName;  /* "-" means Standard Input */
+    float bright;
+    float red_scale;
+    float blue_scale;
+    const char * profile;
+    unsigned int identify_only;
+    unsigned int verbose;
+    unsigned int half_size;
+    unsigned int four_color_rgb;
+    unsigned int document_mode;
+    unsigned int quick_interpolate;
+    unsigned int use_auto_wb;
+    unsigned int use_camera_wb;
+    unsigned int use_camera_rgb;
+    unsigned int use_secondary;
+    unsigned int no_clip_color;
+    unsigned int linear;
+};
+
+
+static struct cmdlineInfo cmdline;
+
+static void
+parseCommandLine(int argc, char ** argv,
+                 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
+   sometimes, one of these strings is actually just a suffix of an entry
+   in argv!
+-----------------------------------------------------------------------------*/
+    optStruct3 opt;
+    optEntry *option_def;
+    unsigned int option_def_index;
+    unsigned int brightSpec, red_scaleSpec, blue_scaleSpec,
+        profileSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;
+    opt.allowNegNum = FALSE;
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "bright", 
+            OPT_FLOAT,   &cmdlineP->bright,     &brightSpec, 0);
+    OPTENT3(0, "red_scale", 
+            OPT_FLOAT,   &cmdlineP->red_scale,  &red_scaleSpec, 0);
+    OPTENT3(0, "blue_scale", 
+            OPT_FLOAT,   &cmdlineP->blue_scale, &blue_scaleSpec, 0);
+    OPTENT3(0, "profile", 
+            OPT_STRING,  &cmdlineP->profile,    &profileSpec, 0);
+    OPTENT3(0,   "identify_only",   
+            OPT_FLAG,    NULL, &cmdlineP->identify_only, 0);
+    OPTENT3(0,   "verbose",   
+            OPT_FLAG,    NULL, &cmdlineP->verbose, 0);
+    OPTENT3(0,   "half_size",   
+            OPT_FLAG,    NULL, &cmdlineP->half_size, 0);
+    OPTENT3(0,   "four_color_rgb",   
+            OPT_FLAG,    NULL, &cmdlineP->four_color_rgb, 0);
+    OPTENT3(0,   "document_mode",   
+            OPT_FLAG,    NULL, &cmdlineP->document_mode, 0);
+    OPTENT3(0,   "quick_interpolate",   
+            OPT_FLAG,    NULL, &cmdlineP->quick_interpolate, 0);
+    OPTENT3(0,   "balance_auto",   
+            OPT_FLAG,    NULL, &cmdlineP->use_auto_wb, 0);
+    OPTENT3(0,   "balance_camera",   
+            OPT_FLAG,    NULL, &cmdlineP->use_camera_wb, 0);
+    OPTENT3(0,   "use_secondary",   
+            OPT_FLAG,    NULL, &cmdlineP->use_secondary, 0);
+    OPTENT3(0,   "no_clip_color",   
+            OPT_FLAG,    NULL, &cmdlineP->no_clip_color, 0);
+    OPTENT3(0,   "rgb",   
+            OPT_FLAG,    NULL, &cmdlineP->use_camera_rgb, 0);
+    OPTENT3(0,   "linear",   
+            OPT_FLAG,    NULL, &cmdlineP->linear, 0);
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+
+    if (!brightSpec)
+        cmdlineP->bright = 1.0;
+    if (!red_scaleSpec)
+        cmdlineP->red_scale = 1.0;
+    if (!blue_scaleSpec)
+        cmdlineP->blue_scale = 1.0;
+    if (!profileSpec)
+        cmdlineP->profile = NULL;
+
+
+    if (argc - 1 == 0)
+        cmdlineP->inputFileName = strdup("-");  /* he wants stdin */
+    else if (argc - 1 == 1)
+        cmdlineP->inputFileName = strdup(argv[1]);
+    else 
+        pm_error("Too many arguments.  The only argument accepted "
+                 "is the input file name");
+}
+
+  
+/*
+   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 = '/';
+#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);
+    }
+  }
+  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]++;
+    }
+    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])
+        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:
+
+   "Interpolation using a Threshold-based variable number of gradients"
+
+   described in http://www-ise.stanford.edu/~tingchen/algodep/vargra.html
+
+   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];
+    }
+    }
+  }
+  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++;
+      }
+    }
+  }
+  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<<g) *ip++ = g;
+    *ip++ = -1;
+      }
+      *ip++ = INT_MAX;
+      for (cp=chood, g=0; g < 8; g++) {
+    y = *cp++;  x = *cp++;
+    *ip++ = (y*width + x) * 4;
+    color = FC(row,col);
+    if (FC(row+y,col+x) != color && FC(row+y*2,col+x*2) == color)
+      *ip++ = (y*width + x) * 8 + color;
+    else
+      *ip++ = 0;
+      }
+    }
+  }
+  brow[4] = calloc (width*3, sizeof **brow);
+  merror (brow[4], "vng_interpolate()");
+  for (row=0; row < 3; row++)
+    brow[row] = brow[4] + row*width;
+  for (row=2; row < height-2; row++) {      /* Do VNG interpolation */
+    for (col=2; col < width-2; col++) {
+      pix = image[row*width+col];
+      ip = code[row & 7][col & 1];
+      memset (gval, 0, sizeof gval);
+      while ((g = ip[0]) != INT_MAX) {      /* Calculate gradients */
+    num = (diff = pix[g] - pix[ip[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];
+  }
+  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
+
+/*
+   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]++;
+    }
+}
+
+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;
+    }
+  free (image);
+  width  = wide;
+  height = high;
+  image  = img;
+  fuji_width = 0;
+}
+
+static void CLASS flip_image()
+{
+    unsigned *flag;
+    int size, base, dest, next, row, col, temp;
+
+    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;
+    }
+    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;
+            }
+            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;
+    }
+    free (flag);
+    if (flip & 4) {
+        temp = height;
+        height = width;
+        width = temp;
+        temp = ymag;
+        ymag = xmag;
+        xmag = temp;
+    }
+}
+
+/*
+   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);
+}
+
+/*
+   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
+writePam(FILE * const ofP,
+         bool   const linear) {
+
+    if (linear)
+        write_pam_linear(ofP);
+    else
+        write_pam_nonlinear(ofP);
+}
+
+
+
+
+static void CLASS
+convertIt(FILE *    const ifP,
+          FILE *    const ofP,
+          loadRawFn const load_raw) {
+
+    shrink = cmdline.half_size && filters;
+    iheight = (height + shrink) >> shrink;
+    iwidth  = (width  + shrink) >> shrink;
+    image = calloc (iheight*iwidth*sizeof *image + meta_length, 1);
+    merror (image, "main()");
+    meta_data = (char *) (image + iheight*iwidth);
+    if (cmdline.verbose)
+        pm_message ("Loading %s %s image ...", make, model);
+
+    use_secondary = cmdline.use_secondary;  /* for load_raw() */
+
+    ifp = ifP;  /* Set global variable for (*load_raw)() */
+
+    load_raw();
+    bad_pixels();
+    height = iheight;
+    width  = iwidth;
+    if (is_foveon) {
+        if (cmdline.verbose)
+            pm_message ("Foveon interpolation...");
+        foveon_interpolate(coeff);
+    } else {
+        scale_colors();
+    }
+    if (shrink) filters = 0;
+    trim = 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);
+    if (cmdline.verbose)
+        pm_message ("Converting to RGB colorspace...");
+    convert_to_rgb();
+
+    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();
+    }
+    writePam(ofP, cmdline.linear);
+}
+
+
+int 
+main (int argc, char **argv) {
+
+    FILE * const ofP = stdout;
+
+    FILE * ifP;
+    int rc;
+    loadRawFn load_raw;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    image = NULL;
+    
+    rc = identify(ifP,
+                  cmdline.use_secondary, cmdline.use_camera_rgb,
+                  cmdline.red_scale, cmdline.blue_scale,
+                  cmdline.four_color_rgb, cmdline.inputFileName,
+                  &load_raw);
+    if (rc != 0)
+        pm_error("Unable to identify the format of the input image");
+    else {
+        if (cmdline.identify_only) {
+            pm_message ("Input is a %s %s image.", make, model);
+        } else {
+            if (cmdline.verbose)
+                pm_message ("Input is a %s %s image.", make, model);
+            convertIt(ifP, ofP, load_raw);
+        }
+    }
+    pm_close(ifP);
+    pm_close(ofP);
+    free(image);
+
+    return 0;
+}
+
+
+
diff --git a/converter/other/cameratopam/canon.c b/converter/other/cameratopam/canon.c
new file mode 100644
index 00000000..a34771d0
--- /dev/null
+++ b/converter/other/cameratopam/canon.c
@@ -0,0 +1,172 @@
+#include <string.h>
+#include "mallocvar.h"
+#include "pm.h"
+#include "global_variables.h"
+#include "util.h"
+#include "decode.h"
+#include "bayer.h"
+#include "canon.h"
+
+
+void 
+canon_600_load_raw(void) {
+    unsigned char  data[1120], *dp;
+    unsigned short pixel[896], *pix;
+    int irow, orow, col;
+
+    for (irow=orow=0; irow < height; irow++)
+    {
+        fread (data, 1120, 1, ifp);
+        for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8)
+        {
+            pix[0] = (dp[0] << 2) + (dp[1] >> 6    );
+            pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3);
+            pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3);
+            pix[3] = (dp[4] << 2) + (dp[1]      & 3);
+            pix[4] = (dp[5] << 2) + (dp[9]      & 3);
+            pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3);
+            pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3);
+            pix[7] = (dp[8] << 2) + (dp[9] >> 6    );
+        }
+        for (col=0; col < width; col++)
+            BAYER(orow,col) = pixel[col];
+        for (col=width; col < 896; col++)
+            black += pixel[col];
+        if ((orow+=2) > height)
+            orow = 1;
+    }
+    black /= (896 - width) * height;
+    maximum = 0x3ff;
+}
+
+
+
+void
+canon_a5_load_raw(void) {
+    unsigned char  data[1940], *dp;
+    unsigned short pixel[1552], *pix;
+    int row, col;
+
+    for (row=0; row < height; row++) {
+        fread (data, raw_width * 10 / 8, 1, ifp);
+        for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=10, pix+=8)
+        {
+            pix[0] = (dp[1] << 2) + (dp[0] >> 6);
+            pix[1] = (dp[0] << 4) + (dp[3] >> 4);
+            pix[2] = (dp[3] << 6) + (dp[2] >> 2);
+            pix[3] = (dp[2] << 8) + (dp[5]     );
+            pix[4] = (dp[4] << 2) + (dp[7] >> 6);
+            pix[5] = (dp[7] << 4) + (dp[6] >> 4);
+            pix[6] = (dp[6] << 6) + (dp[9] >> 2);
+            pix[7] = (dp[9] << 8) + (dp[8]     );
+        }
+        for (col=0; col < width; col++)
+            BAYER(row,col) = (pixel[col] & 0x3ff);
+        for (col=width; col < raw_width; col++)
+            black += pixel[col] & 0x3ff;
+    }
+    if (raw_width > width)
+        black /= (raw_width - width) * height;
+    maximum = 0x3ff;
+}
+
+
+
+/*
+   Return 0 if the image starts with compressed data,
+   1 if it starts with uncompressed low-order bits.
+
+   In Canon compressed data, 0xff is always followed by 0x00.
+ */
+static int
+canon_has_lowbits()
+{
+    unsigned char test[0x4000];
+    int ret=1, i;
+
+    fseek (ifp, 0, SEEK_SET);
+    fread (test, 1, sizeof test, ifp);
+    for (i=540; i < sizeof test - 1; i++)
+        if (test[i] == 0xff) {
+            if (test[i+1]) return 1;
+            ret=0;
+        }
+    return ret;
+}
+
+
+
+void 
+canon_compressed_load_raw(void) {
+    unsigned short *pixel, *prow;
+    int lowbits, i, row, r, col, save, val;
+    unsigned irow, icol;
+    struct decode *decode, *dindex;
+    int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2];
+    unsigned char c;
+
+    MALLOCARRAY(pixel, raw_width*8);
+    if (pixel == NULL)
+        pm_error("Unable to allocate space for %u pixels", raw_width*8);
+    lowbits = canon_has_lowbits();
+    if (!lowbits) maximum = 0x3ff;
+    fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET);
+    zero_after_ff = 1;
+    getbits(ifp, -1);
+    for (row = 0; row < raw_height; row += 8) {
+        for (block=0; block < raw_width >> 3; block++) {
+            memset (diffbuf, 0, sizeof diffbuf);
+            decode = first_decode;
+            for (i=0; i < 64; i++ ) {
+                for (dindex=decode; dindex->branch[0]; )
+                    dindex = dindex->branch[getbits(ifp, 1)];
+                leaf = dindex->leaf;
+                decode = second_decode;
+                if (leaf == 0 && i) break;
+                if (leaf == 0xff) continue;
+                i  += leaf >> 4;
+                len = leaf & 15;
+                if (len == 0) continue;
+                diff = getbits(ifp, len);
+                if ((diff & (1 << (len-1))) == 0)
+                    diff -= (1 << len) - 1;
+                if (i < 64) diffbuf[i] = diff;
+            }
+            diffbuf[0] += carry;
+            carry = diffbuf[0];
+            for (i=0; i < 64; i++ ) {
+                if (pnum++ % raw_width == 0)
+                    base[0] = base[1] = 512;
+                pixel[(block << 6) + i] = ( base[i & 1] += diffbuf[i] );
+            }
+        }
+        if (lowbits) {
+            save = ftell(ifp);
+            fseek (ifp, 26 + row*raw_width/4, SEEK_SET);
+            for (prow=pixel, i=0; i < raw_width*2; i++) {
+                c = fgetc(ifp);
+                for (r=0; r < 8; r+=2, prow++) {
+                    val = (*prow << 2) + ((c >> r) & 3);
+                    if (raw_width == 2672 && val < 512) val += 2;
+                    *prow = val;
+                }
+            }
+            fseek (ifp, save, SEEK_SET);
+        }
+        for (r=0; r < 8; r++) {
+            irow = row - top_margin + r;
+            if (irow >= height) continue;
+            for (col = 0; col < raw_width; col++) {
+                icol = col - left_margin;
+                if (icol < width)
+                    BAYER(irow,icol) = pixel[r*raw_width+col];
+                else
+                    black += pixel[r*raw_width+col];
+            }
+        }
+    }
+    free (pixel);
+    if (raw_width > width)
+        black /= (raw_width - width) * height;
+}
+
diff --git a/converter/other/cameratopam/canon.h b/converter/other/cameratopam/canon.h
new file mode 100644
index 00000000..041cdc4d
--- /dev/null
+++ b/converter/other/cameratopam/canon.h
@@ -0,0 +1,13 @@
+#ifndef CANON_H_INCLUDED
+#define CANON_H_INCLUDED
+
+void 
+canon_600_load_raw(void);
+
+void
+canon_a5_load_raw(void);
+
+void 
+canon_compressed_load_raw(void);
+
+#endif
diff --git a/converter/other/cameratopam/decode.c b/converter/other/cameratopam/decode.c
new file mode 100644
index 00000000..e3a62fab
--- /dev/null
+++ b/converter/other/cameratopam/decode.c
@@ -0,0 +1,172 @@
+#include <string.h>
+
+#include "pm_c_util.h"
+#include "pm.h"
+
+#include "decode.h"
+
+struct decode first_decode[2048], *second_decode, *free_decode;
+
+
+
+void init_decoder() {
+  memset (first_decode, 0, sizeof first_decode);
+  free_decode = first_decode;
+}
+
+
+
+/*
+   Construct a decode tree according the specification in *source.
+   The first 16 bytes specify how many codes should be 1-bit, 2-bit
+   3-bit, etc.  Bytes after that are the leaf values.
+
+   For example, if the source is
+
+    { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0,
+      0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff  },
+
+   then the code is
+
+    00      0x04
+    010     0x03
+    011     0x05
+    100     0x06
+    101     0x02
+    1100        0x07
+    1101        0x01
+    11100       0x08
+    11101       0x09
+    11110       0x00
+    111110      0x0a
+    1111110     0x0b
+    1111111     0xff
+ */
+
+
+unsigned char * 
+make_decoder(const unsigned char * const source, 
+             int                   const level) {
+
+    struct decode *cur;
+    static int leaf;
+    int i, next;
+
+    if (level==0) 
+        leaf=0;
+    cur = free_decode++;
+    if (free_decode > first_decode+2048) {
+        pm_error ("decoder table overflow");
+    }
+    for (i=next=0; i <= leaf && next < 16; )
+        i += source[next++];
+    if (i > leaf) {
+        if (level < next) {
+            cur->branch[0] = free_decode;
+            make_decoder (source, level+1);
+            cur->branch[1] = free_decode;
+            make_decoder (source, level+1);
+        } else
+            cur->leaf = source[16 + leaf++];
+    }
+    return (unsigned char *) source + 16 + leaf;
+}
+
+
+
+const int * 
+make_decoder_int(const int * const source,
+                 int         const level) {
+
+    const int * p;
+    struct decode *cur;
+
+    p = source;  /* initial value */
+
+    cur = free_decode++;
+    if (level < p[0]) {
+        cur->branch[0] = free_decode;
+        p = make_decoder_int (p, level+1);
+        cur->branch[1] = free_decode;
+        p = make_decoder_int (p, level+1);
+    } else {
+        cur->leaf = p[1];
+        p += 2;
+    }
+    return p;
+}
+
+
+
+void 
+crw_init_tables(unsigned int const table) {
+
+  unsigned int const clippedTableNum = MIN(2, table);
+
+  static const unsigned char first_tree[3][29] = {
+    { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0,
+      0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff  },
+
+    { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0,
+      0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff  },
+
+    { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0,
+      0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff  },
+  };
+
+  static const unsigned char second_tree[3][180] = {
+    { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139,
+      0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08,
+      0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0,
+      0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42,
+      0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57,
+      0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9,
+      0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98,
+      0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6,
+      0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4,
+      0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7,
+      0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1,
+      0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64,
+      0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba,
+      0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4,
+      0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff  },
+
+    { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140,
+      0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06,
+      0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32,
+      0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51,
+      0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26,
+      0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59,
+      0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9,
+      0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99,
+      0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85,
+      0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8,
+      0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a,
+      0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9,
+      0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8,
+      0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8,
+      0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff  },
+
+    { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117,
+      0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08,
+      0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22,
+      0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34,
+      0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41,
+      0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48,
+      0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69,
+      0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8,
+      0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94,
+      0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a,
+      0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6,
+      0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62,
+      0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5,
+      0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3,
+      0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff  }
+  };
+
+  init_decoder();
+  make_decoder ( first_tree[clippedTableNum], 0);
+  second_decode = free_decode;
+  make_decoder (second_tree[clippedTableNum], 0);
+}
+
diff --git a/converter/other/cameratopam/decode.h b/converter/other/cameratopam/decode.h
new file mode 100644
index 00000000..b0addc82
--- /dev/null
+++ b/converter/other/cameratopam/decode.h
@@ -0,0 +1,22 @@
+struct decode {
+  struct decode *branch[2];
+  int leaf;
+}; 
+
+extern struct decode * free_decode;
+extern struct decode first_decode[2048];
+extern struct decode * second_decode;
+
+void 
+init_decoder(void);
+
+void 
+crw_init_tables(unsigned int const table);
+
+const int * 
+make_decoder_int (const int * const source, 
+                  int         const level);
+
+unsigned char * 
+make_decoder(const unsigned char * const source, 
+             int                   const level);
diff --git a/converter/other/cameratopam/dng.c b/converter/other/cameratopam/dng.c
new file mode 100644
index 00000000..44d45b02
--- /dev/null
+++ b/converter/other/cameratopam/dng.c
@@ -0,0 +1,73 @@
+#include <string.h>
+#include "global_variables.h"
+
+#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 } };
+#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 } };
+#endif
+  double cam_xyz[4][3], xyz_cam[3][4], invert[3][6], num;
+  int i, j, k;
+
+  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++) {
+    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;
+    }
+  }
+  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];
+
+  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 (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;
+}
+
diff --git a/converter/other/cameratopam/dng.h b/converter/other/cameratopam/dng.h
new file mode 100644
index 00000000..01e7e0a5
--- /dev/null
+++ b/converter/other/cameratopam/dng.h
@@ -0,0 +1,2 @@
+void 
+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
new file mode 100644
index 00000000..0198940c
--- /dev/null
+++ b/converter/other/cameratopam/foveon.c
@@ -0,0 +1,790 @@
+/* This code is licensed to the public by its copyright owners under GPL. */
+
+#define _XOPEN_SOURCE   /* get M_PI */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <float.h>
+#include <math.h>
+
+#include "mallocvar.h"
+#include "pm.h"
+#include "global_variables.h"
+#include "decode.h"
+#include "foveon.h"
+
+#if HAVE_INT64
+   typedef int64_t INT64;
+   static bool const have64BitArithmetic = true;
+#else
+   /* We define INT64 to something that lets the code compile, but we
+      should not execute any INT64 code, because it will get the wrong
+      result.
+   */
+   typedef int INT64;
+   static bool const have64BitArithmetic = false;
+#endif
+
+
+#define FORC3 for (c=0; c < 3; c++)
+#define FORC4 for (c=0; c < colors; c++)
+
+
+
+static char *  
+foveon_gets(int    const offset, 
+            char * const str, 
+            int    const len) {
+
+    unsigned int i;
+    fseek (ifp, offset, SEEK_SET);
+    for (i=0; i < len-1; ++i) {
+        /* It certains seems wrong that we're reading a 16 bit integer
+           and assigning it to char, but that's what Dcraw does.
+        */
+        unsigned short val;
+        pm_readlittleshortu(ifp, &val);
+        str[i] = val;
+        if (str[i] == 0)
+            break;
+    }
+    str[i] = 0;
+    return str;
+}
+
+
+
+void 
+parse_foveon(FILE * const ifp) {
+    long fliplong;
+    long pos;
+    long magic;
+    long junk;
+    long entries;
+
+    fseek (ifp, 36, SEEK_SET);
+    pm_readlittlelong(ifp, &fliplong);
+    flip = fliplong;
+    fseek (ifp, -4, SEEK_END);
+    pm_readlittlelong(ifp, &pos);
+    fseek (ifp, pos, SEEK_SET);
+    pm_readlittlelong(ifp, &magic);
+    if (magic != 0x64434553) 
+        return; /* SECd */
+    pm_readlittlelong(ifp, &junk);
+    pm_readlittlelong(ifp, &entries);
+    while (entries--) {
+        long off, len, tag;
+        long save;
+        long pent;
+        int i, poff[256][2];
+        char name[64];
+        long sec_;
+
+        pm_readlittlelong(ifp, &off);
+        pm_readlittlelong(ifp, &len);
+        pm_readlittlelong(ifp, &tag);
+            
+        save = ftell(ifp);
+        fseek (ifp, off, SEEK_SET);
+        pm_readlittlelong(ifp, &sec_);
+        if (sec_ != (0x20434553 | (tag << 24))) return;
+        switch (tag) {
+        case 0x47414d49:          /* IMAG */
+            if (data_offset) 
+                break;
+            data_offset = off + 28;
+            fseek (ifp, 12, SEEK_CUR);
+            {
+                long wlong, hlong;
+                pm_readlittlelong(ifp, &wlong);
+                pm_readlittlelong(ifp, &hlong);
+                raw_width  = wlong;
+                raw_height = hlong;
+            }
+            break;
+        case 0x464d4143:          /* CAMF */
+            meta_offset = off + 24;
+            meta_length = len - 28;
+            if (meta_length > 0x20000)
+                meta_length = 0x20000;
+            break;
+        case 0x504f5250:          /* PROP */
+            pm_readlittlelong(ifp, &junk);
+            pm_readlittlelong(ifp, &pent);
+            fseek (ifp, 12, SEEK_CUR);
+            off += pent*8 + 24;
+            if (pent > 256) pent=256;
+            for (i=0; i < pent*2; i++) {
+                long x;
+                pm_readlittlelong(ifp, &x);
+                poff[0][i] = off + x*2;
+            }
+            for (i=0; i < pent; i++) {
+                foveon_gets (poff[i][0], name, 64);
+                if (!strcmp (name, "CAMMANUF"))
+                    foveon_gets (poff[i][1], make, 64);
+                if (!strcmp (name, "CAMMODEL"))
+                    foveon_gets (poff[i][1], model, 64);
+                if (!strcmp (name, "WB_DESC"))
+                    foveon_gets (poff[i][1], model2, 64);
+                if (!strcmp (name, "TIME"))
+                    timestamp = atoi (foveon_gets (poff[i][1], name, 64));
+            }
+        }
+        fseek (ifp, save, SEEK_SET);
+    }
+    is_foveon = 1;
+}
+
+
+
+void  
+foveon_coeff(bool * const useCoeffP,
+             float        coeff[3][4]) {
+
+    static const float foveon[3][3] =
+    { {  1.4032, -0.2231, -0.1016 },
+      { -0.5263,  1.4816,  0.0170 },
+      { -0.0112,  0.0183,  0.9113 } };
+
+    int i, j;
+
+    for (i=0; i < 3; ++i)
+        for (j=0; j < 3; ++j)
+            coeff[i][j] = foveon[i][j];
+    *useCoeffP = 1;
+}
+
+
+
+static void  
+foveon_decoder (unsigned int const huff[1024], 
+                unsigned int const code) {
+
+    struct decode *cur;
+    int len;
+    unsigned int code2;
+
+    cur = free_decode++;
+    if (free_decode > first_decode+2048) {
+        pm_error ("decoder table overflow");
+    }
+    if (code) {
+        unsigned int i;
+        for (i=0; i < 1024; i++) {
+            if (huff[i] == code) {
+                cur->leaf = i;
+                return;
+            }
+        }
+    }
+    if ((len = code >> 27) > 26) 
+        return;
+    code2 = (len+1) << 27 | (code & 0x3ffffff) << 1;
+
+    cur->branch[0] = free_decode;
+    foveon_decoder (huff, code2);
+    cur->branch[1] = free_decode;
+    foveon_decoder (huff, code2+1);
+}
+
+
+
+static void  
+foveon_load_camf() {
+    unsigned int i, val;
+    long key;
+
+    fseek (ifp, meta_offset, SEEK_SET);
+    pm_readlittlelong(ifp, &key);
+    fread (meta_data, 1, meta_length, ifp);
+    for (i=0; i < meta_length; i++) {
+        key = (key * 1597 + 51749) % 244944;
+        assert(have64BitArithmetic);
+        val = key * (INT64) 301593171 >> 24;
+        meta_data[i] ^= ((((key << 8) - val) >> 1) + val) >> 17;
+    }
+}
+
+
+
+void  
+foveon_load_raw() {
+
+    struct decode *dindex;
+    short diff[1024], pred[3];
+    unsigned int huff[1024], bitbuf=0;
+    int row, col, bit=-1, c, i;
+
+    assert(have64BitArithmetic);
+
+    for (i=0; i < 1024; ++i)
+        pm_readlittleshort(ifp, &diff[i]);
+
+    for (i=0; i < 1024; ++i) {
+        long x;
+        pm_readlittlelong(ifp, &x);
+        huff[i] = x;
+    }
+    init_decoder();
+    foveon_decoder (huff, 0);
+
+    for (row=0; row < height; row++) {
+        long junk;
+        memset (pred, 0, sizeof pred);
+        if (!bit) 
+            pm_readlittlelong(ifp, &junk);
+        for (col=bit=0; col < width; col++) {
+            FORC3 {
+                for (dindex=first_decode; dindex->branch[0]; ) {
+                    if ((bit = (bit-1) & 31) == 31)
+                        for (i=0; i < 4; i++)
+                            bitbuf = (bitbuf << 8) + fgetc(ifp);
+                    dindex = dindex->branch[bitbuf >> bit & 1];
+                }
+                pred[c] += diff[dindex->leaf];
+            }
+            FORC3 image[row*width+col][c] = pred[c];
+        }
+    }
+    foveon_load_camf();
+    maximum = clip_max = 0xffff;
+}
+
+
+
+static int
+sget4(char const s[]) {
+    return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+}
+
+
+
+static char *  
+foveon_camf_param (const char * const block, 
+                   const char * const param) {
+    unsigned idx, num;
+    char *pos, *cp, *dp;
+
+    for (idx=0; idx < meta_length; idx += sget4(pos+8)) {
+        pos = meta_data + idx;
+        if (strncmp (pos, "CMb", 3)) break;
+        if (pos[3] != 'P') continue;
+        if (strcmp (block, pos+sget4(pos+12))) continue;
+        cp = pos + sget4(pos+16);
+        num = sget4(cp);
+        dp = pos + sget4(cp+4);
+        while (num--) {
+            cp += 8;
+            if (!strcmp (param, dp+sget4(cp)))
+                return dp+sget4(cp+4);
+        }
+    }
+    return NULL;
+}
+
+
+
+static void *  
+foveon_camf_matrix (int                dim[3], 
+                    const char * const name) {
+
+    unsigned i, idx, type, ndim, size, *mat;
+    char *pos, *cp, *dp;
+
+    for (idx=0; idx < meta_length; idx += sget4(pos+8)) {
+        pos = meta_data + idx;
+        if (strncmp (pos, "CMb", 3)) break;
+        if (pos[3] != 'M') continue;
+        if (strcmp (name, pos+sget4(pos+12))) continue;
+        dim[0] = dim[1] = dim[2] = 1;
+        cp = pos + sget4(pos+16);
+        type = sget4(cp);
+        if ((ndim = sget4(cp+4)) > 3) break;
+        dp = pos + sget4(cp+8);
+        for (i=ndim; i--; ) {
+            cp += 12;
+            dim[i] = sget4(cp);
+        }
+        if ((size = dim[0]*dim[1]*dim[2]) > meta_length/4) break;
+        MALLOCARRAY(mat, size);
+        if (mat == NULL)
+            pm_error("Unable to allocate memory for size=%d", size);
+        for (i=0; i < size; i++)
+            if (type && type != 6)
+                mat[i] = sget4(dp + i*4);
+            else
+                mat[i] = sget4(dp + i*2) & 0xffff;
+        return mat;
+    }
+    pm_message ("'%s' matrix not found!", name);
+    return NULL;
+}
+
+
+
+static int  
+foveon_fixed (void *       const ptr, 
+              int          const size, 
+              const char * const name) {
+    void *dp;
+    int dim[3];
+
+    dp = foveon_camf_matrix (dim, name);
+    if (!dp) return 0;
+    memcpy (ptr, dp, size*4);
+    free (dp);
+    return 1;
+}
+
+static float  foveon_avg (unsigned short *pix, int range[2], float cfilt)
+{
+    int i;
+    float val, min=FLT_MAX, max=-FLT_MAX, sum=0;
+
+    for (i=range[0]; i <= range[1]; i++) {
+        sum += val = 
+            (short)pix[i*4] + ((short)pix[i*4]-(short)pix[(i-1)*4]) * cfilt;
+        if (min > val) min = val;
+        if (max < val) max = val;
+    }
+    return (sum - min - max) / (range[1] - range[0] - 1);
+}
+
+static short *foveon_make_curve (double max, double mul, double filt)
+{
+    short *curve;
+    int size;
+    unsigned int i;
+    double x;
+
+    size = 4*M_PI*max / filt;
+    MALLOCARRAY(curve, size+1);
+    if (curve == NULL)
+        pm_error("Out of memory for %d-element curve array", size);
+
+    curve[0] = size;
+    for (i=0; i < size; ++i) {
+        x = i*filt/max/4;
+        curve[i+1] = (cos(x)+1)/2 * tanh(i*filt/mul) * mul + 0.5;
+    }
+    return curve;
+}
+
+static void foveon_make_curves
+(short **curvep, float dq[3], float div[3], float filt)
+{
+    double mul[3], max=0;
+    int c;
+
+    FORC3 mul[c] = dq[c]/div[c];
+    FORC3 if (max < mul[c]) max = mul[c];
+    FORC3 curvep[c] = foveon_make_curve (max, mul[c], filt);
+}
+
+static int  foveon_apply_curve (short *curve, int i)
+{
+    if (abs(i) >= (unsigned short)curve[0]) return 0;
+    return i < 0 ? -(unsigned short)curve[1-i] : (unsigned short)curve[1+i];
+}
+
+void  
+foveon_interpolate(float coeff[3][4]) {
+
+    static const short hood[] = { 
+        -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 };
+    short *pix, prev[3], *curve[8], (*shrink)[3];
+    float cfilt=0.8, ddft[3][3][2], ppm[3][3][3];
+    float cam_xyz[3][3], correct[3][3], last[3][3], trans[3][3];
+    float chroma_dq[3], color_dq[3], diag[3][3], div[3];
+    float (*black)[3], (*sgain)[3], (*sgrow)[3];
+    float fsum[3], val, frow, num;
+    int row, col, c, i, j, diff, sgx, irow, sum, min, max, limit;
+    int dim[3], dscr[2][2], (*smrow[7])[3], total[4], ipix[3];
+    int work[3][3], smlast, smred, smred_p=0, dev[3];
+    int satlev[3], keep[4], active[4];
+    unsigned *badpix;
+    double dsum=0, trsum[3];
+    char str[128], *cp;
+
+    foveon_fixed (dscr, 4, "DarkShieldColRange");
+    foveon_fixed (ppm[0][0], 27, "PostPolyMatrix");
+    foveon_fixed (ddft[1][0], 12, "DarkDrift");
+    foveon_fixed (&cfilt, 1, "ColumnFilter");
+    foveon_fixed (satlev, 3, "SaturationLevel");
+    foveon_fixed (keep, 4, "KeepImageArea");
+    foveon_fixed (active, 4, "ActiveImageArea");
+    foveon_fixed (chroma_dq, 3, "ChromaDQ");
+    foveon_fixed (color_dq, 3,
+                  foveon_camf_param ("IncludeBlocks", "ColorDQ") ?
+                  "ColorDQ" : "ColorDQCamRGB");
+
+    if (!(cp = foveon_camf_param ("WhiteBalanceIlluminants", model2)))
+    { pm_message ( "Invalid white balance \"%s\"", model2);
+    return; }
+    foveon_fixed (cam_xyz, 9, cp);
+    foveon_fixed (correct, 9,
+                  foveon_camf_param ("WhiteBalanceCorrections", model2));
+    memset (last, 0, sizeof last);
+    for (i=0; i < 3; i++)
+        for (j=0; j < 3; j++)
+            FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j];
+
+    sprintf (str, "%sRGBNeutral", model2);
+    if (foveon_camf_param ("IncludeBlocks", str))
+        foveon_fixed (div, 3, str);
+    else {
+#define LAST(x,y) last[(i+x)%3][(c+y)%3]
+        for (i=0; i < 3; i++)
+            FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1);
+#undef LAST
+        FORC3 div[c] = 
+            diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583;
+    }
+    num = 0;
+    FORC3 if (num < div[c]) num = div[c];
+    FORC3 div[c] /= num;
+
+    memset (trans, 0, sizeof trans);
+    for (i=0; i < 3; i++)
+        for (j=0; j < 3; j++)
+            FORC3 trans[i][j] += coeff[i][c] * last[c][j] * div[j];
+    FORC3 trsum[c] = trans[c][0] + trans[c][1] + trans[c][2];
+    dsum = (6*trsum[0] + 11*trsum[1] + 3*trsum[2]) / 20;
+    for (i=0; i < 3; i++)
+        FORC3 last[i][c] = trans[i][c] * dsum / trsum[i];
+    memset (trans, 0, sizeof trans);
+    for (i=0; i < 3; i++)
+        for (j=0; j < 3; j++)
+            FORC3 trans[i][j] += (i==c ? 32 : -1) * last[c][j] / 30;
+
+    foveon_make_curves (curve, color_dq, div, cfilt);
+    FORC3 chroma_dq[c] /= 3;
+    foveon_make_curves (curve+3, chroma_dq, div, cfilt);
+    FORC3 dsum += chroma_dq[c] / div[c];
+    curve[6] = foveon_make_curve (dsum, dsum, cfilt);
+    curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt);
+
+    sgain = foveon_camf_matrix (dim, "SpatialGain");
+    if (!sgain) return;
+    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]);
+        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 (last, black, sizeof last);
+
+    for (row=1; row < height-1; row++) {
+        FORC3 if (last[1][c] > last[0][c]) {
+            if (last[1][c] > last[2][c])
+                black[row][c] = 
+                    (last[0][c] > last[2][c]) ? last[0][c]:last[2][c];
+        } else
+            if (last[1][c] < last[2][c])
+                black[row][c] = 
+                    (last[0][c] < last[2][c]) ? last[0][c]:last[2][c];
+        memmove (last, last+1, 2*sizeof last[0]);
+        memcpy (last[2], black[row+1], sizeof last[2]);
+    }
+    FORC3 black[row][c] = (last[0][c] + last[1][c])/2;
+    FORC3 black[0][c] = (black[1][c] + black[3][c])/2;
+
+    val = 1 - exp(-1/24.0);
+    memcpy (fsum, black, sizeof fsum);
+    for (row=1; row < height; row++)
+        FORC3 fsum[c] += black[row][c] =
+            (black[row][c] - black[row-1][c])*val + black[row-1][c];
+    memcpy (last[0], black[height-1], sizeof last[0]);
+    FORC3 fsum[c] /= height;
+    for (row = height; row--; )
+        FORC3 last[0][c] = black[row][c] =
+            (black[row][c] - fsum[c] - last[0][c])*val + last[0][c];
+
+    memset (total, 0, sizeof total);
+    for (row=2; row < height; row+=4)
+        for (col=2; col < width; col+=4) {
+            FORC3 total[c] += (short) image[row*width+col][c];
+            total[3]++;
+        }
+    for (row=0; row < height; row++)
+        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]);
+        pix = (short*)image[row*width];
+        memcpy (prev, pix, sizeof prev);
+        frow = row / (height-1.0) * (dim[2]-1);
+        if ((irow = frow) == dim[2]-1) irow--;
+        frow -= irow;
+        for (i=0; i < dim[1]; i++)
+            FORC3 sgrow[i][c] = sgain[ irow   *dim[1]+i][c] * (1-frow) +
+                sgain[(irow+1)*dim[1]+i][c] *    frow;
+        for (col=0; col < width; col++) {
+            FORC3 {
+                diff = pix[c] - prev[c];
+                prev[c] = pix[c];
+                ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt
+                                          - ddft[0][c][1] 
+                                          - ddft[0][c][0] 
+                                            * ((float) col/width - 0.5)
+                                          - black[row][c] );
+            }
+            FORC3 {
+                work[0][c] = ipix[c] * ipix[c] >> 14;
+                work[2][c] = ipix[c] * work[0][c] >> 14;
+                work[1][2-c] = ipix[(c+1) % 3] * ipix[(c+2) % 3] >> 14;
+            }
+            FORC3 {
+                for (val=i=0; i < 3; i++)
+                    for (  j=0; j < 3; j++)
+                        val += ppm[c][i][j] * work[i][j];
+                ipix[c] = floor ((ipix[c] + floor(val)) *
+                                 ( sgrow[col/sgx  ][c] * (sgx - col%sgx) +
+                                   sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / 
+                                 div[c]);
+                if (ipix[c] > 32000) ipix[c] = 32000;
+                pix[c] = ipix[c];
+            }
+            pix += 4;
+        }
+    }
+    free (black);
+    free (sgrow);
+    free (sgain);
+
+    if ((badpix = foveon_camf_matrix (dim, "BadPixels"))) {
+        for (i=0; i < dim[0]; i++) {
+            col = (badpix[i] >> 8 & 0xfff) - keep[0];
+            row = (badpix[i] >> 20       ) - keep[1];
+            if ((unsigned)(row-1) > height-3 || (unsigned)(col-1) > width-3)
+                continue;
+            memset (fsum, 0, sizeof fsum);
+            for (sum=j=0; j < 8; j++)
+                if (badpix[i] & (1 << j)) {
+                    FORC3 fsum[c] += 
+                        image[(row+hood[j*2])*width+col+hood[j*2+1]][c];
+                    sum++;
+                }
+            if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum;
+        }
+        free (badpix);
+    }
+
+    /* Array for 5x5 Gaussian averaging of red values */
+    smrow[6] = calloc (width*5, sizeof **smrow);
+    if (smrow[6] == NULL)
+        pm_error("Out of memory");
+    for (i=0; i < 5; i++)
+        smrow[i] = smrow[6] + i*width;
+
+    /* Sharpen the reds against these Gaussian averages */
+    for (smlast=-1, row=2; row < height-2; row++) {
+        while (smlast < row+2) {
+            for (i=0; i < 6; i++)
+                smrow[(i+5) % 6] = smrow[i];
+            pix = (short*)image[++smlast*width+2];
+            for (col=2; col < width-2; col++) {
+                smrow[4][col][0] =
+                    (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4;
+                pix += 4;
+            }
+        }
+        pix = (short*)image[row*width+2];
+        for (col=2; col < width-2; col++) {
+            smred = ( 6 *  smrow[2][col][0]
+                      + 4 * (smrow[1][col][0] + smrow[3][col][0])
+                      +      smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4;
+            if (col == 2)
+                smred_p = smred;
+            i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3);
+            if (i > 32000) i = 32000;
+            pix[0] = i;
+            smred_p = smred;
+            pix += 4;
+        }
+    }
+
+    /* Adjust the brighter pixels for better linearity */
+    FORC3 {
+        i = satlev[c] / div[c];
+        if (maximum > i) maximum = i;
+    }
+    clip_max = maximum;
+    limit = maximum * 9 >> 4;
+    for (pix=(short*)image[0]; pix < (short *) image[height*width]; pix+=4) {
+        if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit)
+            continue;
+        min = max = pix[0];
+        for (c=1; c < 3; c++) {
+            if (min > pix[c]) min = pix[c];
+            if (max < pix[c]) max = pix[c];
+        }
+        i = 0x4000 - ((min - limit) << 14) / limit;
+        i = 0x4000 - (i*i >> 14);
+        i = i*i >> 14;
+        FORC3 pix[c] += (max - pix[c]) * i >> 14;
+    }
+    /*
+      Because photons that miss one detector often hit another,
+      the sum R+G+B is much less noisy than the individual colors.
+      So smooth the hues without smoothing the total.
+    */
+    for (smlast=-1, row=2; row < height-2; row++) {
+        while (smlast < row+2) {
+            for (i=0; i < 6; i++)
+                smrow[(i+5) % 6] = smrow[i];
+            pix = (short*)image[++smlast*width+2];
+            for (col=2; col < width-2; col++) {
+                FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2;
+                pix += 4;
+            }
+        }
+        pix = (short*)image[row*width+2];
+        for (col=2; col < width-2; col++) {
+            FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] -
+                                                ((smrow[1][col][c] + 
+                                                  2*smrow[2][col][c] + 
+                                                  smrow[3][col][c]) >> 2));
+            sum = (dev[0] + dev[1] + dev[2]) >> 3;
+            FORC3 pix[c] += dev[c] - sum;
+            pix += 4;
+        }
+    }
+    for (smlast=-1, row=2; row < height-2; row++) {
+        while (smlast < row+2) {
+            for (i=0; i < 6; i++)
+                smrow[(i+5) % 6] = smrow[i];
+            pix = (short*)image[++smlast*width+2];
+            for (col=2; col < width-2; col++) {
+                FORC3 smrow[4][col][c] =
+                    (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2;
+                pix += 4;
+            }
+        }
+        pix = (short*)image[row*width+2];
+        for (col=2; col < width-2; col++) {
+            for (total[3]=375, sum=60, c=0; c < 3; c++) {
+                for (total[c]=i=0; i < 5; i++)
+                    total[c] += smrow[i][col][c];
+                total[3] += total[c];
+                sum += pix[c];
+            }
+            if (sum < 0) sum = 0;
+            j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174;
+            FORC3 pix[c] += foveon_apply_curve (curve[6],
+                                                ((j*total[c] + 0x8000) >> 16) 
+                                                - pix[c]);
+            pix += 4;
+        }
+    }
+
+    /* Transform the image to a different colorspace */
+    for (pix=(short*)image[0]; pix < (short *) image[height*width]; pix+=4) {
+        FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]);
+        sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2;
+        FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum);
+        FORC3 {
+            for (dsum=i=0; i < 3; i++)
+                dsum += trans[c][i] * pix[i];
+            if (dsum < 0)  dsum = 0;
+            if (dsum > 24000) dsum = 24000;
+            ipix[c] = dsum + 0.5;
+        }
+        FORC3 pix[c] = ipix[c];
+    }
+
+    /* Smooth the image bottom-to-top and save at 1/4 scale */
+    MALLOCARRAY(shrink, (width/4) * (height/4));
+    if (shrink == NULL)
+        pm_error("Out of memory allocating 1/4 scale array");
+
+    for (row = height/4; row > 0; --row) {
+        for (col=0; col < width/4; ++col) {
+            ipix[0] = ipix[1] = ipix[2] = 0;
+            for (i=0; i < 4; i++)
+                for (j=0; j < 4; j++)
+                    FORC3 ipix[c] += image[(row*4+i)*width+col*4+j][c];
+            FORC3
+                if (row+2 > height/4)
+                    shrink[row*(width/4)+col][c] = ipix[c] >> 4;
+                else
+                    shrink[row*(width/4)+col][c] =
+                        (shrink[(row+1)*(width/4)+col][c]*1840 + 
+                         ipix[c]*141 + 2048) >> 12;
+        }
+    }
+    /* From the 1/4-scale image, smooth right-to-left */
+    for (row=0; row < (height & ~3); ++row) {
+        ipix[0] = ipix[1] = ipix[2] = 0;
+        if ((row & 3) == 0)
+            for (col = width & ~3 ; col--; )
+                FORC3 smrow[0][col][c] = ipix[c] =
+                    (shrink[(row/4)*(width/4)+col/4][c]*1485 + 
+                     ipix[c]*6707 + 4096) >> 13;
+
+        /* Then smooth left-to-right */
+        ipix[0] = ipix[1] = ipix[2] = 0;
+        for (col=0; col < (width & ~3); col++)
+            FORC3 smrow[1][col][c] = ipix[c] =
+                (smrow[0][col][c]*1485 + ipix[c]*6707 + 4096) >> 13;
+
+        /* Smooth top-to-bottom */
+        if (row == 0)
+            memcpy (smrow[2], smrow[1], sizeof **smrow * width);
+        else
+            for (col=0; col < (width & ~3); col++)
+                FORC3 smrow[2][col][c] =
+                    (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) 
+                        >> 13;
+
+        /* Adjust the chroma toward the smooth values */
+        for (col=0; col < (width & ~3); col++) {
+            for (i=j=30, c=0; c < 3; c++) {
+                i += smrow[2][col][c];
+                j += image[row*width+col][c];
+            }
+            j = (j << 16) / i;
+            for (sum=c=0; c < 3; c++) {
+                ipix[c] = foveon_apply_curve(
+                    curve[c+3],
+                    ((smrow[2][col][c] * j + 0x8000) >> 16) - 
+                    image[row*width+col][c]);
+                sum += ipix[c];
+            }
+            sum >>= 3;
+            FORC3 {
+                i = image[row*width+col][c] + ipix[c] - sum;
+                if (i < 0) i = 0;
+                image[row*width+col][c] = i;
+            }
+        }
+    }
+    free (shrink);
+    free (smrow[6]);
+    for (i=0; i < 8; i++)
+        free (curve[i]);
+
+    /* Trim off the black border */
+    active[1] -= keep[1];
+    active[3] -= 2;
+    i = active[2] - active[0];
+    for (row = 0; row < active[3]-active[1]; row++)
+        memcpy (image[row*i], image[(row+active[1])*width+active[0]],
+                i * sizeof *image);
+    width = i;
+    height = row;
+}
diff --git a/converter/other/cameratopam/foveon.h b/converter/other/cameratopam/foveon.h
new file mode 100644
index 00000000..57be2244
--- /dev/null
+++ b/converter/other/cameratopam/foveon.h
@@ -0,0 +1,14 @@
+#include "pm.h"
+
+void 
+parse_foveon(FILE * const ifp);
+
+void  
+foveon_interpolate(float coeff[3][4]);
+
+void 
+foveon_load_raw(void);
+
+void  
+foveon_coeff(bool * const useCoeffP,
+             float        coeff[3][4]);
diff --git a/converter/other/cameratopam/global_variables.h b/converter/other/cameratopam/global_variables.h
new file mode 100644
index 00000000..c8732d5a
--- /dev/null
+++ b/converter/other/cameratopam/global_variables.h
@@ -0,0 +1,55 @@
+/* These are unfortunately global variables used by various modules.
+
+   It would be nice to clean up this code and get rid of all of these.
+*/
+#include <stdio.h>
+#include <time.h>
+#include "pm_c_util.h"
+
+extern FILE * ifp;
+extern int flip;
+extern int data_offset;
+extern int raw_width;
+extern int raw_height;
+extern int height;
+extern int width;
+extern char * meta_data;
+extern int meta_offset;
+extern int meta_length;
+extern char make[64];
+extern char model[70];
+extern char model2[64];
+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;
+extern int zero_after_ff;
+extern int shrink;
+extern int iwidth;
+extern unsigned int filters;
+extern int black;
+extern unsigned short white[8][8];
+extern int top_margin;
+extern int left_margin;
+extern int fuji_width;
+extern int tiff_samples;
+extern int tiff_data_compression;
+extern int kodak_data_compression;
+extern int fuji_secondary;
+extern int use_coeff;
+extern int use_gamma;
+extern int xmag;
+extern int ymag;
+extern float cam_mul[4];
+#define camera_red  cam_mul[0]
+#define camera_blue cam_mul[2]
+extern float pre_mul[4];
+extern int colors;
+extern unsigned short curve[0x1000];
+extern float coeff[3][4];
+extern int use_secondary;
+extern bool verbose;
diff --git a/converter/other/cameratopam/identify.c b/converter/other/cameratopam/identify.c
new file mode 100644
index 00000000..a101c8ad
--- /dev/null
+++ b/converter/other/cameratopam/identify.c
@@ -0,0 +1,1183 @@
+#define _BSD_SOURCE   /* Make sure strcasecmp() is in string.h */
+#include <string.h>
+
+#include "pm.h"
+
+#include "global_variables.h"
+#include "util.h"
+#include "foveon.h"
+#include "canon.h"
+#include "dng.h"
+#include "ljpeg.h"
+#include "camera.h"
+
+#include "identify.h"
+
+
+#if HAVE_INT64
+   static bool const have64BitArithmetic = true;
+#else
+   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 *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;
+
+  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;
+    }
+}
+
+/*
+   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,
+         bool         const use_camera_rgb,
+         float        const red_scale,
+         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. */
+
+  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
+
+  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);
+
+  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 (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;
+  }
+
+/*  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;
+
+/* 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 (!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;
+    }
+  }
+  if (!use_coeff) adobe_coeff();
+dng_skip:
+  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 (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;
+  }
+  fseek (ifp, data_offset, SEEK_SET);
+
+  *loadRawFnP = load_raw;
+
+  return 0;
+}
diff --git a/converter/other/cameratopam/identify.h b/converter/other/cameratopam/identify.h
new file mode 100644
index 00000000..012b807c
--- /dev/null
+++ b/converter/other/cameratopam/identify.h
@@ -0,0 +1,11 @@
+typedef void (*loadRawFn)();
+
+int
+identify(FILE *       const ifp,
+         bool         const use_secondary,
+         bool         const use_camera_rgb,
+         float        const red_scale,
+         float        const blue_scale,
+         unsigned int const four_color_rgb,
+         const char * const inputFileName,
+         loadRawFn *  const loadRawFnP);
diff --git a/converter/other/cameratopam/ljpeg.c b/converter/other/cameratopam/ljpeg.c
new file mode 100644
index 00000000..18423f4f
--- /dev/null
+++ b/converter/other/cameratopam/ljpeg.c
@@ -0,0 +1,141 @@
+#define _BSD_SOURCE    /* Make sure string.h containst strcasecmp() */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include "pm.h"
+
+#include "global_variables.h"
+#include "util.h"
+#include "decode.h"
+#include "bayer.h"
+
+#include "ljpeg.h"
+
+
+/*
+   Not a full implementation of Lossless JPEG, just
+   enough to decode Canon, Kodak and Adobe DNG images.
+ */
+
+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]) - 2;
+    if (tag <= 0xff00 || len > 255) return 0;
+    fread (data, 1, len, 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+len && *dp < 4; ) {
+      jh->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;
+}
+
+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;
+}
+
+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++;
+    }
+}
+
+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;
+    }
+  }
+  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
new file mode 100644
index 00000000..60832a3d
--- /dev/null
+++ b/converter/other/cameratopam/ljpeg.h
@@ -0,0 +1,17 @@
+struct jhead {
+  int bits, high, wide, clrs, vpred[4];
+  struct decode *huff[4];
+  unsigned short *row;
+};
+
+void  
+lossless_jpeg_load_raw(void);
+
+int  
+ljpeg_start (FILE * ifp, struct jhead *jh);
+
+int 
+ljpeg_diff (struct decode *dindex);
+
+void
+ljpeg_row (struct jhead *jh);
diff --git a/converter/other/cameratopam/util.c b/converter/other/cameratopam/util.c
new file mode 100644
index 00000000..b3ccf7e9
--- /dev/null
+++ b/converter/other/cameratopam/util.c
@@ -0,0 +1,83 @@
+#define _XOPEN_SOURCE   /* Make sure unistd.h contains swab() */
+#include <unistd.h>
+#include <stdio.h>
+
+#include "pm.h"
+#include "global_variables.h"
+#include "util.h"
+
+#ifndef LONG_BITS
+#define LONG_BITS (8 * sizeof(long))
+#endif
+/*
+   Get a 2-byte integer, making no assumptions about CPU byte order.
+   Nor should we assume that the compiler evaluates left-to-right.
+ */
+unsigned short
+get2(FILE * const ifp)
+{
+    unsigned char a, b;
+
+    a = fgetc(ifp);  b = fgetc(ifp);
+
+    if (order == 0x4949)      /* "II" means little-endian */
+        return a | b << 8;
+    else              /* "MM" means big-endian */
+        return a << 8 | b;
+}
+
+/*
+   Same for a 4-byte integer.
+ */
+int
+get4(FILE * const ifp)
+{
+    unsigned char a, b, c, d;
+
+    a = fgetc(ifp);  b = fgetc(ifp);
+    c = fgetc(ifp);  d = fgetc(ifp);
+
+    if (order == 0x4949)
+        return a | b << 8 | c << 16 | d << 24;
+    else
+        return a << 24 | b << 16 | c << 8 | d;
+}
+
+/*
+   Faster than calling get2() multiple times.
+ */
+void
+read_shorts (FILE * const ifp, unsigned short *pixel, int count)
+{
+    fread (pixel, 2, count, ifp);
+    if ((order == 0x4949) == (BYTE_ORDER == BIG_ENDIAN))
+        swab (pixel, pixel, count*2);
+}
+
+/*
+   getbits(-1) initializes the buffer
+   getbits(n) where 0 <= n <= 25 returns an n-bit integer
+ */
+unsigned 
+getbits (FILE * const ifp, int nbits)
+{
+    static unsigned long bitbuf=0;
+    static int vbits=0;
+    unsigned c, ret;
+
+    if (nbits == 0) return 0;
+    if (nbits == -1)
+        ret = bitbuf = vbits = 0;
+    else {
+        ret = bitbuf << (LONG_BITS - vbits) >> (LONG_BITS - nbits);
+        vbits -= nbits;
+    }
+    while (vbits < LONG_BITS - 7) {
+        c = fgetc(ifp);
+        bitbuf = (bitbuf << 8) + c;
+        if (c == 0xff && zero_after_ff)
+            fgetc(ifp);
+        vbits += 8;
+    }
+    return ret;
+}
diff --git a/converter/other/cameratopam/util.h b/converter/other/cameratopam/util.h
new file mode 100644
index 00000000..bf9006d3
--- /dev/null
+++ b/converter/other/cameratopam/util.h
@@ -0,0 +1,16 @@
+#ifndef UTIL_H_INCLUDED
+#define UTIL_H_INCLUDED
+
+unsigned short
+get2(FILE * const ifp);
+
+int
+get4(FILE * const ifp);
+
+void
+read_shorts (FILE * const ifp, unsigned short *pixel, int count);
+
+unsigned int
+getbits (FILE * const ifp, int nbits);
+
+#endif
diff --git a/converter/other/dithers.h b/converter/other/dithers.h
new file mode 100644
index 00000000..1ced833d
--- /dev/null
+++ b/converter/other/dithers.h
@@ -0,0 +1,91 @@
+#ifndef DITHERS_H_INCLUDED
+#define DITHERS_H_INCLUDED
+
+/*
+** dithers.h
+**
+** Here are some dithering matrices.  They are all taken from "Digital
+** Halftoning" by Robert Ulichney, MIT Press, ISBN 0-262-21009-6.
+*/
+
+
+#if 0
+/*
+** Order-6 ordered dithering matrix.  Note that smaller ordered dithers
+** have no advantage over larger ones, so use dither8 instead.
+*/
+static int dither6[8][8] = {
+  {  1, 59, 15, 55,  2, 56, 12, 52 },
+  { 33, 17, 47, 31, 34, 18, 44, 28 },
+  {  9, 49,  5, 63, 10, 50,  6, 60 },
+  { 41, 25, 37, 21, 42, 26, 38, 22 },
+  {  3, 57, 13, 53,  0, 58, 14, 54 },
+  { 35, 19, 45, 29, 32, 16, 46, 30 },
+  { 11, 51,  7, 61,  8, 48,  4, 62 },
+  { 43, 27, 39, 23, 40, 24, 36, 20 }
+  };
+#endif
+
+/* Order-8 ordered dithering matrix. */
+static int dither8[16][16] = {
+  {   1,235, 59,219, 15,231, 55,215,  2,232, 56,216, 12,228, 52,212},
+  { 129, 65,187,123,143, 79,183,119,130, 66,184,120,140, 76,180,116},
+  {  33,193, 17,251, 47,207, 31,247, 34,194, 18,248, 44,204, 28,244},
+  { 161, 97,145, 81,175,111,159, 95,162, 98,146, 82,172,108,156, 92},
+  {   9,225, 49,209,  5,239, 63,223, 10,226, 50,210,  6,236, 60,220},
+  { 137, 73,177,113,133, 69,191,127,138, 74,178,114,134, 70,188,124},
+  {  41,201, 25,241, 37,197, 21,255, 42,202, 26,242, 38,198, 22,252},
+  { 169,105,153, 89,165,101,149, 85,170,106,154, 90,166,102,150, 86},
+  {   3,233, 57,217, 13,229, 53,213,  0,234, 58,218, 14,230, 54,214},
+  { 131, 67,185,121,141, 77,181,117,128, 64,186,122,142, 78,182,118},
+  {  35,195, 19,249, 45,205, 29,245, 32,192, 16,250, 46,206, 30,246},
+  { 163, 99,147, 83,173,109,157, 93,160, 96,144, 80,174,110,158, 94},
+  {  11,227, 51,211,  7,237, 61,221,  8,224, 48,208,  4,238, 62,222},
+  { 139, 75,179,115,135, 71,189,125,136, 72,176,112,132, 68,190,126},
+  {  43,203, 27,243, 39,199, 23,253, 40,200, 24,240, 36,196, 20,254},
+  { 171,107,155, 91,167,103,151, 87,168,104,152, 88,164,100,148, 84} 
+};
+
+/* Order-3 clustered dithering matrix. */
+static int cluster3[6][6] = {
+  {  9,11,10, 8, 6, 7},
+  { 12,17,16, 5, 0, 1},
+  { 13,14,15, 4, 3, 2},
+  {  8, 6, 7, 9,11,10},
+  {  5, 0, 1,12,17,16},
+  {  4, 3, 2,13,14,15}
+};
+
+/* Order-4 clustered dithering matrix. */
+static int cluster4[8][8] = {
+  { 18,20,19,16,13,11,12,15},
+  { 27,28,29,22, 4, 3, 2, 9},
+  { 26,31,30,21, 5, 0, 1,10},
+  { 23,25,24,17, 8, 6, 7,14},
+  { 13,11,12,15,18,20,19,16},
+  {  4, 3, 2, 9,27,28,29,22},
+  {  5, 0, 1,10,26,31,30,21},
+  {  8, 6, 7,14,23,25,24,17}
+};
+
+/* Order-8 clustered dithering matrix. */
+static int cluster8[16][16] = {
+   { 64, 69, 77, 87, 86, 76, 68, 67, 63, 58, 50, 40, 41, 51, 59, 60},
+   { 70, 94,100,109,108, 99, 93, 75, 57, 33, 27, 18, 19, 28, 34, 52},
+   { 78,101,114,116,115,112, 98, 83, 49, 26, 13, 11, 12, 15, 29, 44},
+   { 88,110,123,124,125,118,107, 85, 39, 17,  4,  3,  2,  9, 20, 42},
+   { 89,111,122,127,126,117,106, 84, 38, 16,  5,  0,  1, 10, 21, 43},
+   { 79,102,119,121,120,113, 97, 82, 48, 25,  8,  6,  7, 14, 30, 45},
+   { 71, 95,103,104,105, 96, 92, 74, 56, 32, 24, 23, 22, 31, 35, 53},
+   { 65, 72, 80, 90, 91, 81, 73, 66, 62, 55, 47, 37, 36, 46, 54, 61},
+   { 63, 58, 50, 40, 41, 51, 59, 60, 64, 69, 77, 87, 86, 76, 68, 67},
+   { 57, 33, 27, 18, 19, 28, 34, 52, 70, 94,100,109,108, 99, 93, 75},
+   { 49, 26, 13, 11, 12, 15, 29, 44, 78,101,114,116,115,112, 98, 83},
+   { 39, 17,  4,  3,  2,  9, 20, 42, 88,110,123,124,125,118,107, 85},
+   { 38, 16,  5,  0,  1, 10, 21, 43, 89,111,122,127,126,117,106, 84},
+   { 48, 25,  8,  6,  7, 14, 30, 45, 79,102,119,121,120,113, 97, 82},
+   { 56, 32, 24, 23, 22, 31, 35, 53, 71, 95,103,104,105, 96, 92, 74},
+   { 62, 55, 47, 37, 36, 46, 54, 61, 65, 72, 80, 90, 91, 81, 73, 66}
+};
+
+#endif
diff --git a/converter/other/exif.c b/converter/other/exif.c
new file mode 100644
index 00000000..19f108a7
--- /dev/null
+++ b/converter/other/exif.c
@@ -0,0 +1,1030 @@
+/*--------------------------------------------------------------------------
+  This file contains subroutines for use by Jpegtopnm to handle the
+  EXIF header.
+
+  The code is adapted from the program Jhead by Matthaias Wandel
+  December 1999 - August 2000, and contributed to the public domain.
+  Bryan Henderson adapted it to Netpbm in September 2001.  Bryan
+  added more of Wandel's code, from Jhead 1.9 dated December 2002 in
+  January 2003.
+
+  An EXIF header is a JFIF APP1 marker.  It is generated by some
+  digital cameras and contains information about the circumstances of
+  the creation of the image (camera settings, etc.).
+
+  The EXIF header uses the TIFF format, only it contains only tag
+  values and no actual image.
+
+  Note that the image format called EXIF is simply JFIF with an EXIF
+  header, i.e. a subformat of JFIF.
+
+  See the EXIF specs at http://exif.org (2001.09.01).
+
+--------------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <limits.h>
+#include <ctype.h>
+
+#ifdef _WIN32
+    #include <sys/utime.h>
+#else
+    #include <utime.h>
+    #include <sys/types.h>
+    #include <unistd.h>
+    #include <errno.h>
+#endif
+
+#include "pm_c_util.h"
+#include "pm.h"
+#include "nstring.h"
+
+#include "exif.h"
+
+static unsigned char * LastExifRefd;
+static 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;
+
+
+/* Describes format descriptor */
+static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
+#define NUM_FORMATS 12
+
+#define FMT_BYTE       1 
+#define FMT_STRING     2
+#define FMT_USHORT     3
+#define FMT_ULONG      4
+#define FMT_URATIONAL  5
+#define FMT_SBYTE      6
+#define FMT_UNDEFINED  7
+#define FMT_SSHORT     8
+#define FMT_SLONG      9
+#define FMT_SRATIONAL 10
+#define FMT_SINGLE    11
+#define FMT_DOUBLE    12
+
+/* Describes tag values */
+
+#define TAG_EXIF_OFFSET       0x8769
+#define TAG_INTEROP_OFFSET    0xa005
+
+#define TAG_MAKE              0x010F
+#define TAG_MODEL             0x0110
+
+#define TAG_ORIENTATION       0x0112
+
+#define TAG_EXPOSURETIME      0x829A
+#define TAG_FNUMBER           0x829D
+
+#define TAG_SHUTTERSPEED      0x9201
+#define TAG_APERTURE          0x9202
+#define TAG_MAXAPERTURE       0x9205
+#define TAG_FOCALLENGTH       0x920A
+
+#define TAG_DATETIME_ORIGINAL 0x9003
+#define TAG_USERCOMMENT       0x9286
+
+#define TAG_SUBJECT_DISTANCE  0x9206
+#define TAG_FLASH             0x9209
+
+#define TAG_FOCALPLANEXRES    0xa20E
+#define TAG_FOCALPLANEUNITS   0xa210
+#define TAG_EXIF_IMAGEWIDTH   0xA002
+#define TAG_EXIF_IMAGELENGTH  0xA003
+
+/* the following is added 05-jan-2001 vcs */
+#define TAG_EXPOSURE_BIAS     0x9204
+#define TAG_WHITEBALANCE      0x9208
+#define TAG_METERING_MODE     0x9207
+#define TAG_EXPOSURE_PROGRAM  0x8822
+#define TAG_ISO_EQUIVALENT    0x8827
+#define TAG_COMPRESSION_LEVEL 0x9102
+
+#define TAG_THUMBNAIL_OFFSET  0x0201
+#define TAG_THUMBNAIL_LENGTH  0x0202
+
+static TagTable_t const TagTable[] = {
+  {   0x100,   "ImageWidth"},
+  {   0x101,   "ImageLength"},
+  {   0x102,   "BitsPerSample"},
+  {   0x103,   "Compression"},
+  {   0x106,   "PhotometricInterpretation"},
+  {   0x10A,   "FillOrder"},
+  {   0x10D,   "DocumentName"},
+  {   0x10E,   "ImageDescription"},
+  {   0x10F,   "Make"},
+  {   0x110,   "Model"},
+  {   0x111,   "StripOffsets"},
+  {   0x112,   "Orientation"},
+  {   0x115,   "SamplesPerPixel"},
+  {   0x116,   "RowsPerStrip"},
+  {   0x117,   "StripByteCounts"},
+  {   0x11A,   "XResolution"},
+  {   0x11B,   "YResolution"},
+  {   0x11C,   "PlanarConfiguration"},
+  {   0x128,   "ResolutionUnit"},
+  {   0x12D,   "TransferFunction"},
+  {   0x131,   "Software"},
+  {   0x132,   "DateTime"},
+  {   0x13B,   "Artist"},
+  {   0x13E,   "WhitePoint"},
+  {   0x13F,   "PrimaryChromaticities"},
+  {   0x156,   "TransferRange"},
+  {   0x200,   "JPEGProc"},
+  {   0x201,   "ThumbnailOffset"},
+  {   0x202,   "ThumbnailLength"},
+  {   0x211,   "YCbCrCoefficients"},
+  {   0x212,   "YCbCrSubSampling"},
+  {   0x213,   "YCbCrPositioning"},
+  {   0x214,   "ReferenceBlackWhite"},
+  {   0x828D,  "CFARepeatPatternDim"},
+  {   0x828E,  "CFAPattern"},
+  {   0x828F,  "BatteryLevel"},
+  {   0x8298,  "Copyright"},
+  {   0x829A,  "ExposureTime"},
+  {   0x829D,  "FNumber"},
+  {   0x83BB,  "IPTC/NAA"},
+  {   0x8769,  "ExifOffset"},
+  {   0x8773,  "InterColorProfile"},
+  {   0x8822,  "ExposureProgram"},
+  {   0x8824,  "SpectralSensitivity"},
+  {   0x8825,  "GPSInfo"},
+  {   0x8827,  "ISOSpeedRatings"},
+  {   0x8828,  "OECF"},
+  {   0x9000,  "ExifVersion"},
+  {   0x9003,  "DateTimeOriginal"},
+  {   0x9004,  "DateTimeDigitized"},
+  {   0x9101,  "ComponentsConfiguration"},
+  {   0x9102,  "CompressedBitsPerPixel"},
+  {   0x9201,  "ShutterSpeedValue"},
+  {   0x9202,  "ApertureValue"},
+  {   0x9203,  "BrightnessValue"},
+  {   0x9204,  "ExposureBiasValue"},
+  {   0x9205,  "MaxApertureValue"},
+  {   0x9206,  "SubjectDistance"},
+  {   0x9207,  "MeteringMode"},
+  {   0x9208,  "LightSource"},
+  {   0x9209,  "Flash"},
+  {   0x920A,  "FocalLength"},
+  {   0x927C,  "MakerNote"},
+  {   0x9286,  "UserComment"},
+  {   0x9290,  "SubSecTime"},
+  {   0x9291,  "SubSecTimeOriginal"},
+  {   0x9292,  "SubSecTimeDigitized"},
+  {   0xA000,  "FlashPixVersion"},
+  {   0xA001,  "ColorSpace"},
+  {   0xA002,  "ExifImageWidth"},
+  {   0xA003,  "ExifImageLength"},
+  {   0xA005,  "InteroperabilityOffset"},
+  {   0xA20B,  "FlashEnergy"},                 /* 0x920B in TIFF/EP */
+  {   0xA20C,  "SpatialFrequencyResponse"},  /* 0x920C    -  - */
+  {   0xA20E,  "FocalPlaneXResolution"},     /* 0x920E    -  - */
+  {   0xA20F,  "FocalPlaneYResolution"},      /* 0x920F    -  - */
+  {   0xA210,  "FocalPlaneResolutionUnit"},  /* 0x9210    -  - */
+  {   0xA214,  "SubjectLocation"},             /* 0x9214    -  - */
+  {   0xA215,  "ExposureIndex"},            /* 0x9215    -  - */
+  {   0xA217,  "SensingMethod"},            /* 0x9217    -  - */
+  {   0xA300,  "FileSource"},
+  {   0xA301,  "SceneType"},
+  {      0, NULL}
+} ;
+
+
+
+/*--------------------------------------------------------------------------
+   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];
+    }else{
+        return (((unsigned char *)Short)[1] << 8) | 
+            ((unsigned char *)Short)[0];
+    }
+}
+
+/*--------------------------------------------------------------------------
+   Convert a 32 bit signed value from file's native byte order
+--------------------------------------------------------------------------*/
+static int Get32s(void * Long)
+{
+    if (MotorolaOrder){
+        return  
+            ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16) |
+            (((unsigned char *)Long)[2] << 8 ) | 
+            (((unsigned char *)Long)[3] << 0 );
+    }else{
+        return  
+            ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16) |
+            (((unsigned char *)Long)[1] << 8 ) | 
+            (((unsigned char *)Long)[0] << 0 );
+    }
+}
+
+/*--------------------------------------------------------------------------
+   Convert a 32 bit unsigned value from file's native byte order
+--------------------------------------------------------------------------*/
+static unsigned Get32u(void * Long)
+{
+    return (unsigned)Get32s(Long) & 0xffffffff;
+}
+
+/*--------------------------------------------------------------------------
+   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_ULONG:     
+    case FMT_SLONG:     fprintf(file, "%d\n",Get32s(ValuePtr));    break;
+    case FMT_SSHORT:    
+        fprintf(file, "%hd\n",(signed short)Get16u(ValuePtr));     break;
+    case FMT_URATIONAL:
+    case FMT_SRATIONAL: 
+        fprintf(file, "%d/%d\n",Get32s(ValuePtr), Get32s(4+(char *)ValuePtr));
+        break;
+    case FMT_SINGLE:    
+        fprintf(file, "%f\n",(double)*(float *)ValuePtr);          break;
+    case FMT_DOUBLE:    fprintf(file, "%f\n",*(double *)ValuePtr); break;
+    default: 
+        fprintf(file, "Unknown format %d:", Format);
+        {
+            int a;
+            for (a=0; a < ByteCount && a < 16; ++a)
+                printf("%02x", ((unsigned char *)ValuePtr)[a]);
+        }
+        fprintf(file, "\n");
+    }
+}
+
+
+/*--------------------------------------------------------------------------
+   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;
+
+        /* 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.
+                */
+                pm_message("Illegal directory entry size");
+                return;
+            }
+        }
+        if (DirEnd > LastExifRefd) LastExifRefd = DirEnd;
+    }
+
+    if (ShowTags){
+        pm_message("Directory with %d entries",NumDirEntries);
+    }
+
+    for (de=0;de<NumDirEntries;de++){
+        int Tag, Format, Components;
+        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.  
+            */
+        int ByteCount;
+        unsigned char * DirEntry;
+        DirEntry = DIR_ENTRY_ADDR(DirStart, de);
+
+        Tag = Get16u(DirEntry);
+        Format = Get16u(DirEntry+2);
+        Components = Get32u(DirEntry+4);
+
+        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);
+            continue;
+        }
+        
+        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;
+        }else{
+            /* 4 bytes or less and value is in the dir entry itself */
+            ValuePtr = DirEntry+8;
+        }
+
+        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;
+        }
+
+        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;
+                }
+            }
+
+            /* 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;a<ByteCount;a++){
+                            if (ISPRINT((ValuePtr)[a])){
+                                fprintf(stderr, "%c", (ValuePtr)[a]);
+                                NoPrint = 0;
+                            }else{
+
+                                /* Avoiding indicating too many
+                                   unprintable characters of proprietary
+                                   bits of binary information this
+                                   program may not know how to parse.  
+                                */
+                                if (!NoPrint){
+                                    fprintf(stderr, "?");
+                                    NoPrint = 1;
+                                }
+                            }
+                        }
+                        fprintf(stderr, "\"\n");
+                    }
+                    break;
+
+                default:
+                    /* Handle arrays of numbers later (will there ever be?)*/
+                    PrintFormatNumber(stderr, ValuePtr, Format, ByteCount);
+            }
+        }
+
+        /* Extract useful components of tag */
+        switch(Tag){
+
+            case TAG_MAKE:
+                strncpy(ImageInfoP->CameraMake, (char*)ValuePtr, 31);
+                break;
+
+            case TAG_MODEL:
+                strncpy(ImageInfoP->CameraModel, (char*)ValuePtr, 39);
+                break;
+
+            case TAG_DATETIME_ORIGINAL:
+                strncpy(ImageInfoP->DateTime, (char*)ValuePtr, 19);
+                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;
+                }
+
+                /* 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_FOCALLENGTH:
+                /* Nice digital cameras actually save the focal length
+                   as a function of how farthey are zoomed in. 
+                */
+
+                ImageInfoP->FocalLength = 
+                    (float)ConvertAnyFormat(ValuePtr, Format);
+                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_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_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 3: FocalplaneUnits = 10;   break;  /* 1 centimeter*/
+                    case 4: FocalplaneUnits = 1;    break;  /* 1 millimeter*/
+                    case 5: FocalplaneUnits = .001; break;  /* 1 micrometer*/
+                }
+                break;
+
+                /* Remaining cases contributed by: Volker C. Schoech
+                   (schoech@gmx.de)
+                */
+
+            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;
+                }
+        }
+
+    }
+
+
+    {
+        /* In addition to linking to subdirectories via exif tags,
+           there's also a potential link to another directory at the end
+           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){
+                        /* 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) 
+                            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);
+                }
+            }
+        }else{
+            /* The exif header ends before the last next directory pointer. */
+        }
+    }
+
+    if (ThumbnailSize && ThumbnailOffset){
+        if (ThumbnailSize + ThumbnailOffset <= ExifLength){
+            /* The thumbnail pointer appears to be valid.  Store it. */
+            ImageInfoP->ThumbnailPointer = ExifData + ThumbnailOffset;
+            ImageInfoP->ThumbnailSize = ThumbnailSize;
+
+            if (ShowTags){
+                fprintf(stderr, "Thumbnail size: %d bytes\n",ThumbnailSize);
+            }
+        }
+    }
+}
+
+
+
+void 
+process_EXIF(unsigned char * const ExifData,
+             unsigned int    const length,
+             ImageInfo_t *   const ImageInfoP, 
+             int             const ShowTags,
+             const char **   const errorP) {
+/*--------------------------------------------------------------------------
+  Interpret an EXIF APP1 marker
+
+  '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.
+--------------------------------------------------------------------------*/
+    int FirstOffset;
+    unsigned char * LastExifRefd;
+
+    *errorP = NULL;  /* initial assumption */
+
+    if (ShowTags){
+        fprintf(stderr, "Exif header %d bytes long\n",length);
+    }
+
+    if (memcmp(ExifData+0,"II",2) == 0) {
+        if (ShowTags) 
+            fprintf(stderr, "Exif header in Intel order\n");
+        MotorolaOrder = 0;
+    } else {
+        if (memcmp(ExifData+0, "MM", 2) == 0) {
+            if (ShowTags) 
+                fprintf(stderr, "Exif header in Motorola order\n");
+            MotorolaOrder = 1;
+        } 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]);
+        }
+    }
+    if (!*errorP) {
+        unsigned short const start = Get16u(ExifData + 2);
+        /* 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);
+        }
+    }
+    if (!*errorP) {
+        FirstOffset = Get32u(ExifData + 4);
+        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
+               differently, and uses it as offset. (Sept 11 2002)
+                */
+            pm_message("Suspicious offset of first IFD value in Exif header");
+        }
+        
+        ImageInfoP->Comments[0] = '\0';  /* Initial value - null string */
+        
+        HaveXRes = FALSE;  /* Initial assumption */
+        FocalplaneUnits = 0;
+        ExifImageWidth = 0;
+        
+        LastExifRefd = ExifData;
+        DirWithThumbnailPtrs = NULL;
+        
+        ProcessExifDir(ExifData, length, FirstOffset, 
+                       ImageInfoP, ShowTags, &LastExifRefd);
+        
+        /* Compute the CCD width, in millimeters. */
+        if (HaveXRes){
+            ImageInfoP->HaveCCDWidth = 1;
+            ImageInfoP->CCDWidth = 
+                    (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
+        } else
+            ImageInfoP->HaveCCDWidth = 0;
+            
+        if (ShowTags){
+            fprintf(stderr, 
+                    "Non-settings part of Exif header: %d bytes\n",
+                    ExifData+length-LastExifRefd);
+        }
+    }
+}
+
+/*--------------------------------------------------------------------------
+   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->DateTime[0]){
+        fprintf(stderr, "Date/Time    : %s\n",ImageInfoP->DateTime);
+    }
+    fprintf(stderr, "Resolution   : %d x %d\n",
+            ImageInfoP->Width, ImageInfoP->Height);
+    if (ImageInfoP->Orientation > 1){
+
+        /* Only print orientation if one was supplied, and if its not
+           1 (normal orientation)
+
+           1 - The 0th row is at the visual top of the image
+               and the 0th column is the visual left-hand side.
+           2 - The 0th row is at the visual top of the image
+               and the 0th column is the visual right-hand side.
+           3 - The 0th row is at the visual bottom of the image
+               and the 0th column is the visual right-hand side.
+           4 - The 0th row is at the visual bottom of the image
+               and the 0th column is the visual left-hand side.
+           5 - The 0th row is the visual left-hand side of of the image
+               and the 0th column is the visual top.
+           6 - The 0th row is the visual right-hand side of of the image
+               and the 0th column is the visual top.
+           7 - The 0th row is the visual right-hand side of of the image
+               and the 0th column is the visual bottom.
+           8 - The 0th row is the visual left-hand side of of the image
+               and the 0th column is the visual bottom.
+
+           Note: The descriptions here are the same as the name of the
+           command line option to pass to jpegtran to right the image
+        */
+        static const char * OrientTab[9] = {
+            "Undefined",
+            "Normal",           /* 1 */
+            "flip horizontal",  /* left right reversed mirror */
+            "rotate 180",       /* 3 */
+            "flip vertical",    /* upside down mirror */
+            "transpose",    /* Flipped about top-left <--> bottom-right axis.*/
+            "rotate 90",        /* rotate 90 cw to right it. */
+            "transverse",   /* flipped about top-right <--> bottom-left axis */
+            "rotate 270",       /* rotate 270 to right it. */
+        };
+
+        fprintf(stderr, "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)",
+                    (int)
+                    (ImageInfoP->FocalLength/ImageInfoP->CCDWidth*36 + 0.5));
+        }
+        fprintf(stderr, "\n");
+    }
+
+    if (ImageInfoP->HaveCCDWidth){
+        fprintf(stderr, "CCD width    : %2.4fmm\n",
+                (double)ImageInfoP->CCDWidth);
+    }
+
+    if (ImageInfoP->ExposureTime){ 
+        if (ImageInfoP->ExposureTime < 0.010){
+            fprintf(stderr, 
+                    "Exposure time: %6.4f s ",
+                    (double)ImageInfoP->ExposureTime);
+        }else{
+            fprintf(stderr, 
+                    "Exposure time: %5.3f s ",
+                    (double)ImageInfoP->ExposureTime);
+        }
+        if (ImageInfoP->ExposureTime <= 0.5){
+            fprintf(stderr, " (1/%d)",(int)(0.5 + 1/ImageInfoP->ExposureTime));
+        }
+        fprintf(stderr, "\n");
+    }
+    if (ImageInfoP->ApertureFNumber){
+        fprintf(stderr, "Aperture     : f/%3.1f\n",
+                (double)ImageInfoP->ApertureFNumber);
+    }
+    if (ImageInfoP->Distance){
+        if (ImageInfoP->Distance < 0){
+            fprintf(stderr, "Focus dist.  : Infinite\n");
+        }else{
+            fprintf(stderr, "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->ExposureBias){ /* 05-jan-2001 vcs */
+        fprintf(stderr, "Exposure bias:%4.2f\n",
+                (double)ImageInfoP->ExposureBias);
+    }
+        
+    if (ImageInfoP->Whitebalance){ /* 05-jan-2001 vcs */
+        switch(ImageInfoP->Whitebalance) {
+        case 1:
+            fprintf(stderr, "Whitebalance : sunny\n");
+            break;
+        case 2:
+            fprintf(stderr, "Whitebalance : fluorescent\n");
+            break;
+        case 3:
+            fprintf(stderr, "Whitebalance : incandescent\n");
+            break;
+        default:
+            fprintf(stderr, "Whitebalance : cloudy\n");
+        }
+    }
+    if (ImageInfoP->MeteringMode){ /* 05-jan-2001 vcs */
+        switch(ImageInfoP->MeteringMode) {
+        case 2:
+            fprintf(stderr, "Metering Mode: center weight\n");
+            break;
+        case 3:
+            fprintf(stderr, "Metering Mode: spot\n");
+            break;
+        case 5:
+            fprintf(stderr, "Metering Mode: matrix\n");
+            break;
+        }
+    }
+    if (ImageInfoP->ExposureProgram){ /* 05-jan-2001 vcs */
+        switch(ImageInfoP->ExposureProgram) {
+        case 2:
+            fprintf(stderr, "Exposure     : program (auto)\n");
+            break;
+        case 3:
+            fprintf(stderr, "Exposure     : aperture priority (semi-auto)\n");
+            break;
+        case 4:
+            fprintf(stderr, "Exposure     : shutter priority (semi-auto)\n");
+            break;
+        }
+    }
+    if (ImageInfoP->CompressionLevel){ /* 05-jan-2001 vcs */
+        switch(ImageInfoP->CompressionLevel) {
+        case 1:
+            fprintf(stderr, "Jpeg Quality  : basic\n");
+            break;
+        case 2:
+            fprintf(stderr, "Jpeg Quality  : normal\n");
+            break;
+        case 4:
+            fprintf(stderr, "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;a<MAX_COMMENT;a++){
+            c = ImageInfoP->Comments[a];
+            if (c == '\0') break;
+            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);
+            }
+        }
+        fprintf(stderr, "\n");
+    }
+
+    fprintf(stderr, "\n");
+}
+
+
+
+
diff --git a/converter/other/exif.h b/converter/other/exif.h
new file mode 100644
index 00000000..e5825e12
--- /dev/null
+++ b/converter/other/exif.h
@@ -0,0 +1,56 @@
+#ifndef EXIF_H_INCLUDED
+#define EXIF_H_INCLUDED
+
+#define MAX_COMMENT 2000
+
+#ifdef _WIN32
+    #define PATH_MAX _MAX_PATH
+#endif
+
+/*--------------------------------------------------------------------------
+  This structure stores Exif header image elements in a simple manner
+  Used to store camera data as extracted from the various ways that it can be
+  stored in an exif header
+--------------------------------------------------------------------------*/
+typedef struct {
+    char  CameraMake   [32];
+    char  CameraModel  [40];
+    char  DateTime     [20];
+    int   Height, Width;
+    int   Orientation;
+    int   IsColor;
+    int   FlashUsed;
+    float FocalLength;
+    float ExposureTime;
+    float ApertureFNumber;
+    float Distance;
+    int   HaveCCDWidth;  /* boolean */
+    float CCDWidth;
+    float ExposureBias;
+    int   Whitebalance;
+    int   MeteringMode;
+    int   ExposureProgram;
+    int   ISOequivalent;
+    int   CompressionLevel;
+    char  Comments[MAX_COMMENT];
+
+    unsigned char * ThumbnailPointer;  /* Pointer at the thumbnail */
+    unsigned ThumbnailSize;     /* Size of thumbnail. */
+
+    char * DatePointer;
+}ImageInfo_t;
+
+
+/* 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);
+
+void 
+ShowImageInfo(ImageInfo_t * const ImageInfoP);
+
+#endif
diff --git a/converter/other/fiasco/Makefile b/converter/other/fiasco/Makefile
new file mode 100644
index 00000000..0dd945ed
--- /dev/null
+++ b/converter/other/fiasco/Makefile
@@ -0,0 +1,59 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/fiasco
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+INCLUDES = \
+	-I$(SRCDIR)/$(SUBDIR)/codec -I$(SRCDIR)/$(SUBDIR)/input \
+	-I$(SRCDIR)/$(SUBDIR)/output -I$(SRCDIR)/$(SUBDIR)/lib \
+
+BINARIES = pnmtofiasco fiascotopnm
+
+MERGEBINARIES = $(BINARIES)
+
+SCRIPTS =
+
+all: $(BINARIES)
+
+FIASCOLIBS = codec/libfiasco_codec.a \
+	     input/libfiasco_input.a \
+	     output/libfiasco_output.a \
+	     lib/libfiasco_lib.a 
+
+COMMON_OBJECTS = binerror.o getopt.o getopt1.o params.o
+
+OBJECTS = $(BINARIES:%=%.o) $(COMMON_OBJECTS)
+
+MERGE_OBJECTS = $(BINARIES:%=%.o2) $(COMMON_OBJECTS)  $(FIASCOLIBS)
+
+SUBDIRS = codec input output lib
+
+include $(SRCDIR)/Makefile.common
+
+$(BINARIES):%:%.o $(COMMON_OBJECTS) $(FIASCOLIBS) $(NETPBMLIB) \
+   $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $< $(COMMON_OBJECTS) \
+	$(shell $(LIBOPT) $(FIASCOLIBS) $(NETPBMLIB)) $(MATHLIB) $(LDLIBS) \
+	$(RPATH) $(LADD)
+
+codec/libfiasco_codec.a: $(BUILDDIR)/$(SUBDIR)/codec FORCE
+	$(MAKE) -C codec -f $(SRCDIR)/$(SUBDIR)/codec/Makefile \
+		libfiasco_codec.a SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR)
+
+input/libfiasco_input.a: $(BUILDDIR)/$(SUBDIR)/input FORCE
+	$(MAKE) -C input -f $(SRCDIR)/$(SUBDIR)/input/Makefile \
+		libfiasco_input.a SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR)
+
+output/libfiasco_output.a: $(BUILDDIR)/$(SUBDIR)/output FORCE
+	$(MAKE) -C output -f $(SRCDIR)/$(SUBDIR)/output/Makefile \
+		libfiasco_output.a SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR)
+
+lib/libfiasco_lib.a: $(BUILDDIR)/$(SUBDIR)/lib FORCE
+	$(MAKE) -C lib -f $(SRCDIR)/$(SUBDIR)/lib/Makefile \
+		libfiasco_lib.a SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR)
+
+
diff --git a/converter/other/fiasco/README.netpbm b/converter/other/fiasco/README.netpbm
new file mode 100644
index 00000000..4f4019ad
--- /dev/null
+++ b/converter/other/fiasco/README.netpbm
@@ -0,0 +1,41 @@
+The 'fiasco' subdirectory of the Netpbm source tree is primarily a copy
+of the source distribution of the Fiasco package by Ullrich Hafner.
+Bryan Henderson adapted fiasco-1.0 on July 6, 2000 to netpbm, and then
+merged in all the updates from fiasco-1.3 on February 9, 2001.
+
+The changes are:
+
+- Uses Netpbm libraries for input and output of Netpbm format images.
+
+- Works with maxvals other than 255 in Netpbm input images.  This change
+  also makes a minor correction to the maxval 255 case.  Where the Fiasco
+  package multiplies by 16 to convert from 8 bit to 12 bit intensity,
+  the correct factor is 4095/255.
+
+- Does not issue warning when system configuration file not found.
+  The location of that file is a compile-time option in 'fiasco', but
+  fixed at /etc in Netpbm.  The expectation is that Netpbm users will
+  never have a system configuration file.
+
+- Does not fail if basis file small.fco is not found.  The Fiasco code
+  already contained facilities for defaulting to a built-in version of
+  small.fco, but it was disabled by an early check for existence of
+  the basis file as an actual file.  In Netpbm, that check for
+  existence is simply removed.
+
+- Remove WINDOWS config.h configuration macro, which determined whether
+  files would be open with "b" flag (binary).  Use "b" flag unconditionally.
+
+- Rename internal "log2" function to "Log2" to avoid conflict with existing
+  "log2" macro or function.  The original package has conditional compilation
+  to allow it to use the existing log2 when configured for a system that has
+  it.  In Netpbm, we always use the private version.
+
+- Compilation warnings fixed.
+
+- 'bin' subdirectory moved to top level directory.
+
+- man pages for programs moved from doc subdirectory to top level directory.
+
+- man page of pnmpsnr created.
+
diff --git a/converter/other/fiasco/binerror.c b/converter/other/fiasco/binerror.c
new file mode 100644
index 00000000..8a41a214
--- /dev/null
+++ b/converter/other/fiasco/binerror.c
@@ -0,0 +1,143 @@
+/*
+ *  error.c:		Error handling
+ *
+ *  Written by:		Stefan Frank
+ *			Ullrich Hafner
+ *  
+ *  Credits:	Modelled after variable argument routines from Jef
+ *		Poskanzer's pbmplus package. 
+ *
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/03/20 21:29:59 $
+ *  $Author: hafner $
+ *  $Revision: 4.3 $
+ *  $State: Exp $
+ */
+
+#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+#define _ERROR_C
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#if STDC_HEADERS
+#	include <stdarg.h>
+#	define VA_START(args, lastarg) va_start(args, lastarg)
+#else  /* not STDC_HEADERS */
+#	include <varargs.h>
+#	define VA_START(args, lastarg) va_start(args)
+#endif /* not STDC_HEADERS */
+#include <string.h>
+
+#if HAVE_SETJMP_H
+#	include <setjmp.h>
+#endif /* HAVE_SETJMP_H */
+
+#include "fiasco.h"
+#include "binerror.h"
+
+/*****************************************************************************
+
+			     global variables
+  
+*****************************************************************************/
+
+int   error_line = 0;
+const char *error_file = NULL;
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+static const char *executable = "(name not initialized)";
+
+/*****************************************************************************
+
+			       public code
+  
+*****************************************************************************/
+
+void
+init_error_handling (const char *name)
+/*
+ *  Initialize filename of executable.
+ *
+ *  No return value.
+ */
+{
+   if (name)
+      executable = strdup (name);
+}
+
+void
+_error (const char *format, ...)
+/*
+ *  Print error message and exit.
+ *
+ *  No return value.
+ */
+{
+   va_list	args;
+
+   VA_START (args, 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);
+
+   exit (1);
+}
+
+void
+_file_error (const char *filename)
+/*
+ *  Print file error message and exit.
+ *
+ *  No return value.
+ */
+{
+   fprintf (stderr, "%s: %s: line %d:\nError: ",
+	    executable, error_file, error_line);
+   perror (filename);
+
+   exit (2);
+}
+
+void 
+_warning (const char *format, ...)
+/*
+ *  Issue a warning and continue execution.
+ *
+ *  No return value.
+ */
+{
+   va_list args;
+
+   VA_START (args, 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/binerror.h b/converter/other/fiasco/binerror.h
new file mode 100644
index 00000000..e7ff43c9
--- /dev/null
+++ b/converter/other/fiasco/binerror.h
@@ -0,0 +1,50 @@
+/*
+ *  error.h
+ *  
+ *  Written by:		Stefan Frank
+ *			Ullrich Hafner
+ *
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/03/20 21:29:59 $
+ *  $Author: hafner $
+ *  $Revision: 4.3 $
+ *  $State: Exp $
+ */
+
+#ifndef _ERROR_H
+#define _ERROR_H
+
+#define error          error_line=__LINE__,error_file=__FILE__,_error
+#define warning        error_line=__LINE__,error_file=__FILE__,_warning
+#define file_error(fn) error_line=__LINE__,error_file=__FILE__,_file_error(fn)
+
+#ifdef _ERROR_C
+#define _EXTERN_TYPE
+#else
+#define _EXTERN_TYPE	extern
+#endif
+
+_EXTERN_TYPE int   error_line;
+_EXTERN_TYPE const char *error_file;
+
+void
+init_error_handling (const char *name);
+void
+_error (const char *format, ...);
+void
+_warning (const char *format, ...);
+void
+_file_error (const char *filename);
+
+#if HAVE_ASSERT_H
+#	include <assert.h>
+#else /* not HAVE_ASSERT_H */
+#	define assert(exp)	{if (!(exp)) error ("Assertion `" #exp " != NULL' failed.");}
+#endif /* not HAVE_ASSERT_H */
+
+#endif /* not _ERROR_H */
+
diff --git a/converter/other/fiasco/buttons.c b/converter/other/fiasco/buttons.c
new file mode 100644
index 00000000..82ed18cd
--- /dev/null
+++ b/converter/other/fiasco/buttons.c
@@ -0,0 +1,510 @@
+/*
+ *  buttons.c:		Draw MWFA player buttons in X11 window	
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/15 17:23:11 $
+ *  $Author: hafner $
+ *  $Revision: 5.2 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#ifndef X_DISPLAY_MISSING
+
+#include <X11/Xlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+
+#if STDC_HEADERS
+#	include <stdlib.h>
+#endif /* not STDC_HEADERS */
+
+#include "types.h"
+#include "macros.h"
+
+#include "display.h"
+#include "binerror.h"
+#include "buttons.h"
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+static const int EVENT_MASK = (KeyPressMask | ButtonPressMask |
+			       ButtonReleaseMask | ExposureMask);
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+draw_progress_bar (x11_info_t *xinfo, binfo_t *binfo, unsigned n,
+		   unsigned n_frames);
+static void
+draw_button (x11_info_t *xinfo, binfo_t *binfo,
+	     buttons_t button, bool_t pressed);
+static void
+draw_control_panel (x11_info_t *xinfo, binfo_t *binfo,
+		    unsigned n, unsigned n_frames);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+binfo_t * 
+init_buttons (x11_info_t *xinfo, unsigned n, unsigned n_frames,
+	      unsigned buttons_height, unsigned progbar_height)
+/*
+ *  Initialize a toolbar with the typical collection of video player
+ *  buttons (pause, play, record, next, etc.) in the window given by 'xinfo'.
+ *  'n' gives the current frame, 'whereas' n_frames is the total number of
+ *  frames of the video stream.
+ *  The size of the button toolbar is given by 'buttons_height',
+ *  the size of the progressbar is given by 'progbar_height'.
+ *
+ *  Return value:
+ *	struct managing the toolbar and progressbar information
+ */
+{
+   XGCValues  values;
+   XEvent     event;
+   Colormap   cmap;
+   XColor     gray, dgray, lgray, red;
+   XColor     graye, dgraye, lgraye, rede;
+   buttons_t  button;			/* counter */
+   binfo_t   *binfo = calloc (1, sizeof (binfo_t));
+
+   if (!binfo)
+      error ("Out of memory.");
+   
+   binfo->width            = xinfo->ximage->width;
+   binfo->height           = buttons_height;
+   binfo->progbar_height   = progbar_height;
+   binfo->record_is_rewind = NO;
+
+   /*
+    *  Generate sub-window for control panel
+    */
+   binfo->window = XCreateSimpleWindow (xinfo->display, xinfo->window,
+					0, xinfo->ximage->height,
+					binfo->width, binfo->height, 0,
+					BlackPixel (xinfo->display,
+						    xinfo->screen),
+					WhitePixel (xinfo->display,
+						    xinfo->screen));
+   XSelectInput(xinfo->display, binfo->window, StructureNotifyMask);
+   XMapWindow (xinfo->display, binfo->window);
+   do
+   {
+      XNextEvent (xinfo->display, &event);
+   }
+   while (event.type != MapNotify || event.xmap.event != binfo->window);
+   XSelectInput (xinfo->display, binfo->window, EVENT_MASK);
+
+   /*
+    *  Generate graphic contexts for different colors.
+    */
+   cmap = DefaultColormap (xinfo->display, xinfo->screen);
+   XAllocNamedColor (xinfo->display, cmap, "#404040", &dgray, &dgraye);
+   XAllocNamedColor (xinfo->display, cmap, "white", &lgray, &lgraye);
+   XAllocNamedColor (xinfo->display, cmap, "#a8a8a8", &gray, &graye);
+   XAllocNamedColor (xinfo->display, cmap, "red", &red, &rede);
+   
+   values.foreground = BlackPixel (xinfo->display, xinfo->screen);
+   values.background = WhitePixel (xinfo->display, xinfo->screen);
+   binfo->gc [BLACK] = XCreateGC (xinfo->display,
+				  RootWindow (xinfo->display, xinfo->screen),
+				  (GCForeground | GCBackground), &values);
+   values.foreground = BlackPixel (xinfo->display, xinfo->screen);
+   values.background = WhitePixel (xinfo->display, xinfo->screen);
+   values.line_width = 3;
+   values.join_style = JoinRound;
+   binfo->gc [THICKBLACK] = XCreateGC (xinfo->display,
+				       RootWindow (xinfo->display,
+						   xinfo->screen),
+				       (GCForeground | GCBackground
+					| GCLineWidth | GCJoinStyle), &values);
+   values.foreground = gray.pixel;
+   values.background = WhitePixel (xinfo->display, xinfo->screen);
+   binfo->gc [NGRAY] = XCreateGC (xinfo->display,
+				  RootWindow (xinfo->display, xinfo->screen),
+				  (GCForeground | GCBackground), &values);
+   values.foreground = lgray.pixel;
+   values.background = WhitePixel (xinfo->display, xinfo->screen);
+   binfo->gc [LGRAY] = XCreateGC (xinfo->display,
+				  RootWindow (xinfo->display, xinfo->screen),
+				  (GCForeground | GCBackground), &values);
+   values.foreground = dgray.pixel;
+   values.background = WhitePixel (xinfo->display, xinfo->screen);
+   binfo->gc [DGRAY] = XCreateGC (xinfo->display,
+				  RootWindow (xinfo->display, xinfo->screen),
+				  (GCForeground | GCBackground), &values);
+   values.foreground = red.pixel;
+   values.background = WhitePixel (xinfo->display, xinfo->screen);
+   binfo->gc [RED]   = XCreateGC (xinfo->display,
+				  RootWindow (xinfo->display, xinfo->screen),
+				  (GCForeground | GCBackground), &values);
+
+   for (button = 0; button < NO_BUTTON; button++)
+      binfo->pressed [button] = NO;
+
+   draw_control_panel (xinfo, binfo, n, n_frames); 
+   
+   return binfo;
+}
+
+void
+wait_for_input (x11_info_t *xinfo)
+/*
+ *  Wait for key press or mouse click in window 'xinfo'.
+ *  Redraw 'image' if event other then ButtonPress or KeyPress occurs.
+ *  Enlarge or reduce size of image by factor 2^'enlarge_factor'.
+ *
+ *  No return value.
+ *
+ *  Side effect:
+ *	program is terminated after key press or mouse click.
+ */
+{
+   bool_t leave_loop = NO;
+   
+   XSelectInput (xinfo->display, xinfo->window, EVENT_MASK);
+
+   while (!leave_loop)
+   {
+      XEvent event;
+
+      XMaskEvent (xinfo->display, EVENT_MASK, &event);
+      switch (event.type)
+      {
+	 case ButtonPress:
+	 case KeyPress:
+	    leave_loop = YES;
+	    break;
+	 default:
+	    display_image (0, 0, xinfo);
+	    break;
+      }
+   }
+}
+
+void
+check_events (x11_info_t *xinfo, binfo_t *binfo, unsigned n, unsigned n_frames)
+/*
+ *  Check the X11 event loop. If the PAUSE buttonin the of panel 'binfo'
+ *  is activated wait until next event occurs.
+ *  Redraw 'image' if event other then ButtonPress or ButtonRelease occurs.
+ *  Enlarge or reduce size of image by factor 2^'enlarge_factor'.
+ *  'n' gives the current frame, 'whereas' n_frames is the total number of
+ *  frames of the video stream.
+ *
+ *  No return values.
+ *
+ *  Side effects:
+ *	status of buttons (binfo->pressed [button]) is changed accordingly.
+ */
+{
+   bool_t leave_eventloop;
+
+   leave_eventloop = (!binfo->pressed [PAUSE_BUTTON]
+		      && binfo->pressed [PLAY_BUTTON])
+		     || (!binfo->pressed [PAUSE_BUTTON]
+			 && binfo->record_is_rewind
+			 && binfo->pressed [RECORD_BUTTON])
+		     || binfo->pressed [RECORD_BUTTON];
+   draw_progress_bar (xinfo, binfo, n, n_frames);
+
+   if (binfo->pressed [PAUSE_BUTTON] && binfo->pressed [PLAY_BUTTON])
+   {
+      XFlush (xinfo->display);
+      draw_button (xinfo, binfo, PLAY_BUTTON, NO); /* clear PLAY mode */
+      XFlush (xinfo->display);
+   }
+   if (binfo->pressed [PAUSE_BUTTON]
+       && binfo->record_is_rewind && binfo->pressed [RECORD_BUTTON])
+   {
+      XFlush (xinfo->display);
+      draw_button (xinfo, binfo, RECORD_BUTTON, NO); /* clear PLAY mode */
+      XFlush (xinfo->display);
+   }
+
+   if (binfo->pressed [STOP_BUTTON])
+   {
+      XFlush (xinfo->display);
+      draw_button (xinfo, binfo, STOP_BUTTON, NO); /* clear STOP button */
+      XFlush (xinfo->display);
+   }
+
+   do
+   {
+      XEvent event;
+      int    button;
+      bool_t wait_release = NO;
+	 
+      
+      if (XCheckMaskEvent (xinfo->display, EVENT_MASK, &event))
+      {
+	 switch (event.type)
+	 {
+	    case ButtonPress:
+	       wait_release = NO;
+	       if (!(binfo->pressed [RECORD_BUTTON] &&
+		     !binfo->record_is_rewind))
+		  for (button = 0; button < NO_BUTTON; button++)
+		  {
+		     int x0, y0, x1, y1; /* button coordinates */
+		  
+		     x0 = button * (binfo->width / NO_BUTTON);
+		     y0 = binfo->progbar_height;
+		     x1 = x0 + binfo->width / NO_BUTTON;
+		     y1 = y0 + binfo->height - binfo->progbar_height - 1;
+		     if (event.xbutton.x > x0 && event.xbutton.x < x1
+			 && event.xbutton.y > y0 && event.xbutton.y < y1) 
+		     {
+			draw_button (xinfo, binfo, button,
+				     !binfo->pressed [button]);
+			wait_release = YES;
+			break;
+		     }
+		  }
+	       break;
+	    case ButtonRelease:
+	       wait_release = NO;
+	       break;
+	    default:
+	       wait_release = NO;
+	       draw_control_panel (xinfo, binfo, n, n_frames);
+	       display_image (0, 0, xinfo);
+	       break;
+	 }
+	 leave_eventloop = !wait_release
+			   && (binfo->pressed [PLAY_BUTTON]
+			       || binfo->pressed [STOP_BUTTON]
+			       || binfo->pressed [RECORD_BUTTON]
+			       || binfo->pressed [QUIT_BUTTON]);
+      }
+   } while (!leave_eventloop);
+
+   if ((binfo->pressed [RECORD_BUTTON] && !binfo->record_is_rewind)
+       && n == n_frames - 1)
+   {
+      binfo->record_is_rewind = YES;
+      draw_button (xinfo, binfo, RECORD_BUTTON, NO);
+   }
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+draw_control_panel (x11_info_t *xinfo, binfo_t *binfo,
+		    unsigned n, unsigned n_frames)
+/*
+ *  Draw control panel 'binfo' with all buttons and progressbar in
+ *  the given 'window'.
+ *  'n' gives the current frame, 'whereas' n_frames is the total number of
+ *  frames of the video stream.
+ *
+ *  No return value.
+ */
+{
+   buttons_t button;
+   
+   XFillRectangle (xinfo->display, binfo->window, binfo->gc [NGRAY],
+		   0, 0, binfo->width, binfo->height);
+   draw_progress_bar (xinfo, binfo, n, n_frames);
+   for (button = 0; button < NO_BUTTON; button++)
+      draw_button (xinfo, binfo, button, binfo->pressed [button]);
+}
+
+static void
+draw_progress_bar (x11_info_t *xinfo, binfo_t *binfo, unsigned n,
+		   unsigned n_frames)
+/*
+ *  Draw progressbar of control panel 'binfo' in the given 'window'.
+ *  'n' gives the current frame, whereas 'n_frames' is the total number of
+ *  frames of the video stream.
+ *
+ *  No return value.
+ */
+{
+   unsigned x, y, width, height;
+
+   x 	  = 2;
+   y 	  = 1;
+   width  = binfo->width - 5;
+   height = binfo->progbar_height - 3;
+   
+   XDrawLine (xinfo->display, binfo->window, binfo->gc [DGRAY],
+	      x, y, x + width, y);
+   XDrawLine (xinfo->display, binfo->window, binfo->gc [DGRAY],
+	      x, y, x, y + height - 1);
+   XDrawLine (xinfo->display, binfo->window, binfo->gc [LGRAY],
+	      x + width, y + 1, x + width, y + height);
+   XDrawLine (xinfo->display, binfo->window, binfo->gc [LGRAY],
+	      x, y + height, x + width, y + height);
+
+   x++; y++; width  -= 2; height -= 2;
+   XFillRectangle (xinfo->display, binfo->window, binfo->gc [NGRAY],
+		   x, y, width, height);
+
+   XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK],
+		   x + n * max (1, width / n_frames), y,
+		   max (1, width / n_frames), height);
+}
+
+static void
+draw_button (x11_info_t *xinfo, binfo_t *binfo,
+	     buttons_t button, bool_t pressed)
+/*
+ *  Draw 'button' of control panel 'binfo' in the given 'window'.
+ *  'pressed' indicates whether the button is pressed or not.
+ *
+ *  No return value.
+ */
+{
+   grayscale_t top, bottom;		/* index of GC */
+   unsigned    x, y, width, height;	/* coordinates of button */
+   
+   x 	  = button * (binfo->width / NO_BUTTON);
+   y 	  = binfo->progbar_height;
+   width  = binfo->width / NO_BUTTON;
+   height = binfo->height - binfo->progbar_height - 1;
+   
+   if (width < 4 || height < 4)
+      return;
+   
+   if (pressed)
+   {
+      top    = DGRAY;
+      bottom = LGRAY;
+   }
+   else
+   {
+      top    = LGRAY;
+      bottom = DGRAY;
+   }
+
+   x 	 += 2;
+   width -= 4;
+   
+   XDrawLine (xinfo->display, binfo->window, binfo->gc [top],
+	      x, y, x + width, y);
+   XDrawLine (xinfo->display, binfo->window, binfo->gc [top],
+	      x, y, x, y + height - 1);
+   XDrawLine (xinfo->display, binfo->window, binfo->gc [bottom],
+	      x + width, y + 1, x + width, y + height);
+   XDrawLine (xinfo->display, binfo->window, binfo->gc [bottom],
+	      x, y + height, x + width, y + height);
+
+   x++; y++; width  -= 2; height -= 2;
+   XFillRectangle (xinfo->display, binfo->window, binfo->gc [NGRAY],
+		   x, y, width, height);
+
+   switch (button)
+   {
+      case STOP_BUTTON:
+	 XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK],
+			 x + width / 2 - 6, y + height / 2 - 4, 11, 11);
+	 if (pressed && !binfo->pressed [STOP_BUTTON])
+	 {
+	    draw_button (xinfo, binfo, PLAY_BUTTON, NO);
+	    draw_button (xinfo, binfo, PAUSE_BUTTON, NO); 
+	    draw_button (xinfo, binfo, RECORD_BUTTON, NO); 
+	 }
+	 break;
+      case PAUSE_BUTTON:
+	 XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK],
+			 x + width / 2 - 6, y + height / 2 - 4, 5, 11);
+	 XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK],
+			 x + width / 2 + 1, y + height / 2 - 4, 5, 11);
+	 break;
+      case PLAY_BUTTON:
+	 {
+	    XPoint triangle [3];
+
+	    triangle [0].x = x + width / 2 - 5;
+	    triangle [0].y = y + height / 2 - 5;
+	    triangle [1].x = 10;
+	    triangle [1].y = 6;
+	    triangle [2].x = -10;
+	    triangle [2].y = 6;
+
+	    XFillPolygon (xinfo->display, binfo->window, binfo->gc [BLACK],
+			  triangle, 3, Convex, CoordModePrevious);
+	    if (pressed && !binfo->pressed [PLAY_BUTTON]
+		&& binfo->pressed [RECORD_BUTTON])
+	       draw_button (xinfo, binfo, RECORD_BUTTON, NO);
+	 }
+	 break;
+      case RECORD_BUTTON:
+	 if (!binfo->record_is_rewind)
+	 {
+	    XFillArc (xinfo->display, binfo->window, binfo->gc [RED],
+		      x + width / 2 - 5, y + height / 2 - 5, 11, 11, 0,
+		      360 * 64);
+	    if (pressed && !binfo->pressed [RECORD_BUTTON])
+	    {
+	       draw_button (xinfo, binfo, STOP_BUTTON, YES);
+	       draw_button (xinfo, binfo, PLAY_BUTTON, NO);
+	       draw_button (xinfo, binfo, PAUSE_BUTTON, NO); 
+	    }
+	 }
+	 else
+	 {
+	    XPoint triangle [3];
+
+	    triangle [0].x = x + width / 2 + 5;
+	    triangle [0].y = y + height / 2 - 5;
+	    triangle [1].x = -10;
+	    triangle [1].y = 6;
+	    triangle [2].x = 10;
+	    triangle [2].y = 6;
+
+	    XFillPolygon (xinfo->display, binfo->window, binfo->gc [BLACK],
+			  triangle, 3, Convex, CoordModePrevious);
+	    if (pressed && !binfo->pressed [RECORD_BUTTON]
+		&& binfo->pressed [PLAY_BUTTON])
+	       draw_button (xinfo, binfo, PLAY_BUTTON, NO);
+	 }
+	 break;
+      case QUIT_BUTTON:
+	 {
+	    XPoint triangle [3];
+
+	    triangle [0].x = x + width / 2 - 6;
+	    triangle [0].y = y + height / 2 + 2;
+	    triangle [1].x = 6;
+	    triangle [1].y = -7;
+	    triangle [2].x = 6;
+	    triangle [2].y = 7;
+
+	    XFillPolygon (xinfo->display, binfo->window, binfo->gc [BLACK],
+			  triangle, 3, Convex, CoordModePrevious);
+	    XFillRectangle (xinfo->display, binfo->window, binfo->gc [BLACK],
+			    x + width / 2 - 5, y + height / 2 + 4, 11, 3);
+	 }
+	 break;
+      default:
+	 break;
+   }
+   binfo->pressed [button] = pressed;
+}
+
+#endif /* not X_DISPLAY_MISSING */
diff --git a/converter/other/fiasco/buttons.h b/converter/other/fiasco/buttons.h
new file mode 100644
index 00000000..a09f3423
--- /dev/null
+++ b/converter/other/fiasco/buttons.h
@@ -0,0 +1,50 @@
+/*
+ *  buttons.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:51:17 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _BUTTONS_H
+#define _BUTTONS_H
+
+#ifndef X_DISPLAY_MISSING
+
+typedef enum grayscale_e {BLACK, NGRAY, LGRAY, DGRAY, RED,
+			  THICKBLACK, NO_GC} grayscale_t;
+typedef enum buttons_e {STOP_BUTTON, PLAY_BUTTON, PAUSE_BUTTON, RECORD_BUTTON,
+			QUIT_BUTTON, NO_BUTTON} buttons_t;
+
+typedef struct buttoninfo
+{
+   Window   window;
+   bool_t   pressed [NO_BUTTON];
+   GC	    gc [NO_GC];
+   unsigned width;
+   unsigned height;
+   unsigned progbar_height;
+   bool_t   record_is_rewind;
+} binfo_t;
+
+void
+check_events (x11_info_t *xinfo, binfo_t *binfo, unsigned n,
+	      unsigned n_frames);
+void
+wait_for_input (x11_info_t *xinfo);
+binfo_t * 
+init_buttons (x11_info_t *xinfo, unsigned n, unsigned n_frames,
+	      unsigned buttons_height, unsigned progbar_height);
+
+#endif /* not X_DISPLAY_MISSING */
+
+#endif /* not _BUTTONS_H */
+
diff --git a/converter/other/fiasco/codec/Makefile b/converter/other/fiasco/codec/Makefile
new file mode 100644
index 00000000..9a9d502a
--- /dev/null
+++ b/converter/other/fiasco/codec/Makefile
@@ -0,0 +1,27 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../../..
+  BUILDDIR = $(SRCDIR)
+endif
+FIASCOSUBDIR = converter/other/fiasco
+SUBDIR = $(FIASCOSUBDIR)/codec
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \
+	 -I$(SRCDIR)/$(FIASCOSUBDIR)/input -I$(SRCDIR)/$(FIASCOSUBDIR)/output 
+
+OBJECTS =  approx.o bintree.o coder.o coeff.o \
+           control.o decoder.o dfiasco.o domain-pool.o ip.o motion.o mwfa.o \
+           options.o prediction.o subdivide.o tiling.o wfalib.o
+
+MERGE_OBJECTS = $(OBJECTS)
+
+all: libfiasco_codec.a
+
+include $(SRCDIR)/Makefile.common
+
+libfiasco_codec.a: $(OBJECTS)
+	$(AR) -rc $@ $(OBJECTS)
+	$(RANLIB) $@
+
diff --git a/converter/other/fiasco/codec/approx.c b/converter/other/fiasco/codec/approx.c
new file mode 100644
index 00000000..72e38cbf
--- /dev/null
+++ b/converter/other/fiasco/codec/approx.c
@@ -0,0 +1,702 @@
+/*
+ *  approx.c:		Approximation of range images with matching pursuit
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include <math.h>
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "cwfa.h"
+#include "ip.h"
+#include "rpf.h"
+#include "domain-pool.h"
+#include "misc.h"
+#include "list.h"
+#include "approx.h"
+#include "coeff.h"
+#include "wfalib.h"
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+typedef struct mp
+{
+   word_t exclude [MAXEDGES];
+   word_t indices [MAXEDGES + 1];
+   word_t into [MAXEDGES + 1];
+   real_t weight [MAXEDGES];
+   real_t matrix_bits;
+   real_t weights_bits;
+   real_t err;
+   real_t costs;
+} mp_t;
+
+/*****************************************************************************
+
+			     prototypes
+  
+*****************************************************************************/
+
+static void
+orthogonalize (unsigned index, unsigned n, unsigned level, real_t min_norm,
+	       const word_t *domain_blocks, const coding_t *c);
+static void 
+matching_pursuit (mp_t *mp, bool_t full_search, real_t price,
+		  unsigned max_edges, int y_state, const range_t *range,
+		  const domain_pool_t *domain_pool, const coeff_t *coeff,
+		  const wfa_t *wfa, const coding_t *c);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+real_t 
+approximate_range (real_t max_costs, real_t price, int max_edges,
+		   int y_state, range_t *range, domain_pool_t *domain_pool,
+		   coeff_t *coeff, const wfa_t *wfa, const coding_t *c)
+/*
+ *  Approximate image block 'range' by matching pursuit. This functions
+ *  calls the matching pursuit algorithm several times (with different
+ *  parameters) in order to find the best approximation. Refer to function
+ *  'matching_pursuit()' for more details about parameters.
+ *
+ *  Return value:
+ *	approximation costs
+ */
+{
+   mp_t	  mp;
+   bool_t success = NO;
+
+   /*
+    *  First approximation attempt: default matching pursuit algorithm.
+    */
+   mp.exclude [0] = NO_EDGE;
+   matching_pursuit (&mp, c->options.full_search, price, max_edges,
+		     y_state, range, domain_pool, coeff, wfa, c);
+
+   /*
+    *  Next approximation attempt: remove domain block mp->indices [0]
+    *  from domain pool (vector with smallest costs) and run the
+    *  matching pursuit again.
+    */
+   if (c->options.second_domain_block)
+   {
+      mp_t tmp_mp = mp;
+      
+      tmp_mp.exclude [0] = tmp_mp.indices [0];
+      tmp_mp.exclude [1] = NO_EDGE;
+	    
+      matching_pursuit (&tmp_mp, c->options.full_search, price, max_edges,
+			y_state, range, domain_pool, coeff, wfa, c);
+      if (tmp_mp.costs < mp.costs)	/* success */
+      {
+	 success = YES;
+	 mp      = tmp_mp;
+      }
+   }
+
+   /*
+    *  Next approximation attempt: check whether some coefficients have
+    *  been quantized to zero. Vectors causing the underflow are
+    *  removed from the domain pool and then the matching pursuit
+    *  algorithm is run again (until underflow doesn't occur anymore).
+    */
+   if (c->options.check_for_underflow)
+   {
+      int  iteration = -1;
+      mp_t tmp_mp    = mp;
+      
+      do
+      {
+	 int i;
+ 
+	 iteration++;
+	 tmp_mp.exclude [iteration] = NO_EDGE;
+	 
+	 for (i = 0; isdomain (tmp_mp.indices [i]); i++)
+	    if (tmp_mp.weight [i] == 0)
+	    {
+	       tmp_mp.exclude [iteration] = tmp_mp.indices [i];
+	       break;
+	    }
+      
+	 if (isdomain (tmp_mp.exclude [iteration])) /* try again */
+	 {
+	    tmp_mp.exclude [iteration + 1] = NO_EDGE;
+	    
+	    matching_pursuit (&tmp_mp, c->options.full_search, price,
+			      max_edges, y_state, range, domain_pool,
+			      coeff, wfa, c);
+	    if (tmp_mp.costs < mp.costs)	/* success */
+	    {
+	       success = YES;
+	       mp      = tmp_mp;
+	    }
+	 }
+      } while (isdomain (tmp_mp.exclude [iteration])
+	       && iteration < MAXEDGES - 1);
+   }
+
+   /*
+    *  Next approximation attempt: check whether some coefficients have
+    *  been quantized to +/- max-value. Vectors causing the overflow are
+    *  removed from the domain pool and then the matching pursuit
+    *  algorithm is run again (until overflow doesn't occur anymore).
+    */
+   if (c->options.check_for_overflow)
+   {
+      int  iteration = -1;
+      mp_t tmp_mp    = mp;
+      
+      do
+      {
+	 int i;
+ 
+	 iteration++;
+	 tmp_mp.exclude [iteration] = NO_EDGE;
+	 
+	 for (i = 0; isdomain (tmp_mp.indices [i]); i++)
+	 {
+	    rpf_t *rpf = tmp_mp.indices [i] ? coeff->rpf : coeff->dc_rpf;
+	    
+	    if (tmp_mp.weight [i] == btor (rtob (200, rpf), rpf)
+		|| tmp_mp.weight [i] == btor (rtob (-200, rpf), rpf))
+	    {
+	       tmp_mp.exclude [iteration] = tmp_mp.indices [i];
+	       break;
+	    }
+	 }
+      
+	 if (isdomain (tmp_mp.exclude [iteration])) /* try again */
+	 {
+	    tmp_mp.exclude [iteration + 1] = NO_EDGE;
+	    
+	    matching_pursuit (&tmp_mp, c->options.full_search, price,
+			      max_edges, y_state, range, domain_pool,
+			      coeff, wfa, c);
+	    if (tmp_mp.costs < mp.costs)	/* success */
+	    {
+	       success = YES;
+	       mp      = tmp_mp;
+	    }
+	 }
+      } while (isdomain (tmp_mp.exclude [iteration])
+	       && iteration < MAXEDGES - 1);
+   }
+
+   /*
+    *  Finally, check whether the best approximation has costs
+    *  smaller than 'max_costs'.
+    */
+   if (mp.costs < max_costs) 
+   {
+      int    edge;
+      bool_t overflow  = NO;
+      bool_t underflow = NO;
+      int    new_index, old_index;
+
+      new_index = 0;
+      for (old_index = 0; isdomain (mp.indices [old_index]); old_index++)
+	 if (mp.weight [old_index] != 0)
+	 {
+	    rpf_t *rpf = mp.indices [old_index] ? coeff->rpf : coeff->dc_rpf;
+	    
+	    if (mp.weight [old_index] == btor (rtob (200, rpf), rpf)
+		|| mp.weight [old_index] == btor (rtob (-200, rpf), rpf))
+	       overflow = YES;
+	    
+	    mp.indices [new_index] = mp.indices [old_index];
+	    mp.into [new_index]    = mp.into [old_index];
+	    mp.weight [new_index]  = mp.weight [old_index];
+	    new_index++;
+	 }
+	 else
+	    underflow = YES;
+      
+      mp.indices [new_index] = NO_EDGE;
+      mp.into  [new_index]   = NO_EDGE;
+
+      /*
+       *  Update of probability models
+       */
+      {
+	 word_t *domain_blocks = domain_pool->generate (range->level, y_state,
+							wfa,
+							domain_pool->model);
+	 domain_pool->update (domain_blocks, mp.indices,
+			      range->level, y_state, wfa, domain_pool->model);
+	 coeff->update (mp.weight, mp.into, range->level, coeff);
+	 
+	 Free (domain_blocks);
+      }
+      
+      for (edge = 0; isedge (mp.indices [edge]); edge++)
+      {
+	 range->into [edge]   = mp.into [edge];
+	 range->weight [edge] = mp.weight [edge];
+      }
+      range->into [edge]  = NO_EDGE;
+      range->matrix_bits  = mp.matrix_bits;
+      range->weights_bits = mp.weights_bits;
+      range->err          = mp.err;
+   }
+   else
+   {
+      range->into [0] = NO_EDGE;
+      mp.costs	      = MAXCOSTS;
+   }
+   
+   return mp.costs;
+}
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+static real_t norm_ortho_vector [MAXSTATES];     
+/*
+ *  Square-norm of the i-th vector of the orthogonal basis (OB)
+ *  ||o_i||^2; i = 0, ... ,n
+ */
+static real_t ip_image_ortho_vector [MAXEDGES];
+/* 
+ *  Inner product between the i-th vector of the OB and the given range: 
+ *  <b, o_i>; i = 0, ... ,n 
+ */
+static real_t ip_domain_ortho_vector [MAXSTATES][MAXEDGES];
+/* 
+ *  Inner product between the i-th vector of the OB and the image of domain j: 
+ *  <s_j, o_i>; j = 0, ... , wfa->states; i = 0, ... ,n, 
+ */
+static real_t rem_denominator [MAXSTATES];     
+static real_t rem_numerator [MAXSTATES];
+/*
+ *  At step n of the orthogonalization the comparitive value
+ *  (numerator_i / denominator_i):= <b, o_n>^2 / ||o_n|| ,
+ *  is computed for every domain i,
+ *  where o_n := s_i - \sum(k = 0, ... , n-1) {(<s_i, o_k> / ||o_k||^2) o_k}
+ *  To avoid computing the same values over and over again,
+ *  the constant (remaining) parts of every domain are
+ *  stored in 'rem_numerator' and 'rem_denominator' separately
+ */
+static bool_t used [MAXSTATES];    
+/*
+ *  Shows whether a domain image was already used in a
+ *  linear combination (YES) or not (NO)
+ */
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void 
+matching_pursuit (mp_t *mp, bool_t full_search, real_t price,
+		  unsigned max_edges, int y_state, const range_t *range,
+		  const domain_pool_t *domain_pool, const coeff_t *coeff,
+		  const wfa_t *wfa, const coding_t *c)
+/*
+ *  Find an approximation of the current 'range' with a linear
+ *  combination of vectors of the 'domain_pool'. The linear
+ *  combination is generated step by step with the matching pursuit
+ *  algorithm.  If flag 'full_search' is set then compute complete set
+ *  of linear combinations with n = {0, ..., 'max_edges'} vectors and
+ *  return the best one. Otherwise abort the computation as soon as
+ *  costs (LC (n + 1)) exceed costs ( LC (n)) and return the
+ *  sub-optimal solution.  'price' is the langrange multiplier
+ *  weighting rate and distortion.  'band' is the current color band
+ *  and 'y_state' the corresponding state in the Y component at same
+ *  pixel position.  'domain_pool' gives the set of available vectors,
+ *  and 'coeff' the model for the linear factors. The number of
+ *  elements in the linear combination is limited by 'max_edges'. In
+ *  'mp', vectors may be specified which should be excluded during the
+ *  approximation.
+ *  
+ *  No return value.
+ *
+ *  Side effects:
+ *	vectors, factors, rate, distortion and costs are stored in 'mp'
+ */
+{
+   unsigned	 n;			/* current vector of the OB */
+   int		 index;			/* best fitting domain image */
+   unsigned	 domain;		/* counter */
+   real_t	 norm;			/* norm of range image */
+   real_t	 additional_bits;	/* bits for mc, nd, and tree */
+   word_t	*domain_blocks;		/* current set of domain images */
+   const real_t  min_norm = 2e-3;	/* lower bound of norm */
+   unsigned 	 best_n   = 0;
+   unsigned	 size 	  = size_of_level (range->level);
+ 
+   /*
+    *  Initialize domain pool and inner product arrays
+    */
+   domain_blocks = domain_pool->generate (range->level, y_state, wfa,
+					  domain_pool->model);
+   for (domain = 0; domain_blocks [domain] >= 0; domain++)
+   {
+      used [domain] = NO;
+      rem_denominator [domain]		/* norm of domain */
+	 = get_ip_state_state (domain_blocks [domain], domain_blocks [domain],
+			       range->level, c);
+      if (rem_denominator [domain] / size < min_norm)
+	 used [domain] = YES;		/* don't use domains with small norm */
+      else
+	 rem_numerator [domain]		/* inner product <s_domain, b> */
+	    = get_ip_image_state (range->image, range->address,
+				  range->level, domain_blocks [domain], c);
+      if (!used [domain] && fabs (rem_numerator [domain]) < min_norm)
+	 used [domain] = YES;
+   }
+
+   /*
+    *  Exclude all domain blocks given in array 'mp->exclude'
+    */
+   for (n = 0; isdomain (mp->exclude [n]); n++)
+      used [mp->exclude [n]] = YES;
+
+   /*
+    *  Compute the approximation costs if 'range' is approximated with
+    *  no linear combination, i.e. the error is equal to the square
+    *  of the image norm and the size of the automaton is determined by
+    *  storing only zero elements in the current matrix row
+    */
+   for (norm = 0, n = 0; n < size; n++)
+      norm += square (c->pixels [range->address * size + n]);
+
+   additional_bits = range->tree_bits + range->mv_tree_bits
+		     + range->mv_coord_bits + range->nd_tree_bits
+		     + range->nd_weights_bits;
+
+   mp->err          = norm;
+   mp->weights_bits = 0;
+   mp->matrix_bits  = domain_pool->bits (domain_blocks, NULL, range->level,
+					 y_state, wfa, domain_pool->model);
+   mp->costs        = (mp->matrix_bits + mp->weights_bits
+		       + additional_bits) * price + mp->err;
+
+   n = 0;
+   do 
+   {
+      /*
+       *  Current approximation is: b = d_0 o_0 + ... + d_(n-1) o_(n-1)
+       *  with corresponding costs 'range->err + range->bits * p'.
+       *  For all remaining state images s_i (used[s_i] == NO) set
+       *  o_n :	= s_i - \sum(k = 0, ... , n-1) {(<s_i, o_k> / ||o_k||^2) o_k}
+       *  and try to beat current costs.
+       *  Choose that vector for the next orthogonalization step,
+       *  which has minimal costs: s_index.
+       *  (No progress is indicated by index == -1)
+       */
+      
+      real_t min_matrix_bits  = 0;
+      real_t min_weights_bits = 0;
+      real_t min_error 	      = 0;
+      real_t min_weight [MAXEDGES];
+      real_t min_costs = full_search ? MAXCOSTS : mp->costs;
+      
+      for (index = -1, domain = 0; domain_blocks [domain] >= 0; domain++) 
+	 if (!used [domain]) 
+	 {
+	    real_t    matrix_bits, weights_bits;
+	    /*
+	     *  To speed up the search through the domain images,
+	     *  the costs of using domain image 'domain' as next vector
+	     *  can be approximated in a first step:
+	     *  improvement of image quality
+	     *	  <= square (rem_numerator[domain]) / rem_denominator[domain]
+	     */
+	    {
+		  word_t   vectors [MAXEDGES + 1];
+		  word_t   states [MAXEDGES + 1];
+		  real_t   weights [MAXEDGES + 1];
+		  unsigned i, k;
+		  
+		  for (i = 0, k = 0; k < n; k++)
+		     if (mp->weight [k] != 0)
+		     {
+			vectors [i] = mp->indices [k];
+			states [i]  = domain_blocks [vectors [i]];
+			weights [i] = mp->weight [k];
+			i++;
+		     }
+		  vectors [i] 	  = domain;
+		  states [i]  	  = domain_blocks [domain];
+		  weights [i] 	  = 0.5;
+		  vectors [i + 1] = -1;
+		  states [i + 1]  = -1;
+
+		  weights_bits = coeff->bits (weights, states, range->level,
+					      coeff);
+		  matrix_bits = domain_pool->bits (domain_blocks, vectors,
+						   range->level, y_state,
+						   wfa, domain_pool->model);
+	    }
+	    if (((matrix_bits + weights_bits + additional_bits) * price +
+		 mp->err -
+		 square (rem_numerator [domain]) / rem_denominator [domain])
+		< min_costs)
+	    {
+	       /*
+		*  1.) Compute the weights (linear factors) c_i of the
+		*  linear combination
+		*  b = c_0 v_0 + ... + c_(n-1) v_(n-1) + c_n v_'domain'
+		*  Use backward substitution to obtain c_i from the linear
+		*  factors of the lin. comb. b = d_0 o_0 + ... + d_n o_n
+		*  of the corresponding orthogonal vectors {o_0, ..., o_n}.
+		*  Vector o_n of the orthogonal basis is obtained by using
+		*  vector 'v_domain' in step n of the Gram Schmidt
+		*  orthogonalization (see above for definition of o_n).
+		*  Recursive formula for the coefficients c_i:
+		*  c_n := <b, o_n> / ||o_n||^2
+		*  for i = n - 1, ... , 0:
+		*  c_i := <b, o_i> / ||o_i||^2 +
+		*          \sum (k = i + 1, ... , n){ c_k <v_k, o_i>
+		*					/ ||o_i||^2 }
+		*  2.) Because linear factors are stored with reduced precision
+		*  factor c_i is rounded with the given precision in step i
+		*  of the recursive formula. 
+		*/
+
+	       unsigned k;		/* counter */
+	       int    	l;		/* counter */
+	       real_t 	m_bits;		/* number of matrix bits to store */
+	       real_t 	w_bits;		/* number of weights bits to store */
+	       real_t 	r [MAXEDGES];	/* rounded linear factors */
+	       real_t 	f [MAXEDGES];	/* linear factors */
+	       int    	v [MAXEDGES];	/* mapping of domains to vectors */
+	       real_t 	costs;		/* current approximation costs */
+	       real_t 	m_err;		/* current approximation error */
+
+	       f [n] = rem_numerator [domain] / rem_denominator [domain];
+	       v [n] = domain;		/* corresponding mapping */
+	       for (k = 0; k < n; k++)
+	       {
+		  f [k] = ip_image_ortho_vector [k] / norm_ortho_vector [k];
+		  v [k] = mp->indices [k];
+	       }
+	    
+	       for (l = n; l >= 0; l--) 
+	       {
+		  rpf_t *rpf = domain_blocks [v [l]]
+			       ? coeff->rpf : coeff->dc_rpf;
+
+		  r [l] = f [l] = btor (rtob (f [l], rpf), rpf);
+		     
+		  for (k = 0; k < (unsigned) l; k++)
+		     f [k] -= f [l] * ip_domain_ortho_vector [v [l]][k]
+			      / norm_ortho_vector [k] ;
+	       } 
+
+	       /*
+		*  Compute the number of output bits of the linear combination
+		*  and store the weights with reduced precision. The
+		*  resulting linear combination is
+		*  b = r_0 v_0 + ... + r_(n-1) v_(n-1) + r_n v_'domain'
+		*/
+	       {
+		  word_t vectors [MAXEDGES + 1];
+		  word_t states [MAXEDGES + 1];
+		  real_t weights [MAXEDGES + 1];
+		  int	 i;
+		  
+		  for (i = 0, k = 0; k <= n; k++)
+		     if (f [k] != 0)
+		     {
+			vectors [i] = v [k];
+			states [i]  = domain_blocks [v [k]];
+			weights [i] = f [k];
+			i++;
+		     }
+		  vectors [i] = -1;
+		  states [i]  = -1;
+
+		  w_bits = coeff->bits (weights, states, range->level, coeff);
+		  m_bits = domain_pool->bits (domain_blocks, vectors,
+					      range->level, y_state,
+					      wfa, domain_pool->model);
+	       }
+	       
+	       /*
+		*  To compute the approximation error, the corresponding
+		*  linear factors of the linear combination 
+		*  b = r_0 o_0 + ... + r_(n-1) o_(n-1) + r_n o_'domain'
+		*  with orthogonal vectors must be computed with following
+		*  formula:
+		*  r_i := r_i +
+		*          \sum (k = i + 1, ... , n) { r_k <v_k, o_i>
+		*					/ ||o_i||^2 }
+		*/
+	       for (l = 0; (unsigned) l <= n; l++)
+	       {
+		  /*
+		   *  compute <v_n, o_n>
+		   */
+		  real_t a;
+
+		  a = get_ip_state_state (domain_blocks [v [l]],
+					  domain_blocks [domain],
+					  range->level, c);
+		  for (k = 0; k < n; k++) 
+		     a -= ip_domain_ortho_vector [v [l]][k]
+			  / norm_ortho_vector [k]
+			  * ip_domain_ortho_vector [domain][k];
+		  ip_domain_ortho_vector [v [l]][n] = a;
+	       }
+	       norm_ortho_vector [n]     = rem_denominator [domain];
+	       ip_image_ortho_vector [n] = rem_numerator [domain];
+ 	    
+	       for (k = 0; k <= n; k++)
+		  for (l = k + 1; (unsigned) l <= n; l++)
+		     r [k] += ip_domain_ortho_vector [v [l]][k] * r [l]
+			      / norm_ortho_vector [k];
+	       /*
+		*  Compute approximation error:
+		*  error := ||b||^2 +
+		*  \sum (k = 0, ... , n){r_k^2 ||o_k||^2 - 2 r_k <b, o_k>}
+		*/
+	       m_err = norm;
+	       for (k = 0; k <= n; k++)
+		  m_err += square (r [k]) * norm_ortho_vector [k]
+			 - 2 * r [k] * ip_image_ortho_vector [k];
+	       if (m_err < 0)		/* TODO: return MAXCOSTS */
+		  warning ("Negative image norm: %f"
+			   " (current domain: %d, level = %d)",
+			   (double) m_err, domain, range->level);
+
+	       costs = (m_bits + w_bits + additional_bits) * price + m_err;
+	       if (costs < min_costs)	/* found a better approximation */
+	       {
+		  index            = domain;
+		  min_costs        = costs;
+		  min_matrix_bits  = m_bits;
+		  min_weights_bits = w_bits;
+		  min_error        = m_err;
+		  for (k = 0; k <= n; k++)
+		     min_weight [k] = f [k];
+	       }
+	    }
+	 }
+      
+      if (index >= 0)			/* found a better approximation */
+      {
+	 if (min_costs < mp->costs)
+	 {
+	    unsigned k;
+	    
+	    mp->costs        = min_costs;
+	    mp->err          = min_error;
+	    mp->matrix_bits  = min_matrix_bits;
+	    mp->weights_bits = min_weights_bits;
+	    
+	    for (k = 0; k <= n; k++)
+	       mp->weight [k] = min_weight [k];
+
+	    best_n = n + 1;
+	 }
+	 
+	 mp->indices [n] = index;
+	 mp->into [n]    = domain_blocks [index];
+
+	 used [index] = YES;
+
+	 /* 
+	  *  Gram-Schmidt orthogonalization step n 
+	  */
+	 orthogonalize (index, n, range->level, min_norm, domain_blocks, c);
+	 n++;
+      }	
+   } 
+   while (n < max_edges && index >= 0);
+
+   mp->indices [best_n] = NO_EDGE;
+   
+   mp->costs = (mp->matrix_bits + mp->weights_bits + additional_bits) * price
+	       + mp->err;
+
+   Free (domain_blocks);
+}
+
+static void
+orthogonalize (unsigned index, unsigned n, unsigned level, real_t min_norm,
+	       const word_t *domain_blocks, const coding_t *c)
+/*
+ *  Step 'n' of the Gram-Schmidt orthogonalization procedure:
+ *  vector 'index' is orthogonalized with respect to the set
+ *  {u_[0], ... , u_['n' - 1]}. The size of the image blocks is given by
+ *  'level'. If the denominator gets smaller than 'min_norm' then
+ *  the corresponding domain is excluded from the list of available
+ *  domain blocks.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	The remainder values (numerator and denominator) of
+ *	all 'domain_blocks' are updated. 
+ */
+{
+   unsigned domain;
+   
+   ip_image_ortho_vector [n] = rem_numerator [index];
+   norm_ortho_vector [n]     = rem_denominator [index];
+
+   /*
+    *  Compute inner products between all domain images and 
+    *  vector n of the orthogonal basis:
+    *  for (i = 0, ... , wfa->states)  
+    *  <s_i, o_n> := <s_i, v_n> -
+    *      \sum (k = 0, ... , n - 1){ <v_n, o_k> <s_i, o_k> / ||o_k||^2}
+    *  Moreover the denominator and numerator parts of the comparitive
+    *  value are updated.
+    */
+   for (domain = 0; domain_blocks [domain] >= 0; domain++) 
+      if (!used [domain]) 
+      {
+	 unsigned k;
+	 real_t   tmp = get_ip_state_state (domain_blocks [index],
+					    domain_blocks [domain], level, c);
+	 
+	 for (k = 0; k < n; k++) 
+	    tmp -= ip_domain_ortho_vector [domain][k] / norm_ortho_vector [k]
+		   * ip_domain_ortho_vector [index][k];
+	 ip_domain_ortho_vector [domain][n] = tmp;
+	 rem_denominator [domain] -= square (tmp) / norm_ortho_vector [n];
+	 rem_numerator [domain]   -= ip_image_ortho_vector [n]
+				     / norm_ortho_vector [n]
+				     * ip_domain_ortho_vector [domain][n] ;
+
+	 /*
+	  *  Exclude vectors with small denominator
+	  */
+	 if (!used [domain]) 
+	    if (rem_denominator [domain] / size_of_level (level) < min_norm) 
+	       used [domain] = YES;
+      }
+}
+
+
+
diff --git a/converter/other/fiasco/codec/approx.h b/converter/other/fiasco/codec/approx.h
new file mode 100644
index 00000000..c54b78c9
--- /dev/null
+++ b/converter/other/fiasco/codec/approx.h
@@ -0,0 +1,30 @@
+/*
+ *  approx.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _APPROX_H
+#define _APPROX_H
+
+#include "types.h"
+#include "cwfa.h"
+#include "domain-pool.h"
+
+real_t 
+approximate_range (real_t max_costs, real_t price, int max_edges,
+		   int y_state, range_t *range, domain_pool_t *domain_pool,
+		   coeff_t *coeff, const wfa_t *wfa, const coding_t *c);
+
+#endif /* not _APPROX_H */
+
diff --git a/converter/other/fiasco/codec/bintree.c b/converter/other/fiasco/codec/bintree.c
new file mode 100644
index 00000000..ddd74e15
--- /dev/null
+++ b/converter/other/fiasco/codec/bintree.c
@@ -0,0 +1,94 @@
+/*
+ *  bintree.c:		Bintree model of WFA tree	
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include <math.h>
+
+#include "bintree.h"
+#include "misc.h"
+#include "cwfa.h"
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+tree_update (bool_t child, unsigned level, tree_t *model)
+/*
+ *  Update tree model of given 'level'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	tree model is changed.
+ */
+{
+   if (!child)
+      model->total [level]++;
+   else
+   {
+      model->counts [level]++;
+      model->total [level]++;
+   }
+}
+
+real_t
+tree_bits (bool_t child, unsigned level, const tree_t *model)
+/*
+ *  Compute number of bits needed for coding element 'child' of the bintree.
+ *  For each 'level' a different context is used.
+ *
+ *  Return value:
+ *	# bits
+ */
+{
+   real_t prob = model->counts [level] / (real_t) model->total [level];
+
+   return child ? - log2 (prob) : - log2 (1 - prob);
+}
+
+void
+init_tree_model (tree_t *tree_model)
+/*
+ *  Initialize the model for the tree.
+ *  Symbol RANGE is synonymous with the '0' symbol and
+ *  symbol NO_RANGE is synonymous with the '1' symbol of the binary coder.
+ *  The 'count' array counts the number of NO_RANGE symbols.
+ *
+ *  No return value.
+ */
+{
+   unsigned level;
+   unsigned counts_0 [MAXLEVEL] = {20, 17, 15, 10, 5,  4,  3,
+				   2,  1,  1,  1,  1,  1,  1,  1,
+				   1,  1,  1,  1 , 1,  1,  1};
+   unsigned counts_1 [MAXLEVEL] = {1 , 1,  1,  1,  1,  1,  1,
+				   1,  1,  2,  3,  5,  10, 15, 20,
+				   25, 30, 35, 60, 60, 60, 60};
+   
+   for (level = 0; level < MAXLEVEL ; level++) 
+   {
+      tree_model->counts [level] = counts_1 [level];
+      tree_model->total [level]  = counts_0 [level] + counts_1 [level];
+   }
+}
diff --git a/converter/other/fiasco/codec/bintree.h b/converter/other/fiasco/codec/bintree.h
new file mode 100644
index 00000000..cdb80c94
--- /dev/null
+++ b/converter/other/fiasco/codec/bintree.h
@@ -0,0 +1,43 @@
+/*
+ *  bintree.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _BINTREE_H
+#define _BINTREE_H
+
+#include "wfa.h"
+#include "types.h"
+
+typedef struct tree
+/*
+ *  Used for estimating the number of bits needed for storing the
+ *  tree array. For each level a different context is used.
+ *  The binary alphabet consists of the two symbols NO_RANGE and RANGE,
+ *  which indicate whether there exists a tree edge or not.
+ */
+{
+   unsigned counts [MAXLEVEL];		/* # NO_RANGE symbols at given level */
+   unsigned total [MAXLEVEL];		/* total number of symbols at  ''   */
+} tree_t;
+
+real_t
+tree_bits (bool_t child, unsigned level, const tree_t *model);
+void
+init_tree_model (tree_t *tree_model);
+void
+tree_update (bool_t child, unsigned level, tree_t *model);
+
+#endif /* not _BINTREE_H */
+
diff --git a/converter/other/fiasco/codec/coder.c b/converter/other/fiasco/codec/coder.c
new file mode 100644
index 00000000..df878d87
--- /dev/null
+++ b/converter/other/fiasco/codec/coder.c
@@ -0,0 +1,965 @@
+/*
+ *  coder.c:		WFA coder toplevel functions
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include "config.h"
+#include "pnm.h"
+
+#include <math.h>
+#include <ctype.h>
+
+#include <string.h>
+
+#include "nstring.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "fiasco.h"
+
+#include "cwfa.h"
+#include "misc.h"
+#include "control.h"
+#include "bintree.h"
+#include "subdivide.h"
+#include "read.h"
+#include "write.h"
+#include "image.h"
+#include "mwfa.h"
+#include "list.h"
+#include "decoder.h"
+#include "motion.h"
+#include "wfalib.h"
+#include "domain-pool.h"
+#include "coeff.h"
+#include "coder.h"
+#include "rpf.h"
+
+/*****************************************************************************
+
+				global variables
+  
+*****************************************************************************/
+
+const real_t MAXCOSTS =	1e20;
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static coding_t *
+alloc_coder (char const * const *inputname, const c_options_t *options,
+	     wfa_info_t *wi);
+static void
+free_coder (coding_t *c);
+static char *
+get_input_image_name (char const * const *templptr, unsigned ith_image);
+static void
+video_coder (char const * const *image_template, bitfile_t *output,
+	     wfa_t *wfa, coding_t *c);
+static void 
+frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output);
+static void
+print_statistics (char c, real_t costs, const wfa_t *wfa, const image_t *image,
+		  const range_t *range);
+static frame_type_e
+pattern2type (unsigned frame, const char *pattern);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+int
+fiasco_coder (char const * const *inputname, const char *outputname,
+	      float quality, const fiasco_c_options_t *options)
+/*
+ *  FIASCO coder.
+ *  Encode image or video frames given by the array of filenames `inputname'
+ *  and write to the outputfile `outputname'.
+ *  If 'inputname' = NULL or
+ *     'inputname [0]' == NULL or
+ *     'inputname [0]' == "-", read standard input.
+ *  If 'outputname' == NULL or "-", write on standard output.
+ *  'quality' defines the approximation quality and is 1 (worst) to 100 (best).
+ *
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   try
+   {
+      char const * const default_input [] = {"-", NULL};
+      fiasco_c_options_t *default_options = NULL;
+      const c_options_t  *cop;
+      char const * const *template;
+      
+      /*
+       *  Check parameters
+       */
+      if (!inputname || !inputname [0] || streq (inputname [0], "-"))
+	 template = default_input;
+      else
+	 template = inputname;
+      
+      if (quality <= 0)
+      {
+	 set_error (_("Compression quality has to be positive."));
+	 return 0;
+      }
+      else if (quality >= 100)
+      {
+	 warning (_("Quality typically is 1 (worst) to 100 (best).\n"
+		    "Be prepared for a long running time."));
+      }
+
+      if (options)
+      {
+	 cop = cast_c_options ((fiasco_c_options_t *) options);
+	 if (!cop)
+	    return 0;
+      }
+      else
+      {
+	 default_options = fiasco_c_options_new ();
+	 cop 		 = cast_c_options (default_options);
+      }
+
+   /*
+    *  Open output stream and initialize WFA
+    */
+      {
+	 bitfile_t *output = open_bitfile (outputname, "FIASCO_DATA",
+					   WRITE_ACCESS);
+	 if (!output)
+	 {
+	    set_error (_("Can't write outputfile `%s'.\n%s"),
+		       outputname ? outputname : "<stdout>",
+		       get_system_error ());
+	    if (default_options)
+	       fiasco_c_options_delete (default_options);
+	    return 0;
+	 }
+	 else
+	 {
+	    wfa_t    *wfa = alloc_wfa (YES);
+	    coding_t *c   = alloc_coder (template, cop, wfa->wfainfo);
+	 
+	    read_basis (cop->basis_name, wfa);
+	    append_basis_states (wfa->basis_states, wfa, c);
+	 
+	    c->price = 128 * 64 / quality;
+	 
+	    video_coder (template, output, wfa, c);
+	 
+	    close_bitfile (output);
+	    free_wfa (wfa);
+	    free_coder (c);
+	 
+	    if (default_options)
+	       fiasco_c_options_delete (default_options);
+	 }
+      }
+      return 1;
+   }
+   catch
+   {
+      return 0;
+   }
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static coding_t *
+alloc_coder (char const * const *inputname, const c_options_t *options,
+	     wfa_info_t *wi)
+/*
+ *  Coder structure constructor.
+ *  Allocate memory for the FIASCO coder structure and
+ *  fill in default values specified by 'options'.
+ *
+ *  Return value:
+ *	pointer to the new coder structure or NULL on error
+ */
+{
+   coding_t *c = NULL;
+   
+   /*
+    *  Check whether all specified image frames are readable and of same type
+    */
+   {
+      char     *filename;
+      int   	width, w = 0, height, h = 0;
+      bool_t	color, c = NO;
+      unsigned 	n;
+      
+      for (n = 0; (filename = get_input_image_name (inputname, n)); n++)
+      {
+          FILE *file;
+          xelval maxval;
+          int format;
+          if (filename == NULL)
+              file = stdin;
+          else
+              file = pm_openr(filename);
+          pnm_readpnminit(file, &width, &height, &maxval, &format);
+          color = (PNM_FORMAT_TYPE(format) == PPM_FORMAT) ? TRUE: FALSE;
+
+          pm_close(file);
+	 if (n)
+	 {
+	    if (w != width || h != height || c != color)
+	    {
+	       set_error (_("Format of image frame `%s' doesn't match."),
+			  filename ? filename : "<stdin>");
+	       return NULL;
+	    }
+	 }
+	 else
+	 {
+	    w = width;
+	    h = height;
+	    c = color;
+	 }
+	 Free (filename);
+      }
+      wi->frames = n;
+      wi->width  = w;
+      wi->height = h;
+      wi->color  = c;
+   }
+
+   /*
+    *  Levels ...
+    */
+   {
+      unsigned lx, ly;
+      
+      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);
+   }
+   
+   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->tiling = alloc_tiling (options->tiling_method,
+			     options->tiling_exponent, wi->level);
+
+   if (wi->frames > 1 && c->tiling->exponent > 0)
+   {
+      c->tiling->exponent = 0;
+      warning (_("Image tiling valid only with still image compression."));
+   }
+
+   if (c->options.lc_max_level >= wi->level - c->tiling->exponent)
+   {
+      message ("'max_level' changed from %d to %d due to 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;
+   }
+   
+   if (c->options.lc_min_level > c->options.lc_max_level)
+      c->options.lc_min_level = c->options.lc_max_level;
+   
+   /*
+    *  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);
+   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->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 *));
+   c->ip_images_state = Calloc (MAXSTATES, sizeof (real_t *));
+   c->ip_states_state = Calloc (MAXSTATES * MAXLEVEL, sizeof (real_t *));
+   
+   debug_message ("Imageslevel :%d, Productslevel :%d",
+		  c->options.images_level, c->products_level);
+   debug_message ("Memory : (%d + %d + %d * 'states') * 'states' + %d",
+		  size_of_tree (c->options.images_level) * 4,
+		  size_of_tree (c->products_level) * 4,
+		  (c->options.lc_max_level - c->options.images_level),
+		  size_of_level (c->options.lc_max_level));
+   
+   /*
+    *  Domain pools ...
+    */
+   c->domain_pool   = NULL;
+   c->d_domain_pool = NULL;
+
+   /*
+    *  Coefficients model ...
+    */
+   c->coeff   = NULL;
+   c->d_coeff = NULL;
+
+   /*
+    *  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);
+
+   /*
+    *  Title and comment strings
+    */
+   wi->title   = strdup (options->title);
+   wi->comment = strdup (options->comment);
+   
+   /*
+    *  Reduced precision format
+    */
+   wi->rpf
+      = alloc_rpf (options->rpf_mantissa, options->rpf_range);
+   wi->dc_rpf
+      = alloc_rpf (options->dc_rpf_mantissa, options->dc_rpf_range);
+   wi->d_rpf
+      = alloc_rpf (options->d_rpf_mantissa, options->d_rpf_range);
+   wi->d_dc_rpf
+      = alloc_rpf (options->d_dc_rpf_mantissa, options->d_dc_rpf_range);
+   
+   /*
+    *  Color image options ...
+    */
+   wi->chroma_max_states = max (1, options->chroma_max_states);
+
+   /*
+    *  Set up motion compensation struct.
+    *  p_min_level, p_max_level are also used for ND prediction
+    */
+   wi->search_range   = options->search_range;
+   wi->fps 	      = options->fps;
+   wi->half_pixel     = options->half_pixel_prediction;
+   wi->cross_B_search = options->half_pixel_prediction;
+   wi->B_as_past_ref  = options->B_as_past_ref;
+   wi->smoothing      = options->smoothing;
+   
+   c->mt = alloc_motion (wi);
+
+   return c;
+}
+
+static void
+free_coder (coding_t *c)
+/*
+ *  Coder struct destructor:
+ *  Free memory of 'coder' struct.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	structure 'coder' is discarded.
+ */
+{
+   free_tiling (c->tiling);
+   free_motion (c->mt);
+   
+   Free (c->pixels);
+   Free (c->images_of_state);
+   Free (c->ip_images_state);
+   Free (c->ip_states_state);
+   Free (c);
+}
+
+static char *
+get_input_image_name (char const * const *templptr, unsigned ith_image)
+/*
+ *  Construct the i-th image-name using templates.
+ *  If the template contains a '[' it must be of the form
+ *  "prefix[start-end{+,-}step]suffix"
+ *  where "{+,-}step" is optional.
+ *  Leading zeros of "start" are significant.
+ *
+ *  Example:
+ *   "image0[12-01-1].pgm" yields image012.pgm, image011.pgm, ..., image001.pgm
+ *
+ *  Return value:
+ *      ptr to name of image 'ith_image' or NULL if ith_image is out of range.
+ */
+{
+   while (*templptr)
+   {
+      const char *template = *templptr++;
+      char       *s;
+
+      if (!(s = strchr (template, '['))) /* no template, just a filename */
+      {
+	 if (ith_image == 0)
+	    return strdup (template);
+	 else
+	    ith_image--;
+      }
+      else				/* template parser */
+      {
+	 unsigned  n_digits;		/* # of digits in image name no. */
+	 char 	  *s2;
+	 char 	  *suffix;		/* characters after template end */
+	 char  	   prefix [MAXSTRLEN];	/* chars up to the template start */
+	 unsigned  first;		/* first image number */
+	 unsigned  last;		/* last image number */
+	 int  	   image_num;		/* current image number */
+	 int   	   increment = 1;
+	 int 	   dummy;
+
+	 strcpy (prefix, template);
+	 prefix [s - template] = '\0';
+   
+	 for (s2 = ++s, n_digits = 0; ISDIGIT (*s2); s2++, n_digits++)
+	    ;
+	 if (sscanf (s, "%d", &dummy) == 0 || dummy < 0)
+	    error ("Input name template conversion failure.\n"
+		   "Check spelling of template.");
+	 first = (unsigned) dummy;
+	 
+	 if (*s2++ != '-')
+	    error ("Input name template conversion failure.\n"
+		   "Check spelling of template.");
+   
+	 for (s = s2; ISDIGIT (*s2); s2++)
+	    ;
+	 if (sscanf (s, "%d", &dummy) == 0 || dummy < 0)
+	    error ("Input name template conversion failure.\n"
+		   "Check spelling of template.");
+	 last = (unsigned) dummy;
+	 
+	 if (*s2 == '+' || *s2 == '-') 
+	 {
+	    for (s = s2++; ISDIGIT (*s2); s2++)
+	       ;
+	    if (sscanf (s, "%d", &increment) == 0)
+	       error ("Input name template conversion failure.\n"
+		      "Check spelling of template.");
+	 } 	 
+	 if (*s2 != ']')
+	    error ("Input name template conversion failure.\n"
+		   "Check spelling of template.");
+	 suffix = s2 + 1;
+   
+	 image_num = first + increment * ith_image;
+	 if (image_num < 0)
+	    error ("Input name template conversion failure.\n"
+		   "Check spelling of template.");
+	 
+	 if ((increment >  0 && (unsigned) image_num > last) || 
+	     (increment <= 0 && (unsigned) image_num < last))
+	 {
+	    /* TODO: check this */
+	    ith_image -= (last - first) / increment + 1;
+	 }
+	 else
+	 {
+	    char formatstr [MAXSTRLEN]; /* format string for image filename */
+	    char image_name [MAXSTRLEN]; /* image file name to be composed */
+	    
+	    strcpy (formatstr, "%s%0?d%s");
+	    formatstr [4] = '0' + (char) n_digits;
+	    sprintf (image_name, formatstr, prefix, image_num, suffix);
+	    return strdup (image_name);
+	 }
+      }
+   }
+   return NULL;
+}	
+
+static void
+video_coder (char const * const *image_template, bitfile_t *output,
+	     wfa_t *wfa, coding_t *c)
+/*
+ *  Toplevel function to encode a sequence of video frames specified
+ *  by 'image_template'. The output is written to stream 'output'.
+ *  Coding options are given by 'c'.
+ *
+ *  No return value.
+ */
+{
+   unsigned  display;			/* picture number in display order */
+   int	     future_display;		/* number of future reference */
+   int	     frame;			/* current frame number */
+   char	    *image_name;		/* image name of current frame */
+   image_t  *reconst 	  = NULL; 	/* decoded reference image */
+   bool_t    future_frame = NO;		/* YES if last frame was in future */
+   
+   debug_message ("Generating %d WFA's ...", wfa->wfainfo->frames);
+
+   future_display = -1;
+   frame          = -1;
+   display        = 0;
+
+   while ((image_name = get_input_image_name (image_template, display)))
+   {
+      frame_type_e type;		/* current frame type: I, B, P */
+      
+      /*
+       *  Determine type of next frame.
+       *  Skip already coded frames (future reference!)
+       */
+      if (display == 0 && !c->options.reference_filename)
+	 type = I_FRAME;		/* Force first frame to be intra */
+      else
+	 type = pattern2type (display, c->options.pattern);
+      
+      if (type != I_FRAME && c->options.reference_filename)
+	 /* Load reference from disk */
+      {
+	 debug_message ("Reading reference frame `%s'.",
+			c->options.reference_filename);
+	 reconst 	 = read_image (c->options.reference_filename);
+	 c->options.reference_filename = NULL;
+      }
+      if ((int) display == future_display) /* Skip already coded future ref */
+      {				
+	 display++;
+	 continue;
+      }	  
+      else if (type == B_FRAME && (int) display > future_display) 
+      {
+	 unsigned i = display;
+	 /*
+	  *  Search for future reference
+	  */
+	 while (type == B_FRAME)
+	 {
+	    char *name;			/* image name of future frame */
+
+	    i++;
+	    name = get_input_image_name (image_template, i);
+	    
+	    if (!name)			/* Force last valid frame to be 'P' */
+	    {
+	       future_display = i - 1;
+	       type = P_FRAME;
+	    }
+	    else
+	    {
+	       future_display = i;    
+	       image_name     = name;
+	       type 	      = pattern2type (i, c->options.pattern);
+	    }
+	    frame = future_display;
+	 }
+      }
+      else
+      {
+	 frame = display;
+	 display++;
+      }
+
+      debug_message ("Coding \'%s\' [%c-frame].", image_name,
+		     type == I_FRAME ? 'I' : (type == P_FRAME ? 'P' : 'B'));
+       
+      /*
+       *  Depending on current frame type update past and future frames
+       *  which are needed as reference frames.
+       */
+      c->mt->frame_type = type;
+      if (type == I_FRAME)
+      {
+	 if (c->mt->past)		/* discard past frame */
+	    free_image (c->mt->past);
+	 c->mt->past = NULL;
+	 if (c->mt->future)		/* discard future frame */
+	    free_image (c->mt->future);
+	 c->mt->future = NULL;
+	 if (reconst)			/* discard current frame */
+	    free_image (reconst);
+	 reconst = NULL;
+      }
+      else if (type == P_FRAME)
+      {
+	 if (c->mt->past)		/* discard past frame */
+	    free_image (c->mt->past);
+	 c->mt->past = reconst;		/* past frame <- current frame */
+	 reconst    = NULL;
+	 if (c->mt->future)		/* discard future frame */
+	    free_image (c->mt->future);
+	 c->mt->future = NULL;
+      }
+      else				/* B_FRAME */
+      {
+	 if (future_frame)		/* last frame was future frame */
+	 {
+	    if (c->mt->future)		/* discard future frame */
+	       free_image (c->mt->future);
+	    c->mt->future = reconst;	/* future frame <- current frame */
+	    reconst      = NULL;
+	 }
+	 else
+	 {
+	    if (wfa->wfainfo->B_as_past_ref == YES)
+	    {
+	       if (c->mt->past)		/* discard past frame */
+		  free_image (c->mt->past);
+	       c->mt->past = reconst;	/* past frame <- current frame */
+	       reconst    = NULL;
+	    }
+	    else
+	    {
+	       if (reconst)		/* discard current frame */
+		  free_image (reconst);
+	       reconst = NULL;
+	    }
+	 }
+      }
+
+      /*
+       *  Start WFA coding of current frame
+       */
+      future_frame   = frame == future_display;
+      c->mt->number   = frame;
+      c->mt->original = read_image (image_name);
+      if (c->tiling->exponent && type == I_FRAME) 
+	 perform_tiling (c->mt->original, c->tiling);
+
+      frame_coder (wfa, c, output);
+
+      /*
+       *  Regenerate image:
+       *  1. Compute approximation of WFA ranges (real image bintree order)
+       *  2. Generate byte image in rasterscan order
+       *  3. Apply motion compensation
+       */
+      reconst = decode_image (wfa->wfainfo->width, wfa->wfainfo->height,
+			      FORMAT_4_4_4, NULL, wfa);
+
+      if (type != I_FRAME)
+	 restore_mc (0, reconst, c->mt->past, c->mt->future, wfa);
+
+      if (c->mt->original)
+	 free_image (c->mt->original);
+      c->mt->original = NULL;
+      
+      remove_states (wfa->basis_states, wfa); /* Clear WFA structure */
+   }
+
+   if (reconst)
+      free_image (reconst);
+   if (c->mt->future)
+      free_image (c->mt->future);
+   if (c->mt->past)
+      free_image (c->mt->past);
+   if (c->mt->original)
+      free_image (c->mt->original);
+}
+
+static frame_type_e
+pattern2type (unsigned frame, const char *pattern)
+{
+    int tmp = TOUPPER (pattern [frame % strlen (pattern)]);
+    frame_type_e retval;
+
+    switch (tmp)
+    {
+    case 'I':
+        retval = I_FRAME;
+        break;
+    case 'B':
+        retval = B_FRAME;
+        break;
+    case 'P':
+        retval = P_FRAME;
+        break;
+    default:
+        error ("Frame type %c not valid. Choose one of I,B or P.", tmp);
+    }
+    return retval;
+}
+
+static void 
+frame_coder (wfa_t *wfa, coding_t *c, bitfile_t *output)
+/*
+ * 
+ *  WFA Coding of next frame.  All important coding parameters are
+ *  stored in 'c'.  The generated 'wfa' is written to stream 'output'
+ *  immediately after coding.
+ *
+ *  No return value.
+ */
+{
+   unsigned state;
+   range_t  range;			/* first range == the entire image */
+   real_t   costs;			/* total costs (minimized quantity) */
+   unsigned bits;			/* number of bits written on disk */
+   clock_t  ptimer;
+   
+   prg_timer (&ptimer, START);
+
+   bits = bits_processed (output);
+   
+   init_tree_model (&c->tree);
+   init_tree_model (&c->p_tree);
+
+   c->domain_pool
+      = alloc_domain_pool (c->options.id_domain_pool,
+			   wfa->wfainfo->max_states,
+			   c->options.max_elements, wfa);
+   c->d_domain_pool
+      = alloc_domain_pool ((c->options.prediction
+			    || c->mt->frame_type != I_FRAME)
+			   ? c->options.id_d_domain_pool : "constant",
+			   wfa->wfainfo->max_states,
+			   c->options.max_elements, wfa);
+
+   c->coeff   = alloc_coeff_model (c->options.id_rpf_model,
+				   wfa->wfainfo->rpf,
+				   wfa->wfainfo->dc_rpf,
+				   c->options.lc_min_level,
+				   c->options.lc_max_level);
+   c->d_coeff = alloc_coeff_model (c->options.id_d_rpf_model,
+				   wfa->wfainfo->d_rpf,
+				   wfa->wfainfo->d_dc_rpf,
+				   c->options.lc_min_level,
+				   c->options.lc_max_level);
+
+   if (!c->mt->original->color)		/* grayscale image */
+   {
+      memset (&range, 0, sizeof (range_t));
+      range.level = wfa->wfainfo->level;
+
+      costs = subdivide (MAXCOSTS, GRAY, RANGE, &range, wfa, c,
+			 c->options.prediction || c->mt->frame_type != I_FRAME,
+			 NO);
+      if (c->options.progress_meter != FIASCO_PROGRESS_NONE)
+	 message ("");
+
+      if (isrange (range.tree))		/* entire image is approx. by lc? */
+	 error ("No root state generated!");
+      else
+	 wfa->root_state = range.tree;
+
+      print_statistics ('\0', costs, wfa, c->mt->original, &range);
+   }
+   else
+   {
+      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;
+	       
+	       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'};
+	    
+	    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 (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 (*) 
+       *
+       *              *
+       *            /   \
+       *           +     *
+       *          / \   /  
+       *         Y   CbCr 
+       */
+      wfa->tree [wfa->states][0] = tree[Cr];
+      wfa->tree [wfa->states][1] = RANGE;
+      append_state (YES, compute_final_distribution (wfa->states, wfa),
+		    wfa->wfainfo->level + 1, wfa, c);
+      wfa->tree[wfa->states][0] = YCb_node;
+      wfa->tree[wfa->states][1] = wfa->states - 1;
+      append_state (YES, compute_final_distribution (wfa->states, wfa),
+		    wfa->wfainfo->level + 2, wfa, c);
+
+      wfa->root_state = wfa->states - 1;
+   }
+
+   for (state = wfa->basis_states; state < MAXSTATES; state++)
+   {
+      unsigned level;
+      
+      if (c->images_of_state [state])
+      {
+	 Free (c->images_of_state [state]);
+	 c->images_of_state [state] = NULL;
+      }
+      if (c->ip_images_state [state])
+      {
+	 Free (c->ip_images_state [state]);
+	 c->ip_images_state [state] = NULL;
+      }
+      for (level = c->options.images_level + 1;
+	   level <= c->options.lc_max_level;
+	   level++)
+	 if (c->ip_states_state [state][level])
+	 {
+	    Free (c->ip_states_state [state][level]);
+	    c->ip_states_state [state][level] = NULL;
+	 }
+      
+   }
+   
+   locate_delta_images (wfa);
+   write_next_wfa (wfa, c, output);
+   
+   bits = bits_processed (output) - bits;
+   debug_message ("Total number of bits written: %d (%d bytes, %5.3f bpp)",
+		  bits, bits >> 3,
+		  bits / (double) (c->mt->original->height
+				   * c->mt->original->width));
+   debug_message ("Total encoding time (real): %d sec",
+		  prg_timer (&ptimer, STOP) / 1000);
+
+   c->domain_pool->free (c->domain_pool);
+   c->d_domain_pool->free (c->d_domain_pool);
+
+   c->coeff->free (c->coeff);
+   c->d_coeff->free (c->d_coeff);
+}
+
+static void
+print_statistics (char c, real_t costs, const wfa_t *wfa, const image_t *image,
+		  const range_t *range)
+{
+   unsigned max_level, min_level, state, label, lincomb;
+   
+   for (max_level = 0, min_level = MAXLEVEL, state = wfa->basis_states;
+	state < wfa->states; state++)
+   {
+      for (lincomb = 0, label = 0; label < MAXLABELS; label++)
+	 lincomb += isrange(wfa->tree[state][label]) ? 1 : 0;
+	 
+      if (lincomb)
+      {
+	 max_level = max (max_level,
+			  (unsigned) (wfa->level_of_state [state] - 1));
+	 min_level = min (min_level,
+			  (unsigned) (wfa->level_of_state [state] - 1));
+      }
+   }
+   debug_message ("Image partitioning: maximum level %d , minimum level %d",
+		  max_level, min_level);
+   debug_message ("WFA contains %d states (%d basis states).",
+		  wfa->states, wfa->basis_states);
+   debug_message ("Estimated error: %.2f (RMSE: %.2f, PSNR: %.2f dB).",
+		  (double) range->err,
+		  sqrt (range->err / image->width / image->height),
+		  10 * log ( 255.0 * 255.0 /
+			     (range->err / image->width / image->height))
+		  / log (10.0));
+   debug_message ("Estimated filesize: %.0f bits (%.0f bytes).",
+		  (double) (range->tree_bits + range->matrix_bits
+			    + range->weights_bits
+			    + range->mv_tree_bits + range->mv_coord_bits
+			    + range->nd_tree_bits + range->nd_weights_bits),
+		  (double) (range->tree_bits + range->matrix_bits
+			    + range->weights_bits + range->mv_tree_bits
+			    + range->mv_coord_bits + range->nd_tree_bits
+			    + range->nd_weights_bits) / 8);
+   if (c)
+      debug_message ("(%cT: %.0f, %cM: %.0f, %cW: %.0f, %cMC: %.0f, "
+		     "%cMV: %.0f, %cNT: %.0f, %cNW: %.0f.)",
+		     c, (double) range->tree_bits,
+		     c, (double) range->matrix_bits,
+		     c, (double) range->weights_bits,
+		     c, (double) range->mv_tree_bits,
+		     c, (double) range->mv_coord_bits,
+		     c, (double) range->nd_tree_bits,
+		     c, (double) range->nd_weights_bits);
+   else
+      debug_message ("(T: %.0f, M: %.0f, W: %.0f, MC: %.0f, MV: %.0f, "
+		     "NT: %.0f, NW: %.0f.)",
+		     (double) range->tree_bits,
+		     (double) range->matrix_bits,
+		     (double) range->weights_bits,
+		     (double) range->mv_tree_bits,
+		     (double) range->mv_coord_bits,
+		     (double) range->nd_tree_bits,
+		     (double) range->nd_weights_bits);
+   debug_message ("Total costs : %.2f", (double) costs);
+}
diff --git a/converter/other/fiasco/codec/coder.h b/converter/other/fiasco/codec/coder.h
new file mode 100644
index 00000000..c6f4bb7c
--- /dev/null
+++ b/converter/other/fiasco/codec/coder.h
@@ -0,0 +1,24 @@
+/*
+ *  coder.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _CODER_H
+#define _CODER_H
+
+#include "types.h"
+#include "cwfa.h"
+
+#endif /* not _CODER_H */
+
diff --git a/converter/other/fiasco/codec/coeff.c b/converter/other/fiasco/codec/coeff.c
new file mode 100644
index 00000000..0cd64f17
--- /dev/null
+++ b/converter/other/fiasco/codec/coeff.c
@@ -0,0 +1,369 @@
+/*
+ *  coeff.c:		Matching pursuit coefficients probability model
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include <string.h>
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "rpf.h"
+#include "misc.h"
+#include "coeff.h"
+
+/*
+ *  Coefficient model interface:
+ *  Implementing the coefficients model interface requires the
+ *  following steps: 
+ *  - Add a constructor that initializes the coeff_t structure
+ *  - Allocate new model with default_alloc() 
+ *  - Fill the c_array_t coeff_models[] array with constructor and name
+ *  - Write code for methods bits() and update()
+ *  - Either use default functions for remaining methods or override them
+ *  The new model is automatically registered at the command line.
+ */
+
+/*****************************************************************************
+		  uniform distribution coefficients model
+*****************************************************************************/
+
+static coeff_t *
+alloc_uniform_coeff_model (rpf_t *rpf, rpf_t *dc_rpf,
+			   unsigned min_level, unsigned max_level);
+static void
+uniform_update (const real_t *used_coeff, const word_t *used_states,
+		unsigned level, coeff_t *coeff);
+static real_t
+uniform_bits (const real_t *used_coeff, const word_t *used_states,
+	      unsigned level, const coeff_t *coeff);
+
+/*****************************************************************************
+			  default functions
+*****************************************************************************/
+
+static void
+default_model_free (void *model);
+static void *
+default_model_duplicate (const coeff_t *coeff, const void *model);
+static void
+default_free (coeff_t *coeff);
+static coeff_t *
+default_alloc (rpf_t *rpf, rpf_t *dc_rpf,
+	       unsigned min_level, unsigned max_level);
+
+/*****************************************************************************
+		adaptive arithmetic coding model
+*****************************************************************************/
+
+static coeff_t *
+alloc_aac_coeff_model (rpf_t *rpf, rpf_t *dc_rpf,
+		       unsigned min_level, unsigned max_level);
+static void
+aac_model_free (void *model);
+static void *
+aac_model_alloc (const coeff_t *coeff);
+static void *
+aac_model_duplicate (const coeff_t *coeff, const void *model);
+static void
+aac_update (const real_t *used_coeff, const word_t *used_states,
+	    unsigned level, coeff_t *coeff);
+static real_t
+aac_bits (const real_t *used_coeff, const word_t *used_states,
+	  unsigned level, const coeff_t *coeff);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+typedef struct c_array
+{
+   const char *identifier;
+   coeff_t    *(*function) (rpf_t *rpf, rpf_t *dc_rpf,
+			    unsigned min_level, unsigned max_level);
+} c_array_t;
+
+c_array_t coeff_models[] = {{"adaptive", alloc_aac_coeff_model},
+			    {"uniform",	 alloc_uniform_coeff_model},
+			    {NULL,	 NULL}};
+
+coeff_t *
+alloc_coeff_model (const char *coeff_model_name, rpf_t *rpf, rpf_t *dc_rpf,
+		   unsigned min_level, unsigned max_level)
+/*
+ *  Allocate a new coefficients model which is identified by the string
+ *  'coeff_model_name'.  'rpf' and 'dc_rpf' define the reduced
+ *  precision formats the should be used to quantize normal and DC
+ *  components, respectively. 'min_level' and 'max_level' define the
+ *  range of range approximations.
+ * 
+ *  Return value:
+ *	pointer to the allocated coefficients model
+ *
+ *  Note:
+ *      Refer to 'coeff.h' for a short description of the member functions.  */
+{
+   unsigned n;
+   
+   for (n = 0; coeff_models [n].identifier; n++) /* step through all id's */
+      if (strcaseeq (coeff_models [n].identifier, coeff_model_name)) 
+	 return coeff_models [n].function (rpf, dc_rpf, min_level, max_level);
+
+   warning ("Can't initialize coefficients model '%s'. "
+	    "Using default value '%s'.",
+	    coeff_model_name, coeff_models [0].identifier);
+
+   return coeff_models [0].function (rpf, dc_rpf, min_level, max_level);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+/*****************************************************************************
+		  uniform distribution coefficients model
+*****************************************************************************/
+
+static coeff_t *
+alloc_uniform_coeff_model (rpf_t *rpf, rpf_t *dc_rpf,
+			   unsigned min_level, unsigned max_level)
+/*
+ *  Underlying probability model: uniform distribution.
+ *  I.e. each coefficient is written as such with
+ *  (1 + exponent_bits + mantissa_bits) bits.
+ */
+{
+   coeff_t *coeff = default_alloc (rpf, dc_rpf, min_level, max_level);
+
+   coeff->bits   = uniform_bits;
+   coeff->update = uniform_update;
+   
+   return coeff;
+}
+
+static real_t
+uniform_bits (const real_t *used_coeff, const word_t *used_states,
+	      unsigned level, const coeff_t *coeff)
+{
+   unsigned edge;
+   real_t   bits = 0;			/* #bits to store coefficients */
+   
+   for (edge = 0; isedge (used_states [edge]); edge++)
+   {
+      rpf_t *rpf = used_states [edge] ? coeff->rpf : coeff->dc_rpf;
+      
+      bits += rpf->mantissa_bits + 1;
+   }
+
+   return bits;
+}
+
+static void
+uniform_update (const real_t *used_coeff, const word_t *used_states,
+		unsigned level, coeff_t *coeff)
+{
+   return;				/* nothing to do */
+}
+
+/*****************************************************************************
+		adaptive arithmetic coding  model
+*****************************************************************************/
+
+typedef struct aac_model
+{
+   word_t *counts;
+   word_t *totals;
+} aac_model_t;
+
+static coeff_t *
+alloc_aac_coeff_model (rpf_t *rpf, rpf_t *dc_rpf,
+		       unsigned min_level, unsigned max_level)
+/*
+ *  Underlying probability model: adaptive arithmetic coding using
+ *  the level of a range as context.
+ */
+{
+   coeff_t *coeff = default_alloc (rpf, dc_rpf, min_level, max_level);
+   
+   coeff->bits            = aac_bits;
+   coeff->update          = aac_update;
+   coeff->model_free      = aac_model_free;
+   coeff->model_duplicate = aac_model_duplicate;
+   coeff->model		  = aac_model_alloc (coeff);
+   
+   return coeff;
+}
+
+static real_t
+aac_bits (const real_t *used_coeff, const word_t *used_states,
+	  unsigned level, const coeff_t *coeff)
+{
+   real_t	bits  = 0;		/* # bits to store coefficients */
+   unsigned	edge;
+   int		state;
+   word_t      *counts;
+   aac_model_t *model = (aac_model_t *) coeff->model;
+
+   counts = model->counts
+	    + (1 << (1 + coeff->dc_rpf->mantissa_bits))
+	    + ((level - coeff->min_level)
+	       * (1 << (1 + coeff->rpf->mantissa_bits)));
+   
+   for (edge = 0; isedge (state = used_states [edge]); edge++)
+      if (state)
+	 bits -= log2 (counts [rtob (used_coeff [edge], coeff->rpf)]
+		       / (real_t) model->totals [level
+						- coeff->min_level + 1]);
+      else
+	 bits -= log2 (model->counts [rtob (used_coeff [edge], coeff->dc_rpf)]
+		       / (real_t) model->totals [0]);
+   
+   return bits;
+}
+
+static void
+aac_update (const real_t *used_coeff, const word_t *used_states,
+	    unsigned level, coeff_t *coeff)
+{
+   unsigned	edge;
+   int		state;
+   word_t      *counts;
+   aac_model_t *model = (aac_model_t *) coeff->model;
+
+   counts = model->counts
+	    + (1 << (1 + coeff->dc_rpf->mantissa_bits))
+	    + ((level - coeff->min_level)
+	       * (1 << (1 + coeff->rpf->mantissa_bits)));
+
+   for (edge = 0; isedge (state = used_states [edge]); edge++)
+      if (state)
+      {
+	 counts [rtob (used_coeff [edge], coeff->rpf)]++;
+	 model->totals [level - coeff->min_level + 1]++;
+      }
+      else
+      {
+	 model->counts [rtob (used_coeff [edge], coeff->dc_rpf)]++;
+	 model->totals [0]++;
+      }
+}
+
+static void *
+aac_model_duplicate (const coeff_t *coeff, const void *model)
+{
+   aac_model_t *src = (aac_model_t *) model;
+   aac_model_t *dst = aac_model_alloc (coeff);
+
+   memcpy (dst->counts, src->counts,
+	   sizeof (word_t) * ((coeff->max_level - coeff->min_level + 1)
+			      * (1 << (1 + coeff->rpf->mantissa_bits))
+			      + (1 << (1 + coeff->dc_rpf->mantissa_bits))));
+   memcpy (dst->totals, src->totals,
+	   sizeof (word_t) * (coeff->max_level - coeff->min_level + 1 + 1));
+   
+   return dst;
+}
+
+static void *
+aac_model_alloc (const coeff_t *coeff)
+{
+   aac_model_t *model;
+   unsigned	size = (coeff->max_level - coeff->min_level + 1)
+		       * (1 << (1 + coeff->rpf->mantissa_bits))
+		       + (1 << (1 + coeff->dc_rpf->mantissa_bits));
+   
+   model 	 = Calloc (1, sizeof (aac_model_t));
+   model->counts = Calloc (size, sizeof (word_t));
+   model->totals = Calloc (coeff->max_level - coeff->min_level + 1 + 1,
+			   sizeof (word_t));
+   /*
+    *  Initialize model
+    */
+   {
+      unsigned  n;
+      word_t   *ptr = model->counts;
+      
+      for (n = size; n; n--)
+	 *ptr++ = 1;
+      model->totals [0] = 1 << (1 + coeff->dc_rpf->mantissa_bits);
+      for (n = coeff->min_level; n <= coeff->max_level; n++)
+	 model->totals [n - coeff->min_level + 1]
+	    = 1 << (1 + coeff->rpf->mantissa_bits);
+   }
+   
+   return (void *) model;
+}
+
+static void
+aac_model_free (void *model)
+{
+   aac_model_t	*aac_model = (aac_model_t *) model;
+
+   if (aac_model)
+   {
+      Free (aac_model->counts);
+      Free (aac_model->totals);
+      Free (aac_model);
+   }
+}
+
+/*****************************************************************************
+				default functions
+*****************************************************************************/
+
+static coeff_t *
+default_alloc (rpf_t *rpf, rpf_t *dc_rpf,
+	       unsigned min_level, unsigned max_level)
+{
+   coeff_t *coeff = Calloc (1, sizeof (coeff_t));
+
+   coeff->rpf 	      	  = rpf;
+   coeff->dc_rpf       	  = dc_rpf;
+   coeff->min_level	  = min_level;
+   coeff->max_level	  = max_level;
+   coeff->model	      	  = NULL;
+   coeff->bits	      	  = NULL;
+   coeff->update      	  = NULL;
+   coeff->free	      	  = default_free;
+   coeff->model_free  	  = default_model_free;
+   coeff->model_duplicate = default_model_duplicate;
+   
+   return coeff;
+}
+
+static void
+default_free (coeff_t *coeff)
+{
+   coeff->model_free (coeff->model);
+   Free (coeff);
+}
+
+static void *
+default_model_duplicate (const coeff_t *coeff, const void *model)
+{
+   return NULL;
+}
+
+static void
+default_model_free (void *model)
+{
+   if (model)
+      Free (model);
+}
diff --git a/converter/other/fiasco/codec/coeff.h b/converter/other/fiasco/codec/coeff.h
new file mode 100644
index 00000000..118cd0fc
--- /dev/null
+++ b/converter/other/fiasco/codec/coeff.h
@@ -0,0 +1,61 @@
+/*
+ *  coeff.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _COEFF_H
+#define _COEFF_H
+
+#include "types.h"
+#include "rpf.h"
+#include "wfa.h"
+
+typedef struct coeff
+{
+   rpf_t    *rpf;			/* reduced precision format */
+   rpf_t    *dc_rpf;			/* RPF of DC (state 0) component */
+   unsigned min_level, max_level;	/* allocate memory for [min,..,max] */
+   void	    *model;			/* generic pointer to prob. model */
+   real_t (*bits) (const real_t *used_coeff, const word_t *used_domains,
+		   unsigned level, const struct coeff *coeff);
+   /*
+    *  Compute bit-rate of a range approximation with coefficients given by
+    *  -1 terminated list 'used_domains'.
+    */
+   void   (*update) (const real_t *used_coeff, const word_t *used_domains,
+		       unsigned level, struct coeff *coeff);
+   /*
+    *  Update the probability model according to the chosen approximation.
+    *  (given by the -1 terminated list 'used_domains').
+    */
+   void	  (*free) (struct coeff *coeff);
+   /*
+    *  Discard the given coefficients struct.
+    */
+   void   (*model_free) (void *model);
+   /*
+    *  Free given probability model.
+    */
+   void   *(*model_duplicate) (const struct coeff *coeff, const void *model);
+   /*
+    *  Duplicate the given probability model (i.e. alloc and copy).
+    */
+} coeff_t;
+
+coeff_t *
+alloc_coeff_model (const char *coeff_model_name, rpf_t *rpf, rpf_t *dc_rpf,
+		   unsigned min_level, unsigned max_level);
+
+#endif /* not _COEFF_H */
+
diff --git a/converter/other/fiasco/codec/control.c b/converter/other/fiasco/codec/control.c
new file mode 100644
index 00000000..9af9928b
--- /dev/null
+++ b/converter/other/fiasco/codec/control.c
@@ -0,0 +1,276 @@
+/*
+ *  control.c:		Control unit of WFA structure
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#if HAVE_STRING_H
+#	include <string.h>
+#else /* not HAVE_STRING_H */
+#	include <strings.h>
+#endif /* not HAVE_STRING_H */
+ 
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "cwfa.h"
+#include "ip.h"
+#include "misc.h"
+#include "wfalib.h"
+#include "control.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void 
+clear_or_alloc (real_t **ptr, size_t size);
+static void 
+compute_images (unsigned from, unsigned to, const wfa_t *wfa, coding_t *c);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void    
+append_state (bool_t auxiliary_state, real_t final, unsigned level_of_state,
+	      wfa_t *wfa, coding_t *c)
+/*
+ *  Append a 'wfa' state. If 'auxiliary_state' == YES then
+ *  allocate memory for inner products and state images.  'final' is
+ *  the final distribution of the new state. 'level_of_state' is the
+ *  level of the subimage which is represented by this state
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	The WFA information are updated in structure 'wfa'
+ *	State images are computed and inner products are cleared (in 'c')
+ */
+{
+   wfa->final_distribution [wfa->states] = final;
+   wfa->level_of_state [wfa->states]     = level_of_state;
+   
+   if (!auxiliary_state)
+   {
+      unsigned level;
+
+      wfa->domain_type [wfa->states] = USE_DOMAIN_MASK;
+
+      /*
+       *  Allocate memory for inner products and for state images
+       */
+      clear_or_alloc (&c->images_of_state [wfa->states],
+		      size_of_tree (c->options.images_level));
+	 
+      for (level = c->options.images_level + 1;
+	   level <= c->options.lc_max_level; level++)
+	 clear_or_alloc (&c->ip_states_state [wfa->states][level],
+			 wfa->states + 1);
+
+      clear_or_alloc (&c->ip_images_state [wfa->states],
+		      size_of_tree (c->products_level));
+
+      /*
+       *  Compute the images of the current state at level 0,..,'imageslevel'
+       */
+      
+      c->images_of_state [wfa->states][0] = final;
+      compute_images (wfa->states, wfa->states, wfa, c);  
+
+      /*
+       *  Compute the inner products between the current state and the
+       *  old states 0,...,'states'-1
+       */ 
+      
+      compute_ip_states_state (wfa->states, wfa->states, wfa, c);
+   }
+   else
+   {
+      unsigned level;
+      
+      wfa->domain_type [wfa->states] = 0;
+	    
+      /*
+       *  Free the allocated memory
+       */
+      if (c->images_of_state [wfa->states] != NULL)
+      {
+	 Free (c->images_of_state [wfa->states]);
+	 c->images_of_state [wfa->states] = NULL;
+      }
+      for (level = 0; level <= c->options.lc_max_level; level++)
+	 if (c->ip_states_state [wfa->states][level])
+	 {
+	    Free (c->ip_states_state [wfa->states][level]);
+	    c->ip_states_state [wfa->states][level] = NULL;
+	 }
+      if (c->ip_images_state [wfa->states])
+      {
+	 Free (c->ip_images_state [wfa->states]);
+	 c->ip_images_state [wfa->states] = NULL;
+      }
+   }
+   
+   wfa->states++;
+   if (wfa->states >= MAXSTATES) 
+      error ("Maximum number of states reached!");
+}	
+ 
+void 
+append_basis_states (unsigned basis_states, wfa_t *wfa, coding_t *c)
+/*
+ *  Append the WFA basis states 0, ... , ('basis_states' - 1).
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	The WFA information are updated in structure 'wfa'
+ *	State images and inner products are computed (in 'c')
+ */
+{
+   unsigned level, state;
+
+   /*
+    *  Allocate memory
+    */
+
+   for (state = 0; state < basis_states; state++)
+   {
+      clear_or_alloc (&c->images_of_state [state],
+		      size_of_tree (c->options.images_level));
+
+      for (level = c->options.images_level + 1;
+	   level <= c->options.lc_max_level; level++)
+	 clear_or_alloc (&c->ip_states_state [state][level], state + 1);
+
+      clear_or_alloc (&c->ip_images_state [state],
+		      size_of_tree (c->products_level));
+
+      c->images_of_state [state][0] = wfa->final_distribution [state];
+      wfa->level_of_state [state]   = -1;
+   }
+   
+   compute_images (0, basis_states - 1, wfa, c);  
+   compute_ip_states_state (0, basis_states - 1, wfa, c);
+   wfa->states = basis_states;
+   
+   if (wfa->states >= MAXSTATES) 
+      error ("Maximum number of states reached!");
+}	
+ 
+void 
+append_transitions (unsigned state, unsigned label, const real_t *weight,
+		    const word_t *into, wfa_t *wfa)
+/*
+ *  Append the 'wfa' transitions (given by the arrays 'weight' and 'into')
+ *  of the range ('state','label').
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	new 'wfa' edges are appended
+ */
+{
+   unsigned edge;
+
+   wfa->y_column [state][label] = 0;
+   for (edge = 0; isedge (into [edge]); edge++)
+   {
+      append_edge (state, into [edge], weight [edge], label, wfa);
+      if (into [edge] == wfa->y_state [state][label])
+	 wfa->y_column [state][label] = 1;
+   }
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void 
+compute_images (unsigned from, unsigned to, const wfa_t *wfa, coding_t *c)
+/*
+ *  Computes the images of the given states 'from', ... , 'to' 
+ *  at level 0,...,'c->imagelevel'.
+ *  Uses the fact that each state image is a linear combination of state
+ *  images, i.e. s_i := c_0 s_0 + ... + c_i s_i.
+ */
+{
+   unsigned label, level, state;
+   
+   /*
+    *  Compute the images Phi(state)
+    *  #		level = 0
+    *  ##		level = 1
+    *  ####		level = 2
+    *  ########    	level = 3
+    *  ...
+    *  ########...##    level = imageslevel
+    */
+   
+   for (level = 1; level <= c->options.images_level; level++)
+      for (state = from; state <= to; state++)
+	 for (label = 0; label < MAXLABELS; label++)
+	 {
+	    real_t   *dst, *src;
+	    unsigned  edge;
+	    int	      domain;		/* current domain */
+	    
+	    if (ischild (domain = wfa->tree[state][label]))
+	    {
+	       dst = c->images_of_state [state] + address_of_level (level) +
+		     label * size_of_level (level - 1);
+	       src = c->images_of_state [domain]
+		     + address_of_level (level - 1);
+	       memcpy (dst, src, size_of_level (level - 1) * sizeof (real_t));
+	    }
+	    for (edge = 0; isedge (domain = wfa->into[state][label][edge]);
+		 edge++)
+	    {
+	       unsigned n;
+	       real_t 	weight = wfa->weight [state][label][edge];
+	       
+	       dst = c->images_of_state [state] + address_of_level (level) +
+		     label * size_of_level (level - 1);
+	       src = c->images_of_state [domain]
+		     + address_of_level (level - 1);
+		  
+	       for (n = size_of_level (level - 1); n; n--)
+		  *dst++ += *src++ * weight;
+	    }
+	 }
+
+}
+
+static void 
+clear_or_alloc (real_t **ptr, size_t size)
+/*
+ *  if *ptr == NULL 	allocate memory with Calloc 
+ *  otherwise 		fill the real_t-array ptr[] with 0
+ */
+{
+   if (*ptr == NULL) 
+      *ptr = Calloc (size, sizeof (real_t));
+   else 
+      memset (*ptr, 0, size * sizeof (real_t));
+    
+}
diff --git a/converter/other/fiasco/codec/control.h b/converter/other/fiasco/codec/control.h
new file mode 100644
index 00000000..f601d8b8
--- /dev/null
+++ b/converter/other/fiasco/codec/control.h
@@ -0,0 +1,33 @@
+/*
+ *  control.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _CONTROL_H
+#define _CONTROL_H
+
+#include "cwfa.h"
+#include "types.h"
+
+void 
+append_transitions (unsigned state, unsigned label, const real_t *weight,
+		    const word_t *into, wfa_t *wfa);
+void 
+append_basis_states (unsigned basis_states, wfa_t *wfa, coding_t *c);
+void    
+append_state (bool_t auxiliary_state, real_t final, unsigned level_of_state,
+	      wfa_t *wfa, coding_t *c);
+
+#endif /* not _CONTROL_H */
+
diff --git a/converter/other/fiasco/codec/cwfa.h b/converter/other/fiasco/codec/cwfa.h
new file mode 100644
index 00000000..9c4e7fee
--- /dev/null
+++ b/converter/other/fiasco/codec/cwfa.h
@@ -0,0 +1,107 @@
+/*
+ *  cwfa.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/10/28 17:39:30 $
+ *  $Author: hafner $
+ *  $Revision: 5.3 $
+ *  $State: Exp $
+ */
+
+#ifndef _CWFA_H
+#define _CWFA_H
+
+#include "wfa.h"
+#include "types.h"
+#include "tiling.h"
+#include "rpf.h"
+#include "domain-pool.h"
+#include "bintree.h"
+#include "coeff.h"
+#include "list.h"
+#include "wfalib.h"
+#include "options.h"
+
+extern const real_t MAXCOSTS;
+
+typedef struct motion
+{
+   image_t	 *original;		/* Current image */
+   image_t	 *past;			/* Preceeding image */
+   image_t	 *future;		/* Succeeding image */
+   frame_type_e	  frame_type;		/* frame type: B_, P_ I_FRAME */
+   unsigned	  number;		/* display number of frame */
+   real_t        *xbits;		/* # bits for mv x-component */
+   real_t        *ybits;		/* # bits for mv y-component */
+   real_t       **mc_forward_norms; 	/* norms of mcpe */
+   real_t       **mc_backward_norms; 	/* norms of mcpe */
+} motion_t;
+
+typedef struct range
+/*
+ *  Information about current range in the original image.
+ *  Approximation data (error, encoding bits, approximation type and factors
+ *  of the linear combination) are also saved.
+ */ 
+{
+   unsigned global_address;             /* We need absolute image addresses
+				           for distance calculations. */
+   unsigned x, y;			/* Coordinates of upper left corner */
+   unsigned image;			/* Position in the tree */
+   unsigned address;			/* Address of the pixel data */
+   unsigned level;			/* Level of the range */
+   real_t   weight [MAXEDGES + 1];	/* coeff. of the approximation */
+   word_t   into [MAXEDGES + 1];	/* used domains of the approximation */
+   int	    tree;			/* == domain : range is approximated
+					   with new state 'domain'
+					   == RANGE  :
+					   with a linear comb. */
+   real_t   err;			/* approximation error */
+   real_t   tree_bits;			/* # bits to encode tree */
+   real_t   matrix_bits;		/* # bits to encode matrices */
+   real_t   weights_bits;		/* # bits to encode weights */
+   mv_t	    mv;				/* motion vector */
+   real_t   mv_tree_bits;		/* # bits to encode mv tree */
+   real_t   mv_coord_bits;		/* # bits to encode mv coordinates */
+   real_t   nd_tree_bits;		/* # bits to encode nd tree */
+   real_t   nd_weights_bits;		/* # bits to encode nd factors */
+   bool_t   prediction;			/* range is predicted? */
+} range_t;
+
+typedef struct coding
+/*
+ *  All parameters and variables that must be accessible through the coding
+ *  process.
+ */
+{
+   real_t     	   price;		/* determines quality of approx. */
+   real_t   	 **images_of_state;	/* image of state i at level
+					   0, ... , imageslevel */
+   real_t   *(*ip_states_state)[MAXLEVEL]; /* inner products between state i
+					      and states 0, ... , i
+					      at all image levels */
+   real_t   	 **ip_images_state;	/* inner products between all
+					   ranges and state i */
+   real_t    	  *pixels;		/* current image pixels stored in tree
+					   order (only leaves are stored) */
+   unsigned   	   products_level;	/* inner products are stored up to
+					   this level */
+   tiling_t   	  *tiling;		/* tiling of the entire image */
+   tree_t     	   tree;		/* probability model */
+   tree_t     	   p_tree;		/* prediction probability model */
+   motion_t   	  *mt;			/* motion compensation information */
+   coeff_t   	  *coeff;
+   coeff_t   	  *d_coeff;
+   domain_pool_t  *domain_pool;
+   domain_pool_t  *d_domain_pool;
+   c_options_t     options;		/* global options */
+} coding_t;
+
+#endif /* not _CWFA_H */
+
diff --git a/converter/other/fiasco/codec/decoder.c b/converter/other/fiasco/codec/decoder.c
new file mode 100644
index 00000000..9474c1e7
--- /dev/null
+++ b/converter/other/fiasco/codec/decoder.c
@@ -0,0 +1,1532 @@
+/*
+ *  decode.c:		Decoding of an image represented by a WFA
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+ 
+/*
+ *  $Date: 2000/10/22 10:44:48 $
+ *  $Author: hafner $
+ *  $Revision: 5.3 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#if HAVE_STRING_H
+#	include <string.h>
+#else /* not HAVE_STRING_H */
+#	include <strings.h>
+#endif /* not HAVE_STRING_H */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "image.h"
+#include "misc.h"
+#include "motion.h"
+#include "read.h"
+#include "wfalib.h"
+#include "decoder.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+compute_state_images (unsigned frame_level, word_t **simg,
+		      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);
+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);
+static void
+compute_actual_size (unsigned luminance_root,
+		     unsigned *width, unsigned *height, const wfa_t *wfa);
+static void
+enlarge_image (int enlarge_factor, format_e format, unsigned y_root,
+	       wfa_t *wfa);
+static word_t *
+duplicate_state_image (const word_t *domain, unsigned offset, unsigned level);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+video_t *
+alloc_video (bool_t store_wfa)
+/*
+ *  Video struct constructor:
+ *  Initialize video structure and allocate memory for current, past
+ *  and future WFA if flag 'store_wfa' is TRUE.
+ *
+ *  Return value:
+ *	pointer to the new video structure
+ */
+{
+   video_t *video = Calloc (1, sizeof (video_t));
+   
+   video->future_display = -1;
+   video->display        = 0;
+
+   video->future = video->sfuture = video->past
+		 = video->frame   = video->sframe = NULL;
+
+   if (store_wfa)
+   {
+      video->wfa        = alloc_wfa (NO);
+      video->wfa_past   = alloc_wfa (NO);
+      video->wfa_future = alloc_wfa (NO);
+   }
+   else
+      video->wfa = video->wfa_past = video->wfa_future = NULL;
+
+   return video;
+}
+
+void
+free_video (video_t *video)
+/*
+ *  Video struct destructor:
+ *  Free memory of given 'video' struct.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'video' struct is discarded.
+ */
+{
+   if (video->past)
+      free_image (video->past);
+   if (video->future)
+      free_image (video->future);
+   if (video->sfuture)
+      free_image (video->sfuture);
+   if (video->frame)
+      free_image (video->frame);
+   if (video->sframe)
+      free_image (video->sframe);
+   if (video->wfa)
+      free_wfa (video->wfa);
+   if (video->wfa_past)
+      free_wfa (video->wfa_past);
+   if (video->wfa_future)
+      free_wfa (video->wfa_future);
+
+   Free (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)
+/*
+ *  Get next frame of the WFA 'video' from stream 'input'.
+ *  'orig_wfa' is the constant part of the WFA used by all frames.
+ *  Depending on values of 'enlarge_factor' and 'smoothing' enlarge and
+ *  smooth image, respectively. 
+ *  If 'store_wfa' is TRUE, then store WFA structure of reference frames
+ *  (used by analysis tool xwfa).
+ *  If 'reference_frame' is not NULL, then load image 'reference_frame'
+ *  from disk.
+ *  'format' gives the color format to be used (either 4:2:0 or 4:4:4).
+ *  If 'timer' is not NULL, then accumulate running time statistics. 
+ *
+ *  Return value:
+ *	pointer to decoded frame
+ *
+ *  Side effects:
+ *	'video' and 'timer' struct are modified.
+ */
+{
+   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)	 
+   {
+      /*
+       *  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);
+      video->frame  = video->future;
+      video->future = NULL;
+
+      if (video->sframe) /* discard current (smoothed) frame */
+	 free_image (video->sframe);
+      video->sframe  = video->sfuture;
+      video->sfuture = NULL;
+
+      if (store_wfa)
+	 copy_wfa (video->wfa, video->wfa_future);
+
+      video->display++;
+
+      if (!store_wfa)
+	 video->wfa = NULL;
+   }
+   else
+   {
+      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);
+	 }
+   
+	 /*
+	  *  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 (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;
+	 }
+      
+	 if (!store_wfa)
+	    remove_states (video->wfa->basis_states, video->wfa);
+      } while (!video->frame);
+
+      if (!store_wfa)
+	 video->wfa = NULL;
+   }
+   
+   return video->sframe ? video->sframe : video->frame;
+}
+
+image_t *
+decode_image (unsigned orig_width, unsigned orig_height, format_e format,
+	      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
+ *  coding time. Use 4:2:0 subsampling or 4:4:4 'format' for color images.
+ *  If 'dec_timer' is given, accumulate running time statistics. 
+ *  
+ *  Return value:
+ *	pointer to decoded image
+ *
+ *  Side effects:
+ *	'*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   state;
+   clock_t    ptimer;
+
+   prg_timer (&ptimer, START);
+
+   /*
+    *  Compute root of bintree for each color band
+    */
+   if (wfa->wfainfo->color)
+   {
+      root_state [Y]  = wfa->tree [wfa->tree [wfa->root_state][0]][0];
+      root_state [Cb] = wfa->tree [wfa->tree [wfa->root_state][0]][1];
+      root_state [Cr] = wfa->tree [wfa->tree [wfa->root_state][1]][0];
+   }
+   else
+      root_state [GRAY] = wfa->root_state;
+
+   /*
+    *  Compute maximum level of a linear combination
+    */
+   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]);
+   
+
+   /*
+    *  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);
+   frame = alloc_image (width, height, wfa->wfainfo->color, format);
+   
+   /*
+    *  Allocate buffers for intermediate state images
+    */
+   if (wfa->wfainfo->color)
+   {
+      wfa->level_of_state [wfa->root_state]               = 128;
+      wfa->level_of_state [wfa->tree[wfa->root_state][0]] = 128;
+      wfa->level_of_state [wfa->tree[wfa->root_state][1]] = 128;
+   }
+   alloc_state_images (&images, &offsets, frame, root_state, 0, max_level, 
+		       format, wfa);
+
+   if (dec_timer)
+      dec_timer [0] += prg_timer (&ptimer, STOP);
+
+   /*
+    *  Decode all state images, forming the complete image.
+    */
+   prg_timer (&ptimer, START);
+   compute_state_images (max_level, images, offsets, wfa);
+   if (dec_timer)
+      dec_timer [1] += prg_timer (&ptimer, STOP);
+
+   /*
+    *  Cleanup buffers used for intermediate state images
+    */
+   prg_timer (&ptimer, START);
+   free_state_images (max_level, frame->color, images, offsets, root_state, 0,
+		      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)		
+      {
+	 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)
+      dec_timer [2] += prg_timer (&ptimer, STOP);
+
+   return frame;
+}
+
+image_t *
+decode_state (unsigned state, unsigned level, wfa_t *wfa)
+/*
+ *  Decode 'state' image of 'wfa' at given 'level'.
+ *
+ *  Return value.
+ *	pointer to decoded state image
+ *
+ *  Side effects:
+ *	'wfa' states > 'state' are removed.  
+ */
+{
+   word_t  *domains [2];
+   image_t *img = Calloc (1, sizeof (image_t));
+
+   /*
+    *  Generate a new state with a 1.0 transition to 'state'
+    */
+   remove_states (state + 1, wfa);
+   append_edge (state + 1, state, 1.0, 0, wfa);
+   wfa->states = state + 2;
+
+   img->color  = NO;
+   img->width  = width_of_level (level);
+   img->height = height_of_level (level);
+   img->format = FORMAT_4_4_4;
+   img->pixels [GRAY] = decode_range (state + 1, 0, level, domains, wfa);
+
+   /*
+    *  Copy decoded range to the frame buffer
+    */
+   {
+      word_t   *src, *dst;
+      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;
+      }
+      Free (domains [0]);
+   }
+
+   return img;
+}
+
+word_t *
+decode_range (unsigned range_state, unsigned range_label, unsigned range_level,
+	      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
+ *
+ *  Side effects:
+ *	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
+ */
+{
+   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);
+   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);
+   alloc_state_images (&images, &offsets, state_image, NULL, range_state,
+		       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 */
+   {
+      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));
+   }
+   else					/* rectangle */
+   {
+      word_t   *src, *dst;
+      unsigned  y;
+      
+      src = images [range_state + (range_level + 1) * wfa->states]
+	    + 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);
+      }
+   }
+
+   if (domain != NULL)			/* copy domain images */
+   {
+      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);
+      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);
+      *domain = NULL;
+   }
+   
+   free_state_images (range_level + 1, NO, images, offsets, NULL, range_state,
+		      NO, wfa);
+   free_image (state_image);
+   
+   return range;
+}
+
+void
+smooth_image (unsigned sf, const wfa_t *wfa, image_t *image)
+/*
+ *  Smooth 'image' along the partitioning boundaries of the 'wfa'
+ *  with factor 's'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	pixel values of the 'image' are modified with respect to 's'
+ */
+{
+   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;
+
+   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 */
+   
+   for (state = wfa->basis_states;
+	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 */
+      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 */
+      {
+	 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);
+#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);
+#endif /* not HAVE_SIGNED_SHIFT */
+	 }
+      }
+      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;
+	    
+#ifdef HAVE_SIGNED_SHIFT
+	    *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);
+#endif /* not HAVE_SIGNED_SHIFT */
+	 }
+      }
+   }
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+enlarge_image (int enlarge_factor, format_e format, unsigned y_root,
+	       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.
+ *  'wfa' root state of the first chroma band is given by 'y_root' + 1.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	coordinates of ranges and motion blocks in the WFA structure 'wfa'
+ *	are modified.
+ */
+{
+   
+   if (enlarge_factor != 0 || format == FORMAT_4_2_0)
+   {
+      unsigned state;
+
+      if (enlarge_factor == 0)
+      {
+	 state 		= y_root + 1;
+	 enlarge_factor = -1;
+      }
+      else
+	 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--;
+      }
+   }
+}
+
+static void
+compute_actual_size (unsigned luminance_root,
+		     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
+ *   to the bintree partitioning.)
+ *  If 'luminance_root' < MAXSTATES then the size of chroma ranges (4:2:0).
+ *
+ *  Return values:
+ *	actual 'width' and 'height' of the decoded frame.
+ */
+{
+   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);
+      }
+
+   if (x & 1)				/* ensure that image size is even */
+      x++;
+   if (y & 1)
+      y++;
+   *width  = x;
+   *height = y;
+}
+
+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)
+/*
+ *  Generate list of 'wfa' state images which have to be computed for
+ *  each level to obtain the decoded 'frame'. 'root_state[]' denotes the
+ *  state images of the three color bands.
+ *  'max_level' fives the max. level of a linear combination.
+ *  Memory is allocated for every required state image.
+ *  Use 4:2:0 subsampling or 4:4:4 'format' for color images.
+ *  If 'range_state' > 0 then rather compute image of 'range_state' than 
+ *  image of 'wfa->root_state'.
+ *
+ *  Return values:
+ *	'*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.
+ */
+{
+   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));
+
+   /*
+    *  Initialize buffers for those state images which are at 'max_level'.
+    */
+   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;
+   }
+   else
+   {
+      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 (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;
+	    }
+      }
+   }
+   
+   /*
+    *  Generate list of state images which must be computed at each level
+    */
+   for (level = max_level; level > 0; level--)
+   {
+      int      child, domain;
+      unsigned state, label, edge;
+      
+      /*
+       *  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 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);
+		  }
+	       }
+      
+   }
+
+   *images  = simg;
+   *offsets = offs;
+}
+
+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)
+/*
+ *  Free memory of state images.
+ *  For more details refer to the inverse function 'alloc_state_images()'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	arrays 'state_image' and 'offset' are discarded.
+ */
+{
+   word_t   marker;			/* ptr is required as a marker */
+   unsigned level;
+
+   if (range_state > 0)
+   {
+      state_image [range_state + max_level * wfa->states] = &marker;
+   }
+   else
+   {
+      unsigned state;
+      
+      /*
+       *  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] = &marker;
+
+      if (color)
+      {
+	 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] = &marker;
+      }
+   }
+   
+   for (level = max_level; level > 0; level--)
+   {
+      int      domain, child;
+      unsigned state, label, edge;
+      /*
+       *  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] = &marker;
+	       }
+      /*
+       *  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]
+			= &marker;
+		  }
+   }
+   Free (state_image);
+   Free (offset);
+}
+
+static void
+compute_state_images (unsigned max_level, word_t **simg,
+		      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
+ *  are given by 'offset').
+ *
+ *  Warning: Several optimizations are used in this function making 
+ *  it difficult to understand.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	state images (given by pointers in the array 'state_image')
+ *	are computed.
+ */
+{
+   unsigned level, state;
+     
+   /*
+    *  Copy one-pixel images in case state_image pointer != &final distr.
+    */
+
+   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;
+
+   /*
+    *  Compute images of states
+    *  Integer arithmetics are used rather than floating point operations.
+    *  'weight' gives the weight in integer notation
+    *  'src', 'dst', and 'idst' are pointers to the source and
+    *  destination pixels (short or integer format), respectively.
+    *  Short format : one operation per register (16 bit mode). 
+    *  Integer format : two operations per register (32 bit mode). 
+    *  'src_offset', 'dst_offset', and 'dst_offset' give the number of
+    *  pixels which have to be omitted when jumping to the next image row.
+    */
+   for (level = 1; level <= max_level; level++) 
+   {
+      unsigned label;
+      unsigned width  = width_of_level (level - 1);
+      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;
+#ifdef HAVE_SIGNED_SHIFT
+			   *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;
+#ifdef HAVE_SIGNED_SHIFT
+			      *dst++ = ((weight * (int) *src++) >> 10) << 1;
+#else /* not HAVE_SIGNED_SHIFT */
+			      *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 */
+#ifdef HAVE_SIGNED_SHIFT
+#	ifndef WORDS_BIGENDIAN
+                                 tmp = (((weight * (int) src [1]) >> 10) << 17)
+				       | (((weight * (int) src [0]) >> 9)
+					  & 0xfffe);
+#	else /* not WORDS_BIGENDIAN */
+                                 tmp = (((weight * (int) src [0]) >> 10) << 17)
+				       | (((weight * (int) src [1]) >> 9)
+					  & 0xfffe);
+#	endif /* not WORDS_BIGENDIAN */
+#else /* not HAVE_SIGNED_SHIFT */
+#	ifndef WORDS_BIGENDIAN
+                                 tmp = (((weight * (int) src [1]) / 1024)
+					* 131072)
+				       | (((weight * (int) src [0])/ 512)
+					  & 0xfffe);
+#	else /* not WORDS_BIGENDIAN */
+                                 tmp = (((weight * (int) src [0]) / 1024)
+					* 131072)
+				       | (((weight * (int) src [1]) / 512)
+					  & 0xfffe);
+#	endif /* not WORDS_BIGENDIAN */
+#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;
+#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;
+#ifdef HAVE_SIGNED_SHIFT
+			      *dst++ += ((weight * (int) *src++) >> 10) << 1;
+#else /* not HAVE_SIGNED_SHIFT */
+			      *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 */
+#ifdef HAVE_SIGNED_SHIFT
+#	ifndef WORDS_BIGENDIAN
+                                 tmp = (((weight * (int) src [1]) >> 10) << 17)
+				       | (((weight * (int) src [0]) >> 9)
+					  & 0xfffe);
+#	else /* not WORDS_BIGENDIAN */
+                                 tmp = (((weight * (int)src [0]) >> 10) << 17)
+				       | (((weight * (int)src [1]) >> 9)
+					  & 0xfffe);
+#	endif /* not WORDS_BIGENDIAN */
+#else /* not HAVE_SIGNED_SHIFT */
+#	ifndef WORDS_BIGENDIAN
+                                 tmp = (((weight * (int) src [1]) / 1024)
+					* 131072)
+				       | (((weight * (int) src [0])/ 512)
+					  & 0xfffe);
+#	else /* not WORDS_BIGENDIAN */
+                                 tmp = (((weight * (int) src [0]) / 1024)
+					* 131072)
+				       | (((weight * (int) src [1])/ 512)
+					  & 0xfffe);
+#	endif /* not WORDS_BIGENDIAN */
+#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;
+			   }
+			}
+		     }
+		  }
+	       } 
+   }
+}
+
+static word_t *
+duplicate_state_image (const word_t *domain, unsigned offset, unsigned level)
+/*
+ *  Allocate new memory block 'pixels' and copy pixel values of 'domain' 
+ *  (size and pixel offset are given by 'level' and 'offset')
+ *  to the lock 'pixels'.
+ *
+ *  Return value:
+ *	pointer to the new domain block
+ */
+{
+   word_t *dst, *pixels;
+   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;
+      }
+   else					/* state 0 */
+      for (n = size_of_level (level); n; n--)
+	 *dst++ = (int) (128 * 8 + .5) * 2;
+
+   return pixels;
+}
diff --git a/converter/other/fiasco/codec/decoder.h b/converter/other/fiasco/codec/decoder.h
new file mode 100644
index 00000000..8cd211e0
--- /dev/null
+++ b/converter/other/fiasco/codec/decoder.h
@@ -0,0 +1,70 @@
+/*
+ *  decode.h
+ *		
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/10/22 10:44:48 $
+ *  $Author: hafner $
+ *  $Revision: 5.3 $
+ *  $State: Exp $
+ */
+
+#ifndef _DECODE_H
+#define _DECODE_H
+
+#include "types.h"
+#include "image.h"
+#include "wfa.h"
+
+typedef struct video
+{
+   unsigned  future_display;		/* number of a future frame */
+   unsigned  display;			/* current display number */
+   image_t  *frame;			/* current frame */
+   image_t  *sframe;			/* current smoothed frame */
+   image_t  *future;			/* future reference */
+   image_t  *sfuture;			/* future (smmothed) reference */
+   image_t  *past ;			/* past reference */
+   wfa_t    *wfa;			/* current wfa */
+   wfa_t    *wfa_future;		/* future wfa */
+   wfa_t    *wfa_past;			/* past wfa */
+} video_t;
+
+typedef struct dectimer
+{
+   unsigned int	input [3];
+   unsigned int	preprocessing [3];
+   unsigned int	decoder [3];
+   unsigned int	cleanup [3];
+   unsigned int	motion [3];
+   unsigned int	smooth [3];
+   unsigned int	display [3];
+   unsigned int	frames [3];
+} dectimer_t;
+
+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);
+image_t *
+decode_image (unsigned orig_width, unsigned orig_height, format_e format,
+	      unsigned *dec_timer, const wfa_t *wfa);
+word_t *
+decode_range (unsigned range_state, unsigned range_label, unsigned range_level,
+	      word_t **domain, wfa_t *wfa);
+image_t *
+decode_state (unsigned state, unsigned level, wfa_t *wfa);
+void
+smooth_image (unsigned sf, const wfa_t *wfa, image_t *image);
+video_t *
+alloc_video (bool_t store_wfa);
+void
+free_video (video_t *video);
+
+#endif /* not _DECODE_H */
diff --git a/converter/other/fiasco/codec/dfiasco.c b/converter/other/fiasco/codec/dfiasco.c
new file mode 100644
index 00000000..1cdfc672
--- /dev/null
+++ b/converter/other/fiasco/codec/dfiasco.c
@@ -0,0 +1,398 @@
+/*
+ *  dfiasco.c:		Decoder public interface
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+ 
+/*
+ *  $Date: 2000/10/28 17:39:30 $
+ *  $Author: hafner $
+ *  $Revision: 5.7 $
+ *  $State: Exp $
+ */
+
+#include <string.h>
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "dfiasco.h"
+#include "wfa.h"
+#include "read.h"
+#include "misc.h"
+#include "bit-io.h"
+#include "decoder.h"
+#include "options.h"
+#include "wfalib.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static dfiasco_t *
+cast_dfiasco (fiasco_decoder_t *dfiasco);
+static void
+free_dfiasco (dfiasco_t *dfiasco);
+static dfiasco_t *
+alloc_dfiasco (wfa_t *wfa, video_t *video, bitfile_t *input,
+	       int enlarge_factor, int smoothing, format_e image_format);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+fiasco_decoder_t *
+fiasco_decoder_new (const char *filename, const fiasco_d_options_t *options)
+{
+   try
+   {
+      bitfile_t        	 *input;	/* pointer to WFA FIASCO stream */
+      wfa_t            	 *wfa;		/* wfa structure */
+      video_t          	 *video;	/* information about decoder state */
+      const d_options_t  *dop;		/* decoder additional options */
+      dfiasco_t	       	 *dfiasco;	/* decoder internal state */
+      fiasco_decoder_t 	 *decoder;	/* public interface to decoder */
+      fiasco_d_options_t *default_options = NULL;
+
+      if (options)
+      {
+	 dop = cast_d_options ((fiasco_d_options_t *) options);
+	 if (!dop)
+	    return NULL;
+      }
+      else
+      {
+	 default_options = fiasco_d_options_new ();
+	 dop 		 = cast_d_options (default_options);
+      }
+      
+      wfa   = alloc_wfa (NO);
+      video = alloc_video (NO);
+      input = open_wfa (filename, wfa->wfainfo);
+      read_basis (wfa->wfainfo->basis_name, wfa);
+
+      decoder 	       	   = Calloc (1, sizeof (fiasco_decoder_t));
+      decoder->delete  	   = fiasco_decoder_delete;
+      decoder->write_frame = fiasco_decoder_write_frame;
+      decoder->get_frame   = fiasco_decoder_get_frame;
+      decoder->get_length  = fiasco_decoder_get_length;
+      decoder->get_rate    = fiasco_decoder_get_rate;
+      decoder->get_width   = fiasco_decoder_get_width;
+      decoder->get_height  = fiasco_decoder_get_height;
+      decoder->get_title   = fiasco_decoder_get_title;
+      decoder->get_comment = fiasco_decoder_get_comment;
+      decoder->is_color    = fiasco_decoder_is_color;
+
+      decoder->private = dfiasco
+		       = alloc_dfiasco (wfa, video, input,
+					dop->magnification,
+					dop->smoothing,
+					dop->image_format);
+   
+      if (default_options)
+	 fiasco_d_options_delete (default_options);
+      if (dfiasco->enlarge_factor >= 0)
+      {
+	 int 	       n;
+	 unsigned long pixels = wfa->wfainfo->width * wfa->wfainfo->height;
+
+	 for (n = 1; n <= (int) dfiasco->enlarge_factor; n++)
+	 {
+	    if (pixels << (n << 1) > 2048 * 2048)
+	    {
+	       set_error (_("Magnifaction factor `%d' is too large. "
+			    "Maximium value is %d."),
+			  dfiasco->enlarge_factor, max (0, n - 1));
+	       fiasco_decoder_delete (decoder);
+	       return NULL;
+	    }
+	 }
+      }
+      else
+      {
+	 int n;
+
+	 for (n = 0; n <= (int) - dfiasco->enlarge_factor; n++)
+	 {
+	    if (wfa->wfainfo->width >> n < 32
+		|| wfa->wfainfo->height >> n < 32)
+	    {
+	       set_error (_("Magnifaction factor `%d' is too small. "
+			    "Minimum value is %d."),
+			  dfiasco->enlarge_factor, - max (0, n - 1));
+	       fiasco_decoder_delete (decoder);
+	       return NULL;
+	    }
+	 }
+      }
+      return (fiasco_decoder_t *) decoder;
+   }
+   catch
+   {
+      return NULL;
+   }
+}
+
+int
+fiasco_decoder_write_frame (fiasco_decoder_t *decoder,
+			    const char *filename)
+{
+   dfiasco_t *dfiasco = cast_dfiasco (decoder);
+   
+   if (!dfiasco)
+      return 0;
+   else
+   {
+      try
+      {
+	 image_t *frame = get_next_frame (NO, dfiasco->enlarge_factor,
+					  dfiasco->smoothing, NULL,
+					  FORMAT_4_4_4, dfiasco->video, NULL,
+					  dfiasco->wfa, dfiasco->input);
+	 write_image (filename, frame);
+      }
+      catch
+      {
+	 return 0;
+      }
+      return 1;
+   }
+}
+
+fiasco_image_t *
+fiasco_decoder_get_frame (fiasco_decoder_t *decoder)
+{
+   dfiasco_t *dfiasco = cast_dfiasco (decoder);
+   
+   if (!dfiasco)
+      return NULL;
+   else
+   {
+      try
+      {
+	 fiasco_image_t *image = Calloc (1, sizeof (fiasco_image_t));
+	 image_t 	*frame = get_next_frame (NO, dfiasco->enlarge_factor,
+						 dfiasco->smoothing, NULL,
+						 dfiasco->image_format,
+						 dfiasco->video, NULL,
+						 dfiasco->wfa, dfiasco->input);
+
+	 frame->reference_count++;	/* for motion compensation */
+	 image->private    = frame;
+	 image->delete     = fiasco_image_delete;
+	 image->get_width  = fiasco_image_get_width;
+	 image->get_height = fiasco_image_get_height;
+	 image->is_color   = fiasco_image_is_color;
+	 
+	 return image;
+      }
+      catch
+      {
+	 return NULL;
+      }
+   }
+}
+
+unsigned
+fiasco_decoder_get_length (fiasco_decoder_t *decoder)
+{
+   dfiasco_t *dfiasco = cast_dfiasco (decoder);
+   
+   if (!dfiasco)
+      return 0;
+   else
+      return dfiasco->wfa->wfainfo->frames;
+}
+
+unsigned
+fiasco_decoder_get_rate (fiasco_decoder_t *decoder)
+{
+   dfiasco_t *dfiasco = cast_dfiasco (decoder);
+   
+   if (!dfiasco)
+      return 0;
+   else
+      return dfiasco->wfa->wfainfo->fps;
+}
+
+unsigned
+fiasco_decoder_get_width (fiasco_decoder_t *decoder)
+{
+   dfiasco_t *dfiasco = cast_dfiasco (decoder);
+
+   if (!dfiasco)
+      return 0;
+   else
+   {
+      unsigned width;
+      
+      if (dfiasco->enlarge_factor >= 0)
+	 width = dfiasco->wfa->wfainfo->width << dfiasco->enlarge_factor;
+      else
+	 width = dfiasco->wfa->wfainfo->width >> - dfiasco->enlarge_factor;
+      
+      return width & 1 ? width + 1 : width;
+   }
+}
+
+unsigned
+fiasco_decoder_get_height (fiasco_decoder_t *decoder)
+{
+   dfiasco_t *dfiasco = cast_dfiasco (decoder);
+
+   if (!dfiasco)
+      return 0;
+   else
+   {
+      unsigned height;
+      
+      if (dfiasco->enlarge_factor >= 0)
+	 height = dfiasco->wfa->wfainfo->height << dfiasco->enlarge_factor;
+      else
+	 height = dfiasco->wfa->wfainfo->height >> - dfiasco->enlarge_factor;
+
+      return height & 1 ? height + 1 : height;
+   }
+}
+
+const char *
+fiasco_decoder_get_title (fiasco_decoder_t *decoder)
+{
+   dfiasco_t *dfiasco = cast_dfiasco (decoder);
+
+   if (!dfiasco)
+      return NULL;
+   else
+      return dfiasco->wfa->wfainfo->title;
+}
+
+const char *
+fiasco_decoder_get_comment (fiasco_decoder_t *decoder)
+{
+   dfiasco_t *dfiasco = cast_dfiasco (decoder);
+
+   if (!dfiasco)
+      return NULL;
+   else
+      return dfiasco->wfa->wfainfo->comment;
+}
+
+int
+fiasco_decoder_is_color (fiasco_decoder_t *decoder)
+{
+   dfiasco_t *dfiasco = cast_dfiasco (decoder);
+
+   if (!dfiasco)
+      return 0;
+   else
+      return dfiasco->wfa->wfainfo->color;
+}
+
+int
+fiasco_decoder_delete (fiasco_decoder_t *decoder)
+{
+   dfiasco_t *dfiasco = cast_dfiasco (decoder);
+   
+   if (!dfiasco)
+      return 1;
+   
+   try
+   {
+      free_wfa (dfiasco->wfa);
+      free_video (dfiasco->video);
+      close_bitfile (dfiasco->input);
+      strcpy (dfiasco->id, " ");
+      free_dfiasco(dfiasco);
+      Free (decoder);
+   }
+   catch
+   {
+      return 0;
+   }
+
+   return 1;
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static dfiasco_t *
+alloc_dfiasco (wfa_t *wfa, video_t *video, bitfile_t *input,
+	       int enlarge_factor, int smoothing, format_e image_format)
+/*
+ *  FIASCO decoder constructor:
+ *  Initialize decoder structure.
+ *
+ *  Return value:
+ *	pointer to the new decoder structure
+ */
+{
+   dfiasco_t *dfiasco = Calloc (1, sizeof (dfiasco_t));
+
+   strcpy (dfiasco->id, "DFIASCO");
+   
+   dfiasco->wfa 	   = wfa;
+   dfiasco->video 	   = video;
+   dfiasco->input 	   = input;
+   dfiasco->enlarge_factor = enlarge_factor;
+   dfiasco->smoothing  	   = smoothing;
+   dfiasco->image_format   = image_format;
+   
+   return dfiasco;
+}
+
+static void
+free_dfiasco (dfiasco_t *dfiasco)
+/*
+ *  FIASCO decoder destructor:
+ *  Free memory of given 'decoder' struct.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'video' struct is discarded.
+ */
+{
+   Free (dfiasco);
+}
+
+static dfiasco_t *
+cast_dfiasco (fiasco_decoder_t *dfiasco)
+/*
+ *  Cast pointer `dfiasco' to type dfiasco_t.
+ *  Check whether `dfiasco' is a valid object of type dfiasco_t.
+ *
+ *  Return value:
+ *	pointer to dfiasco_t struct on success
+ *      NULL otherwise
+ */
+{
+   dfiasco_t *this = (dfiasco_t *) dfiasco->private;
+   if (this)
+   {
+      if (!streq (this->id, "DFIASCO"))
+      {
+	 set_error (_("Parameter `dfiasco' doesn't match required type."));
+	 return NULL;
+      }
+   }
+   else
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "dfiasco");
+   }
+
+   return this;
+}
diff --git a/converter/other/fiasco/codec/dfiasco.h b/converter/other/fiasco/codec/dfiasco.h
new file mode 100644
index 00000000..bcc3c7f9
--- /dev/null
+++ b/converter/other/fiasco/codec/dfiasco.h
@@ -0,0 +1,38 @@
+/*
+ *  dfiasco.h
+ *		
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/07/15 18:00:53 $
+ *  $Author: hafner $
+ *  $Revision: 5.2 $
+ *  $State: Exp $
+ */
+
+#ifndef _DFIASCO_H
+#define _DFIASCO_H
+
+#include "types.h"
+#include "bit-io.h"
+#include "decoder.h"
+#include "image.h"
+#include "wfa.h"
+
+typedef struct dfiasco
+{
+   char       id [8];
+   wfa_t     *wfa;
+   video_t   *video;
+   bitfile_t *input;
+   int	      enlarge_factor;
+   int        smoothing;
+   format_e   image_format;
+} dfiasco_t;
+
+#endif /* not _DFIASCO_H */
+
diff --git a/converter/other/fiasco/codec/domain-pool.c b/converter/other/fiasco/codec/domain-pool.c
new file mode 100644
index 00000000..09f854a6
--- /dev/null
+++ b/converter/other/fiasco/codec/domain-pool.c
@@ -0,0 +1,986 @@
+/*
+ *  domain-pool.c:  Domain pool management (probability model)
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include <math.h>
+
+#if STDC_HEADERS
+#   include <stdlib.h>
+#endif /* not STDC_HEADERS */
+
+#if HAVE_STRING_H
+#   include <string.h>
+#else /* not HAVE_STRING_H */
+#   include <strings.h>
+#endif /* not HAVE_STRING_H */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "misc.h"
+#include "cwfa.h"
+#include "wfalib.h"
+#include "domain-pool.h"
+
+/*
+ *  Domain pool model interface:
+ *  Implementing the domain pool model interface requires the
+ *  following steps: 
+ *  - Add a constructor that initializes the domain_pool_t structure
+ *  - Allocate new model with default_alloc() 
+ *  - Fill the dp_array_t domain_pools array with constructor and name
+ *  - Write code for methods bits() and generate()
+ *  - Either use default functions for remaining methods or override them
+ *  The new model is automatically registered at the command line.
+ */
+
+/*****************************************************************************
+                                          
+                  local variables
+                  
+*****************************************************************************/
+
+static real_t *matrix_0 = NULL;
+static real_t *matrix_1 = NULL;
+
+/*****************************************************************************
+                        non-adaptive domain pool
+*****************************************************************************/
+
+static void
+qac_chroma (unsigned max_domains, const wfa_t *wfa, void *model);
+static bool_t
+qac_append (unsigned new_state, unsigned level, const wfa_t *wfa, void *model);
+static void
+qac_update (const word_t *domains, const word_t *used_domains,
+            unsigned level, int y_state, const wfa_t *wfa, void *model);
+static real_t
+qac_bits (const word_t *domains, const word_t *used_domains,
+          unsigned level, int y_state, const wfa_t *wfa, const void *model);
+static word_t *
+qac_generate (unsigned level, int y_state, const wfa_t *wfa,
+              const void *model);
+static void *
+qac_model_duplicate (const void *src);
+static void
+qac_model_free (void *model);
+static void *
+qac_model_alloc (unsigned max_domains);
+static domain_pool_t *
+alloc_qac_domain_pool (unsigned max_domains, unsigned max_edges,
+                       const wfa_t *wfa);
+
+/*****************************************************************************
+              run length encoding pool
+*****************************************************************************/
+
+static domain_pool_t *
+alloc_rle_no_chroma_domain_pool (unsigned max_domains, unsigned max_edges,
+                                 const wfa_t *wfa);
+static void
+rle_chroma (unsigned max_domains, const wfa_t *wfa, void *model);
+static bool_t
+rle_append (unsigned new_state, unsigned level, const wfa_t *wfa, void *model);
+static void
+rle_update (const word_t *domains, const word_t *used_domains,
+            unsigned level, int y_state, const wfa_t *wfa, void *model);
+static real_t
+rle_bits (const word_t *domains, const word_t *used_domains,
+          unsigned level, int y_state, const wfa_t *wfa, const void *model);
+static word_t *
+rle_generate (unsigned level, int y_state, const wfa_t *wfa,
+              const void *model);
+static void *
+rle_model_duplicate (const void *src);
+static void
+rle_model_free (void *model);
+static void *
+rle_model_alloc (unsigned max_domains);
+static domain_pool_t *
+alloc_rle_domain_pool (unsigned max_domains, unsigned max_edges,
+                       const wfa_t *wfa);
+
+/*****************************************************************************
+              const domain pool
+*****************************************************************************/
+
+static real_t
+const_bits (const word_t *domains, const word_t *used_domains,
+            unsigned level, int y_state, const wfa_t *wfa, const void *model);
+static word_t *
+const_generate (unsigned level, int y_state, const wfa_t *wfa,
+                const void *model);
+static domain_pool_t *
+alloc_const_domain_pool (unsigned max_domains, unsigned max_edges,
+                         const wfa_t *wfa);
+
+/*****************************************************************************
+              basis domain pool
+*****************************************************************************/
+
+static domain_pool_t *
+alloc_basis_domain_pool (unsigned max_domains, unsigned max_edges,
+                         const wfa_t *wfa);
+
+/*****************************************************************************
+              uniform distribution pool
+*****************************************************************************/
+
+static real_t
+uniform_bits (const word_t *domains, const word_t *used_domains,
+              unsigned level, int y_state, const wfa_t *wfa,
+              const void *model);
+static word_t *
+uniform_generate (unsigned level, int y_state, const wfa_t *wfa,
+                  const void *model);
+static domain_pool_t *
+alloc_uniform_domain_pool (unsigned max_domains, unsigned max_edges,
+                           const wfa_t *wfa);
+
+/*****************************************************************************
+              default functions
+*****************************************************************************/
+
+static void
+init_matrix_probabilities (void);
+static void
+default_chroma (unsigned max_domains, const wfa_t *wfa, void *model);
+static bool_t
+default_append (unsigned new_state, unsigned level,
+                const wfa_t *wfa, void *model);
+static void
+default_update (const word_t *domains, const word_t *used_domains,
+                unsigned level, int y_state, const wfa_t *wfa, void *model);
+static void
+default_free (domain_pool_t *pool);
+static void
+default_model_free (void *model);
+static void *
+default_model_alloc (unsigned max_domains);
+static void *
+default_model_duplicate (const void *src);
+static domain_pool_t *
+default_alloc (void);
+
+/*****************************************************************************
+
+                public code
+  
+*****************************************************************************/
+
+typedef struct dp_array
+{
+    const char       *identifier;
+    domain_pool_t *(*function) (unsigned max_domains, unsigned max_edges,
+                                const wfa_t *wfa);
+} dp_array_t;
+
+dp_array_t const domain_pools[] = {{"adaptive", alloc_qac_domain_pool},
+                                   {"constant",   alloc_const_domain_pool}, 
+                                   {"basis",      alloc_basis_domain_pool},
+                                   {"uniform",    alloc_uniform_domain_pool},
+                                   {"rle",        alloc_rle_domain_pool},
+                                   {"rle-no-chroma",  alloc_rle_no_chroma_domain_pool},
+                                   {NULL,     NULL}};
+
+domain_pool_t *
+alloc_domain_pool (const char *domain_pool_name, unsigned max_domains,
+                   unsigned max_edges, const wfa_t *wfa)
+/*
+ *  Allocate a new domain pool identified by the string
+ *  'domain_pool_name'.  Maximum number of domain images (each one
+ *  represented by one state of the given 'wfa') is specified by
+ *  'max_domains'. 
+ * 
+ *  Return value:
+ *  pointer to the allocated domain pool
+ *
+ *  Note:
+ *      refer to 'domain-pool.h' for a short description of the member functions.
+ */
+{
+    unsigned n;
+   
+    if (!max_domains)
+    {
+        warning ("Can't generate empty domain pool. "
+                 "Using at least DC component.");
+        max_domains = 1;
+    }
+   
+    for (n = 0; domain_pools [n].identifier; n++) /* step through all id's */
+        if (strcaseeq (domain_pools [n].identifier, domain_pool_name)) 
+            return domain_pools [n].function (max_domains, max_edges, wfa);
+
+    warning ("Can't initialize domain pool '%s'. Using default value '%s'.",
+             domain_pool_name, domain_pools [0].identifier);
+
+    return domain_pools [0].function (max_domains, max_edges, wfa);
+}
+
+/*****************************************************************************
+
+                private code
+  
+*****************************************************************************/
+
+/*****************************************************************************
+              adaptive domain pool
+*****************************************************************************/
+
+typedef struct qac_model
+{
+    word_t   *index;         /* probability of domains */
+    word_t   *states;            /* mapping states -> domains */
+    u_word_t  y_index;           /* pointer to prob of Y domain */
+    u_word_t  n;             /* number of domains in the pool */
+    u_word_t  max_domains;       /* max. number of domains */
+} qac_model_t;
+
+static domain_pool_t *
+alloc_qac_domain_pool (unsigned max_domains, unsigned max_edges,
+                       const wfa_t *wfa)
+/*
+ *  Domain pool with state images {0, ..., 'max_domains').
+ *  Underlying probability model: quasi arithmetic coding of columns.
+ */
+{
+    domain_pool_t *pool;
+    unsigned   state;
+   
+    pool                  = default_alloc ();
+    pool->model           = qac_model_alloc (max_domains);
+    pool->generate        = qac_generate;
+    pool->bits            = qac_bits;
+    pool->update          = qac_update;
+    pool->append          = qac_append;
+    pool->chroma      = qac_chroma;
+    pool->model_free      = qac_model_free;
+    pool->model_duplicate = qac_model_duplicate;
+   
+    for (state = 0; state < wfa->basis_states; state++)
+        if (usedomain (state, wfa))
+            qac_append (state, -1, wfa, pool->model);
+
+    return pool;
+}
+
+static void *
+qac_model_alloc (unsigned max_domains)
+{
+    qac_model_t *model;
+
+    init_matrix_probabilities ();
+
+    model          = Calloc (1, sizeof (qac_model_t));
+    model->index       = Calloc (max_domains, sizeof (word_t));
+    model->states      = Calloc (max_domains, sizeof (word_t));
+    model->y_index     = 0;
+    model->n       = 0;
+    model->max_domains = max_domains;
+
+    return model;
+}
+
+static void
+qac_model_free (void *model)
+{
+    Free (((qac_model_t *) model)->index);
+    Free (((qac_model_t *) model)->states);
+    Free (model);
+}
+
+static void *
+qac_model_duplicate (const void *src)
+{
+    qac_model_t       *qdst;
+    const qac_model_t *qsrc = (qac_model_t *) src;
+
+    qdst      = qac_model_alloc (qsrc->max_domains);
+    qdst->y_index = qsrc->y_index;
+    qdst->n       = qsrc->n;
+   
+    memcpy (qdst->index, qsrc->index, qsrc->n * sizeof (word_t));
+    memcpy (qdst->states, qsrc->states, qsrc->n * sizeof (word_t));
+
+    return qdst;
+}
+
+static word_t *
+qac_generate (unsigned level, int y_state, const wfa_t *wfa, const void *model)
+{
+    word_t      *domains;
+    unsigned n;
+    qac_model_t *qac_model     = (qac_model_t *) model;
+    bool_t   y_state_is_domain = NO;
+
+    if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */
+        y_state = -1;
+   
+    domains = Calloc (qac_model->n + 2, sizeof (word_t));
+
+    memcpy (domains, qac_model->states, qac_model->n * sizeof (word_t));
+
+    for (n = 0; n < qac_model->n; n++)
+        if (domains [n] == y_state)   /* match */
+            y_state_is_domain = YES;       
+
+    if (y_state_is_domain)
+        domains [qac_model->n] = -1;  /* end marker */
+    else
+    {
+        domains [qac_model->n]     = y_state; /* additional y-state */
+        domains [qac_model->n + 1] = -1;  /* end marker */
+    }
+
+    return domains;
+}
+
+static real_t
+qac_bits (const word_t *domains, const word_t *used_domains,
+          unsigned level, int y_state, const wfa_t *wfa, const void *model)
+{
+    int      domain;         /* counter */
+    real_t   bits      = 0;      /* bit rate R */
+    qac_model_t *qac_model = (qac_model_t *) model; /* probability model */
+
+    if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */
+        y_state = -1;
+
+    for (domain = 0; domain < qac_model->n; domain++)
+        if (qac_model->states [domain] != y_state)
+            bits += matrix_0 [qac_model->index [domain]];
+    if (y_state >= 0)
+        bits += matrix_0 [qac_model->y_index];
+   
+    if (used_domains != NULL)
+    {
+        unsigned edge;
+      
+        for (edge = 0; isedge (domain = used_domains [edge]); edge++)
+            if (domains [domain] == y_state)
+            {
+                bits -= matrix_0 [qac_model->y_index];
+                bits += matrix_1 [qac_model->y_index];
+            }
+            else
+            {
+                bits -= matrix_0 [qac_model->index [domain]];
+                bits += matrix_1 [qac_model->index [domain]];
+            }
+    } 
+   
+    return bits;
+}
+
+static void
+qac_update (const word_t *domains, const word_t *used_domains,
+            unsigned level, int y_state, const wfa_t *wfa, void *model)
+{
+    int      domain;
+    unsigned edge;
+    bool_t   used_y_state      = NO;
+    qac_model_t *qac_model     = (qac_model_t *) model;
+    bool_t   y_state_is_domain = NO;
+   
+    if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */
+        y_state = -1;
+
+    for (domain = 0; domain < qac_model->n; domain++)
+    {
+        qac_model->index [domain]++;  /* mark domains unused. */
+        if (qac_model->states [domain] == y_state) /* match */
+            y_state_is_domain = YES;       
+    }
+   
+    for (edge = 0; isedge (domain = used_domains [edge]); edge++)
+        if (domains [domain] == y_state) /* chroma coding */
+        {
+            if (y_state_is_domain)
+                qac_model->index [domain]--; /* undo */
+            qac_model->y_index >>= 1;
+            used_y_state = YES;
+        }
+        else              /* luminance coding */
+        {
+            qac_model->index [used_domains [edge]]--; /* undo */
+            qac_model->index [used_domains [edge]] >>= 1;      
+        }
+
+    if (y_state >= 0 && !used_y_state)
+        qac_model->y_index++;     /* update y-state model */
+   
+    for (domain = 0; domain < qac_model->n; domain++)
+        if (qac_model->index [domain] > 1020) /* check for overflow */
+            qac_model->index [domain] = 1020; 
+    if (qac_model->y_index > 1020)   /* check for overflow */
+        qac_model->y_index = 1020; 
+}
+
+static bool_t
+qac_append (unsigned new_state, unsigned level, const wfa_t *wfa, void *model)
+{
+    qac_model_t  *qac_model = (qac_model_t *) model; /* probability model */
+   
+    if (qac_model->n >= qac_model->max_domains)
+        return NO;            /* don't use state in domain pool */
+    else
+    {
+        qac_model->index [qac_model->n]
+            = qac_model->n > 0 ? qac_model->index [qac_model->n - 1] : 0;
+        qac_model->states [qac_model->n] = new_state;
+        qac_model->n++;
+
+        return YES;           /* state will be used in domain pool */
+    }
+}
+
+static void
+qac_chroma (unsigned max_domains, const wfa_t *wfa, void *model)
+{
+    qac_model_t *qac_model = (qac_model_t *) model; /* probability model */
+   
+    if (max_domains < qac_model->n)  /* choose most probable domains */
+    {
+        word_t   *domains;
+        unsigned  n, new, old;
+        word_t   *states = Calloc (max_domains, sizeof (word_t));
+        word_t   *index  = Calloc (max_domains, sizeof (word_t));
+   
+        domains = compute_hits (wfa->basis_states, wfa->states - 1,
+                                max_domains, wfa);
+        for (n = 0; n < max_domains && domains [n] >= 0; n++)
+            states [n] = domains [n];
+        max_domains = min (max_domains, n);
+        Free (domains);
+
+        for (old = 0, new = 0; new < max_domains && old < qac_model->n; old++)
+            if (qac_model->states [old] == states [new])
+                index [new++] = qac_model->index [old];
+
+        Free (qac_model->states);
+        Free (qac_model->index);
+        qac_model->states      = states;
+        qac_model->index       = index;
+        qac_model->n           = max_domains;
+        qac_model->max_domains = max_domains;
+    }
+    qac_model->y_index     = 0;
+    qac_model->max_domains = qac_model->n;
+}
+
+/*****************************************************************************
+              const domain pool
+*****************************************************************************/
+
+static domain_pool_t *
+alloc_const_domain_pool (unsigned max_domains, unsigned max_edges,
+                         const wfa_t *wfa)
+/*
+ *  Domain pool with state image 0 (constant function f(x, y) = 1).
+ *  No probability model is used.
+ */
+{
+    domain_pool_t *pool;
+   
+    pool           = default_alloc ();   
+    pool->generate = const_generate;
+    pool->bits     = const_bits;
+   
+    return pool;
+}
+
+static word_t *
+const_generate (unsigned level, int y_state, const wfa_t *wfa,
+                const void *model)
+{
+    word_t *domains = Calloc (2, sizeof (word_t));
+   
+    domains [0] = 0;
+    domains [1] = -1;
+   
+    return domains;
+}
+
+static real_t
+const_bits (const word_t *domains, const word_t *used_domains,
+            unsigned level, int y_state, const wfa_t *wfa, const void *model)
+{
+    return 0;                /* 0 bits,
+                                either we have a lc or not */
+}
+
+/*****************************************************************************
+                basis domain pool
+*****************************************************************************/
+
+static domain_pool_t *
+alloc_basis_domain_pool (unsigned max_domains, unsigned max_edges,
+                         const wfa_t *wfa)
+/*
+ *  Domain pool with state images {0, ..., 'basis_states' - 1).
+ *  Underlying probability model: quasi arithmetic coding of columns.
+ *  I.e. domain pool = qac_domainpool ('max_domains' == wfa->basis_states)
+ */
+{
+    return alloc_qac_domain_pool (wfa->basis_states, max_edges, wfa);
+}
+
+/*****************************************************************************
+              uniform-distribution pool
+*****************************************************************************/
+
+static domain_pool_t *
+alloc_uniform_domain_pool (unsigned max_domains, unsigned max_edges,
+                           const wfa_t *wfa)
+/*
+ *  Domain pool with state images {0, ..., 'max_domains').
+ *  Underlying probability model: uniform distribution.
+ */
+{
+    domain_pool_t *pool;
+   
+    pool           = default_alloc ();   
+    pool->generate = uniform_generate;
+    pool->bits     = uniform_bits;
+   
+    return pool;
+}
+
+static word_t *
+uniform_generate (unsigned level, int y_state, const wfa_t *wfa,
+                  const void *model)
+{
+    unsigned  state, n;
+    word_t   *domains = Calloc (wfa->states + 1, sizeof (word_t));
+
+    for (state = 0, n = 0; state < wfa->states; state++)
+        if (usedomain (state, wfa))
+            domains [n++] = state;
+    domains [n] = -1;
+   
+    return domains;
+}
+ 
+static real_t
+uniform_bits (const word_t *domains, const word_t *used_domains,
+              unsigned level, int y_state, const wfa_t *wfa, const void *model)
+{
+    unsigned state, n;
+    real_t   bits = 0;
+   
+    for (state = 0, n = 0; state < wfa->states; state++)
+        if (usedomain (state, wfa))
+            n++;
+
+    bits = - n * log2 ((n - 1) / (real_t) n);
+
+    if (used_domains != NULL)
+    {
+        int edge;
+      
+        for (edge = 0; isedge (used_domains [edge]); edge++)
+            bits -= log2 (1.0 / n);
+    }
+
+    return bits;
+}
+
+/*****************************************************************************
+              run length encoding pool
+*****************************************************************************/
+
+typedef struct rle_model
+{
+    word_t   count [MAXEDGES + 1];
+    u_word_t total;
+    u_word_t n;
+    u_word_t max_domains;
+    u_word_t y_index;        /* pointer to prob of Y domain */
+    word_t      *states;         /* mapping states -> domains */
+    qac_model_t *domain_0;
+} rle_model_t;
+
+static domain_pool_t *
+alloc_rle_domain_pool (unsigned max_domains, unsigned max_edges,
+                       const wfa_t *wfa)
+/*
+ *  Domain pool with state images {0, ..., 'max_domains').
+ *  Underlying probability model: rle 
+ */
+{
+    domain_pool_t *pool;
+    unsigned   state;
+   
+    pool                  = default_alloc ();    
+    pool->model           = rle_model_alloc (max_domains);
+    pool->model_free      = rle_model_free;
+    pool->model_duplicate = rle_model_duplicate;
+    pool->generate        = rle_generate;
+    pool->update          = rle_update;
+    pool->bits            = rle_bits;
+    pool->append          = rle_append;
+    pool->chroma          = rle_chroma;
+
+    for (state = 0; state < wfa->basis_states; state++)
+        if (usedomain (state, wfa))
+            rle_append (state, -1, wfa, pool->model);
+
+    return pool;
+}
+
+static void *
+rle_model_alloc (unsigned max_domains)
+{
+    unsigned m;
+    rle_model_t *model = Calloc (1, sizeof (rle_model_t));
+   
+    for (m = model->total = 0; m < MAXEDGES + 1; m++, model->total++)
+        model->count [m] = 1;
+
+    model->domain_0    = qac_model_alloc (1);
+    model->states      = Calloc (max_domains, sizeof (word_t));
+    model->n       = 0;
+    model->y_index     = 0;
+    model->max_domains = max_domains;
+   
+    return model;
+}
+
+static void
+rle_model_free (void *model)
+{
+    qac_model_free (((rle_model_t *) model)->domain_0);
+    Free (((rle_model_t *) model)->states);
+    Free (model);
+}
+
+static void *
+rle_model_duplicate (const void *src)
+{
+    const rle_model_t *rle_src = (rle_model_t *) src;
+    rle_model_t       *model   = Calloc (1, sizeof (rle_model_t));
+
+    model->domain_0    = qac_model_duplicate (rle_src->domain_0);
+    model->n       = rle_src->n;
+    model->max_domains = rle_src->max_domains;
+    model->states      = Calloc (model->max_domains, sizeof (word_t));
+    model->total       = rle_src->total;
+    model->y_index     = rle_src->y_index;
+   
+    memcpy (model->states, rle_src->states,
+            model->max_domains * sizeof (word_t));
+    memcpy (model->count, rle_src->count,
+            (MAXEDGES + 1) * sizeof (word_t));
+   
+    return model;
+}
+
+static word_t *
+rle_generate (unsigned level, int y_state, const wfa_t *wfa, const void *model)
+{
+    word_t      *domains;
+    unsigned n;
+    rle_model_t *rle_model     = (rle_model_t *) model;
+    bool_t   y_state_is_domain = NO;
+   
+    if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */
+        y_state = -1;
+   
+    domains = Calloc (rle_model->n + 2, sizeof (word_t));
+
+    memcpy (domains, rle_model->states, rle_model->n * sizeof (word_t));
+
+    for (n = 0; n < rle_model->n; n++)
+        if (domains [n] == y_state)   /* match */
+            y_state_is_domain = YES;       
+
+    if (y_state_is_domain)
+        domains [rle_model->n] = -1;  /* end marker */
+    else
+    {
+        domains [rle_model->n]     = y_state; /* additional y-state */
+        domains [rle_model->n + 1] = -1;  /* end marker */
+    }
+
+    return domains;
+}
+
+static real_t
+rle_bits (const word_t *domains, const word_t *used_domains,
+          unsigned level, int y_state, const wfa_t *wfa, const void *model)
+{
+    unsigned edge;
+    unsigned n     = 0;
+    real_t   bits      = 0;
+    word_t   sorted [MAXEDGES + 1];
+    rle_model_t *rle_model = (rle_model_t *) model;
+    unsigned last;
+    int      into;
+   
+    if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */
+        y_state = -1;
+
+    if (used_domains)
+    {
+        word_t domain;
+      
+        if (y_state >= 0)
+            bits += matrix_0 [rle_model->y_index];
+      
+        for (edge = n = 0; isedge (domain = used_domains [edge]); edge++)
+            if (domains [domain] != y_state)
+                sorted [n++] = used_domains [edge];
+            else
+            {
+                bits -= matrix_0 [rle_model->y_index];
+                bits += matrix_1 [rle_model->y_index];
+            }
+      
+        if (n > 1)
+            qsort (sorted, n, sizeof (word_t), sort_asc_word);
+    }
+
+    bits = - log2 (rle_model->count [n] / (real_t) rle_model->total);
+    if (used_domains && n && sorted [0] == 0)
+    {
+        word_t array0 [2] = {0, NO_EDGE};
+        bits += qac_bits (array0, array0, level, y_state, wfa, rle_model->domain_0);
+    }
+    else
+    {
+        word_t array0 [2] = {NO_EDGE};
+        bits += qac_bits (array0, array0, level, y_state, wfa, rle_model->domain_0);
+    }
+   
+    last = 1;
+    for (edge = 0; edge < n; edge++)
+        if ((into = sorted [edge]) && rle_model->n - 1 - last)
+        {
+            bits += bits_bin_code (into - last, rle_model->n - 1 - last);
+            last  = into + 1;
+        }
+   
+    return bits;
+}
+
+static void
+rle_update (const word_t *domains, const word_t *used_domains,
+            unsigned level, int y_state, const wfa_t *wfa, void *model)
+{
+    rle_model_t *rle_model  = (rle_model_t *) model;
+    bool_t   state_0    = NO, state_y = NO;
+    word_t   array0 [2] = {0, NO_EDGE};
+    unsigned     edge = 0;
+   
+    if (y_state >= 0 && !usedomain (y_state, wfa)) /* don't use y-state */
+        y_state = -1;
+
+    if (used_domains)
+    {
+        word_t   domain;
+      
+        for (edge = 0; isedge (domain = used_domains [edge]); edge++)
+            if (domains [domain] == 0)
+                state_0 = YES;
+            else if (domains [domain] == y_state)
+                state_y = YES;
+    }
+   
+    rle_model->count [edge]++;
+    rle_model->total++;
+
+    qac_update (array0, array0 + (state_0 ? 0 : 1), level, y_state, wfa,
+                rle_model->domain_0);
+
+    if (state_y)
+        rle_model->y_index >>= 1;
+    else
+        rle_model->y_index++;
+    if (rle_model->y_index > 1020)   /* check for overflow */
+        rle_model->y_index = 1020; 
+}
+
+static bool_t
+rle_append (unsigned new_state, unsigned level, const wfa_t *wfa, void *model)
+{
+    rle_model_t *rle_model = (rle_model_t *) model; /* probability model */
+   
+    if (rle_model->n >= rle_model->max_domains)
+        return NO;            /* don't use state in domain pool */
+    else
+    {
+        rle_model->states [rle_model->n] = new_state;
+        rle_model->n++;
+
+        if (new_state == 0)
+        {
+            assert (rle_model->n == 1);
+            qac_append (0, -1, wfa, rle_model->domain_0);
+        }
+      
+        return YES;           /* state will be used in domain pool */
+    }
+}
+
+static void
+rle_chroma (unsigned max_domains, const wfa_t *wfa, void *model)
+{
+    rle_model_t *rle_model = (rle_model_t *) model; /* probability model */
+   
+    if (max_domains < rle_model->n)  /* choose most probable domains */
+    {
+        unsigned  n;
+        word_t   *states  = Calloc (max_domains, sizeof (word_t));
+        word_t   *domains = compute_hits (wfa->basis_states, wfa->states - 1,
+                                          max_domains, wfa);
+      
+        for (n = 0; n < max_domains && domains [n] >= 0; n++)
+            states [n] = domains [n];
+
+        assert (states [0] == 0);
+        max_domains = min (max_domains, n);
+        Free (domains);
+
+        Free (rle_model->states);
+        rle_model->states = states;
+        rle_model->n      = max_domains;
+    }
+    rle_model->y_index     = 0;
+    rle_model->max_domains = rle_model->n;
+}
+
+/*****************************************************************************
+         run length encoding pool no special chroma pool
+*****************************************************************************/
+
+static domain_pool_t *
+alloc_rle_no_chroma_domain_pool (unsigned max_domains, unsigned max_edges,
+                                 const wfa_t *wfa)
+/*
+ *  Domain pool with state images {0, ..., 'max_domains').
+ *  Underlying probability model: rle 
+ *  Domain pool is not changed for chroma bands
+ */
+{
+    domain_pool_t *pool = alloc_rle_domain_pool (max_domains, max_edges, wfa);
+   
+    pool->chroma = default_chroma;
+
+    return pool;
+}
+
+/*****************************************************************************
+              default functions (see domain-pool.h)
+*****************************************************************************/
+
+static domain_pool_t *
+default_alloc (void)
+{
+    domain_pool_t *pool;
+
+    pool                  = Calloc (1, sizeof (domain_pool_t));
+    pool->model           = default_model_alloc(0);
+    pool->generate        = NULL;
+    pool->bits            = NULL;
+    pool->update          = default_update;
+    pool->append          = default_append;
+    pool->chroma          = default_chroma;
+    pool->free            = default_free;
+    pool->model_free      = default_model_free;
+    pool->model_duplicate = default_model_duplicate;
+   
+    return pool;
+}
+
+static void *
+default_model_duplicate (const void *src)
+{
+    return NULL;
+}
+
+static void *
+default_model_alloc (unsigned max_domains)
+{
+    return NULL;
+}
+
+static void
+default_model_free (void *model)
+{
+    if (model)
+        Free (model);
+}
+
+static void
+default_free (domain_pool_t *pool)
+{
+    pool->model_free (pool->model);
+    Free (pool);
+}
+
+static void
+default_update (const word_t *domains, const word_t *used_domains,
+                unsigned level, int y_state, const wfa_t *wfa, void *model)
+{
+    return;              /* nothing to do */
+}
+
+static bool_t
+default_append (unsigned new_state, unsigned level,
+                const wfa_t *wfa, void *model)
+{
+    return YES;              /* use every state in lin comb */
+}
+
+static void
+default_chroma (unsigned max_domains, const wfa_t *wfa, void *model)
+{
+    return;              /* don't alter domain pool */
+}
+
+static void
+init_matrix_probabilities (void)
+/*
+ *  Compute the information contents of matrix element '0' and '1' for
+ *  each possible probability index 0, ... ,  1023. These values are
+ *  obtained from the probability model in the quasi arithmetic
+ *  coding module.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *  local arrays matrix_0 and matrix_1 are initialized if not already done.
+ */
+{
+    if (matrix_0 == NULL || matrix_1 == NULL)
+    {
+        unsigned index;           
+        unsigned n, exp;
+      
+        matrix_0 = Calloc (1 << (MAX_PROB + 1), sizeof (real_t));
+        matrix_1 = Calloc (1 << (MAX_PROB + 1), sizeof (real_t));
+   
+        for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++)
+            for (exp = 0; exp < (unsigned) 1 << n; exp++, index++)
+            {
+                matrix_1 [index] = -log2 (1 / (real_t) (1 << n));
+                matrix_0 [index] = -log2 (1 - 1 / (real_t) (1 << n));
+            }
+    }
+}
diff --git a/converter/other/fiasco/codec/domain-pool.h b/converter/other/fiasco/codec/domain-pool.h
new file mode 100644
index 00000000..d1488779
--- /dev/null
+++ b/converter/other/fiasco/codec/domain-pool.h
@@ -0,0 +1,75 @@
+/*
+ *  domain-pool.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _DOMAIN_POOL_H
+#define _DOMAIN_POOL_H
+
+#include "cwfa.h"
+#include "types.h"
+
+typedef struct domain_pool
+{
+   void	  *model;			/* probability model */
+   word_t *(*generate) (unsigned level, int y_state, const wfa_t *wfa,
+			const void  *model);
+   /*
+    *  Generate set of domain images which may be used for an approximation.
+    *  Use parameters 'level', 'y_state' and 'wfa' to make the decision.
+    */
+   real_t (*bits) (const word_t *domains, const word_t *used_domains,
+		   unsigned level, int y_state, const wfa_t *wfa,
+		   const void *model);
+   /*
+    *  Compute bit-rate of a range approximation with domains given by
+    *  the -1 terminated list 'used_domains'.
+    */
+   void	  (*update) (const word_t *domains, const word_t *used_domains,
+		     unsigned level, int y_state, const wfa_t *wfa,
+		     void *model);
+   /*
+    *  Update the probability model according to the chosen approximation.
+    *  (given by the -1 terminated list 'used_domains').
+    */
+   bool_t (*append) (unsigned state, unsigned level, const wfa_t *wfa,
+		     void *model);
+   /*
+    *  Try to append a new state to the domain pool.
+    */
+   void	  (*chroma) (unsigned max_domains, const wfa_t *wfa, void *model);
+   /*
+    *  Derive a new domain pool that will be used for chroma channel
+    *  coding 
+    */
+   void   (*free) (struct domain_pool *pool);
+   /*
+    *  Discard the given domain pool struct.
+    */
+   void   (*model_free)	(void *model);
+   /*
+    *  Free given probability model.
+    */
+   void   *(*model_duplicate) (const void *src);
+   /*
+    *  Duplicate the given probability model (i.e. alloc and copy).
+    */
+} domain_pool_t;
+
+domain_pool_t *
+alloc_domain_pool (const char *domain_pool_name, unsigned max_domains,
+		   unsigned max_edges, const wfa_t *wfa);
+
+#endif /* not _DOMAIN_POOL_H */
+
diff --git a/converter/other/fiasco/codec/ip.c b/converter/other/fiasco/codec/ip.c
new file mode 100644
index 00000000..caa97baf
--- /dev/null
+++ b/converter/other/fiasco/codec/ip.c
@@ -0,0 +1,324 @@
+/*
+ *  ip.c:		Computation of inner products
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "cwfa.h"
+#include "control.h"
+#include "ip.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static real_t 
+standard_ip_image_state (unsigned address, unsigned level, unsigned domain,
+			 const coding_t *c);
+static real_t 
+standard_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
+			 const coding_t *c);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+real_t 
+get_ip_image_state (unsigned image, unsigned address, unsigned level,
+		    unsigned domain, const coding_t *c)
+/*
+ *  Return value:
+ *	Inner product between 'image' ('address') and
+ *      'domain' at given 'level' 
+ */
+{
+   if (level <= c->options.images_level)
+   {
+      /*
+       *  Compute the inner product in the standard way by multiplying 
+       *  the pixel-values of the given domain and range image.
+       */ 
+      return standard_ip_image_state (address, level, domain, c);
+   }
+   else 
+   {
+      /*
+       *  Use the already computed inner products stored in 'ip_images_states'
+       */
+      return c->ip_images_state [domain][image];
+   }
+}
+
+void 
+compute_ip_images_state (unsigned image, unsigned address, unsigned level,
+			 unsigned n, unsigned from,
+			 const wfa_t *wfa, coding_t *c)
+/*
+ *  Compute the inner products between all states
+ *  'from', ... , 'wfa->max_states' and the range images 'image'
+ *  (and childs) up to given level.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	inner product tables 'c->ip_images_states' are updated
+ */ 
+{
+   if (level > c->options.images_level) 
+   {
+      unsigned state, label;
+
+      if (level > c->options.images_level + 1)	/* recursive computation */
+	 compute_ip_images_state (MAXLABELS * image + 1, address * MAXLABELS,
+				  level - 1, MAXLABELS * n, from, wfa, c);
+      
+      /*
+       *  Compute inner product <f, Phi_i>
+       */
+      for (label = 0; label < MAXLABELS; label++)
+	 for (state = from; state < wfa->states; state++)
+	    if (need_image (state, wfa))
+	    {
+	       unsigned  edge, count;
+	       int     	 domain;
+	       real_t 	*dst, *src;
+	       
+	       if (ischild (domain = wfa->tree [state][label]))
+	       {
+		  if (level > c->options.images_level + 1)
+		  {
+		     dst = c->ip_images_state [state] + image;
+		     src = c->ip_images_state [domain]
+			   + image * MAXLABELS + label + 1;
+		     for (count = n; count; count--, src += MAXLABELS)
+			*dst++ += *src;
+		  }
+		  else
+		  {
+		     unsigned newadr = address * MAXLABELS + label;
+		     
+		     dst = c->ip_images_state [state] + image;
+		     
+		     for (count = n; count; count--, newadr += MAXLABELS)
+			*dst++ += standard_ip_image_state (newadr, level - 1,
+							   domain, c);
+		  }
+	       }
+	       for (edge = 0; isedge (domain = wfa->into [state][label][edge]);
+		    edge++)
+	       {
+		  real_t weight = wfa->weight [state][label][edge];
+		  
+		  if (level > c->options.images_level + 1)
+		  {
+		     dst = c->ip_images_state [state] + image;
+		     src = c->ip_images_state [domain]
+			   + image * MAXLABELS + label + 1;
+		     for (count = n; count; count--, src += MAXLABELS)
+			*dst++ += *src * weight;
+		  }
+		  else
+		  {
+		     unsigned newadr = address * MAXLABELS + label;
+
+		     dst = c->ip_images_state [state] + image;
+		     
+		     for (count = n; count; count--, newadr += MAXLABELS)
+			*dst++ += weight *
+				  standard_ip_image_state (newadr, level - 1,
+							   domain, c);
+		  }
+	       }
+	    }
+   }
+}
+
+real_t 
+get_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
+		    const coding_t *c)
+/*
+ *  Return value:
+ *	Inner product between 'domain1' and 'domain2' at given 'level'.
+ */
+{
+   if (level <= c->options.images_level)
+   {
+      /*
+       *  Compute the inner product in the standard way by multiplying 
+       *  the pixel-values of both state-images
+       */ 
+      return standard_ip_state_state (domain1, domain2, level, c);
+   }
+   else 
+   {
+      /*
+       *  Use already computed inner products stored in 'ip_images_states'
+       */
+      if (domain2 < domain1)
+	 return c->ip_states_state [domain1][level][domain2];
+      else
+	 return c->ip_states_state [domain2][level][domain1];
+   }
+}
+
+void 
+compute_ip_states_state (unsigned from, unsigned to,
+			 const wfa_t *wfa, coding_t *c)
+/*
+ *  Computes the inner products between the current state 'state1' and the
+ *  old states 0,...,'state1'-1
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	inner product tables 'c->ip_states_state' are computed.
+ */ 
+{
+   unsigned level;
+   unsigned state1, state2;
+
+   /*
+    *  Compute inner product <Phi_state1, Phi_state2>
+    */
+
+   for (level = c->options.images_level + 1;
+	level <= c->options.lc_max_level; level++)
+      for (state1 = from; state1 <= to; state1++)
+	 for (state2 = 0; state2 <= state1; state2++) 
+	    if (need_image (state2, wfa))
+	    {
+	       unsigned	label;
+	       real_t	ip = 0;
+	       
+	       for (label = 0; label < MAXLABELS; label++)
+	       {
+		  int	   domain1, domain2;
+		  unsigned edge1, edge2;
+		  real_t   sum, weight2;
+		  
+		  if (ischild (domain1 = wfa->tree [state1][label]))
+		  {
+		     sum = 0;
+		     if (ischild (domain2 = wfa->tree [state2][label]))
+			sum = get_ip_state_state (domain1, domain2,
+						  level - 1, c);
+		     
+		     for (edge2 = 0;
+			  isedge (domain2 = wfa->into [state2][label][edge2]);
+			  edge2++)
+		     {
+			weight2 = wfa->weight [state2][label][edge2];
+			sum += weight2 * get_ip_state_state (domain1, domain2,
+							     level - 1, c);
+		     }
+		     ip += sum;
+		  }
+		  for (edge1 = 0;
+		       isedge (domain1 = wfa->into [state1][label][edge1]);
+		       edge1++)
+		  {
+		     real_t weight1 = wfa->weight [state1][label][edge1];
+		     
+		     sum = 0;
+		     if (ischild (domain2 = wfa->tree [state2][label]))
+			sum = get_ip_state_state (domain1, domain2,
+						  level - 1, c);
+		     
+		     for (edge2 = 0;
+			  isedge (domain2 = wfa->into [state2][label][edge2]);
+			  edge2++)
+		     {
+			weight2 = wfa->weight [state2][label][edge2];
+			sum += weight2 * get_ip_state_state (domain1, domain2,
+							     level - 1, c);
+		     }
+		     ip += weight1 * sum;
+		  }
+	       }
+	       c->ip_states_state [state1][level][state2] = ip;
+	    }
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static real_t 
+standard_ip_image_state (unsigned address, unsigned level, unsigned domain,
+			 const coding_t *c)
+/*
+ *  Returns the inner product between the subimage 'address' and the
+ *  state image 'domain' at given 'level'.  The stored state images
+ *  and the image tree are used to compute the inner product in the
+ *  standard way by multiplying the corresponding pixel values.
+ *
+ *  Return value:
+ *	computed inner product
+ */
+{
+   unsigned i;
+   real_t   ip = 0, *imageptr, *stateptr;
+
+   if (level > c->options.images_level)
+      error ("Level %d not supported.", level);
+   
+   imageptr = &c->pixels [address * size_of_level (level)];
+
+   stateptr = c->images_of_state [domain] + address_of_level (level);
+   
+   for (i = size_of_level (level); i; i--)
+      ip += *imageptr++ * *stateptr++;
+
+   return ip;
+}
+
+static real_t 
+standard_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
+			 const coding_t *c)
+/*
+ *  Returns the inner product between the subimage 'address' and the
+ *  state image 'state' at given 'level'.  The stored state images are
+ *  used to compute the inner product in the standard way by
+ *  multiplying the corresponding pixel values.
+ *
+ *  Return value:
+ *	computed inner product
+ */
+{
+   unsigned i;
+   real_t   ip = 0, *state1ptr, *state2ptr;
+
+   if (level > c->options.images_level)
+      error ("Level %d not supported.", level);
+
+   state1ptr = c->images_of_state [domain1] + address_of_level (level);
+   state2ptr = c->images_of_state [domain2] + address_of_level (level);
+   
+   for (i = size_of_level (level); i; i--)
+      ip += *state1ptr++ * *state2ptr++;
+
+   return ip;
+}
+
diff --git a/converter/other/fiasco/codec/ip.h b/converter/other/fiasco/codec/ip.h
new file mode 100644
index 00000000..e5e4dd65
--- /dev/null
+++ b/converter/other/fiasco/codec/ip.h
@@ -0,0 +1,37 @@
+/*
+ *  ip.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _IP_H
+#define _IP_H
+
+#include "cwfa.h"
+
+void 
+compute_ip_states_state (unsigned from, unsigned to,
+			 const wfa_t *wfa, coding_t *c);
+real_t 
+get_ip_state_state (unsigned domain1, unsigned domain2, unsigned level,
+		    const coding_t *c);
+void 
+compute_ip_images_state (unsigned image, unsigned address, unsigned level,
+			 unsigned n, unsigned from,
+			 const wfa_t *wfa, coding_t *c);
+real_t 
+get_ip_image_state (unsigned image, unsigned address, unsigned level,
+		    unsigned domain, const coding_t *c);
+
+#endif /* not _IP_H */
+
diff --git a/converter/other/fiasco/codec/motion.c b/converter/other/fiasco/codec/motion.c
new file mode 100644
index 00000000..92951281
--- /dev/null
+++ b/converter/other/fiasco/codec/motion.c
@@ -0,0 +1,338 @@
+/*
+ *  motion.c:		Motion compensation code	
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#if HAVE_STRING_H
+#	include <string.h>
+#else /* not HAVE_STRING_H */
+#	include <strings.h>
+#endif /* not HAVE_STRING_H */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "image.h"
+#include "misc.h"
+#include "motion.h"
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+restore_mc (int enlarge_factor, image_t *image, const image_t *past,
+	    const image_t *future, const wfa_t *wfa)
+/*
+ *  Restore motion compensated prediction of 'image' represented by 'wfa'.
+ *  If 'enlarge_factor' != 0 then enlarge image by given amount.
+ *  Reference frames are given by 'past' and 'future'.
+ *
+ *  No return values.
+ */
+{
+   unsigned  state, label;
+   unsigned  root_state;
+   word_t   *mcblock1, *mcblock2;	/* MC blocks */
+
+#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
+					  + 2 * enlarge_factor, 0)),
+		      sizeof (word_t));
+   mcblock2 = Calloc (size_of_level (max ((int) wfa->wfainfo->p_max_level
+					  + 2 * enlarge_factor, 0)),
+		      sizeof (word_t));
+
+   if (!image->color)
+      root_state = wfa->root_state;
+   else
+      root_state  = wfa->tree [wfa->tree [wfa->root_state][0]][0];
+   
+   for (state = wfa->basis_states; state <= root_state; state++)
+      for (label = 0; label < MAXLABELS; label++)
+	 if (wfa->mv_tree[state][label].type != NONE)
+	 {
+	    color_e band;
+	    unsigned level  = wfa->level_of_state [state] - 1;
+	    unsigned width  = width_of_level (level);
+	    unsigned height = height_of_level (level);
+	    unsigned offset = image->width - width;
+	    
+	    switch (wfa->mv_tree [state][label].type)
+	    {
+	       case FORWARD:
+		  for (band  = first_band (image->color);
+		       band <= last_band (image->color); band++)
+		  {
+		     extract_mc_block (mcblock1, FX (width), FX (height),
+				       past->pixels [band], FX (past->width),
+				       wfa->wfainfo->half_pixel,
+				       FX (wfa->x [state][label]),
+				       FX (wfa->y [state][label]),
+				       FX (wfa->mv_tree [state][label].fx),
+				       FX (wfa->mv_tree [state][label].fy));
+		     {
+			word_t   *mc1;	/* current pixel in MC block */
+			word_t 	 *orig;	/* current pixel in original image */
+			unsigned  x, y;	/* pixel coordinates */
+			
+			mc1  = mcblock1;
+			orig = (word_t *) image->pixels [band]
+			       + FX (wfa->x[state][label])
+			       + FX (wfa->y[state][label]) * FX (image->width);
+		     
+			for (y = FX (height); y; y--)
+			{
+			   for (x = FX (width); x; x--)
+			      *orig++ += *mc1++;
+
+			   orig += FX (offset);
+			}
+		     }
+		  }
+		  break;
+	       case BACKWARD:
+		  for (band  = first_band (image->color);
+		       band <= last_band (image->color); band++)
+		  {
+		     extract_mc_block (mcblock1, FX (width), FX (height),
+				       future->pixels [band],
+				       FX (future->width),
+				       wfa->wfainfo->half_pixel,
+				       FX (wfa->x [state][label]),
+				       FX (wfa->y [state][label]),
+				       FX (wfa->mv_tree [state][label].bx),
+				       FX (wfa->mv_tree [state][label].by));
+		     {
+			word_t   *mc1;	/* current pixel in MC block 1 */
+			word_t   *orig;	/* current pixel in original image */
+			unsigned  x, y;	/* pixel coordinates */
+			
+			mc1  = mcblock1;
+			orig = (word_t *) image->pixels [band]
+			       + FX (wfa->x[state][label])
+			       + FX (wfa->y[state][label]) * FX (image->width);
+		     
+			for (y = FX (height); y; y--)
+			{
+			   for (x = FX (width); x; x--)
+			      *orig++ += *mc1++;
+
+			   orig += FX (offset);
+			}
+		     }
+		  }
+		  break;
+	       case INTERPOLATED:
+		  for (band  = first_band (image->color);
+		       band <= last_band (image->color); band++)
+		  {
+		     extract_mc_block (mcblock1, FX (width), FX (height),
+				       past->pixels [band], FX (past->width),
+				       wfa->wfainfo->half_pixel,
+				       FX (wfa->x[state][label]),
+				       FX (wfa->y[state][label]),
+				       FX (wfa->mv_tree[state][label].fx),
+				       FX (wfa->mv_tree[state][label].fy));
+		     extract_mc_block (mcblock2, FX (width), FX (height),
+				       future->pixels [band],
+				       FX (future->width),
+				       wfa->wfainfo->half_pixel,
+				       FX (wfa->x[state][label]),
+				       FX (wfa->y[state][label]),
+				       FX (wfa->mv_tree[state][label].bx),
+				       FX (wfa->mv_tree[state][label].by));
+		     {
+			word_t   *mc1;	/* current pixel in MC block 1 */
+			word_t   *mc2;	/* current pixel in MC block 1 */
+			word_t   *orig;	/* current pixel in original image */
+			unsigned  x, y;	/* pixel coordinates */
+			
+			mc1  = mcblock1;
+			mc2  = mcblock2;
+			orig = (word_t *) image->pixels [band]
+			       + FX (wfa->x[state][label])
+			       + FX (wfa->y[state][label]) * FX (image->width);
+			
+			for (y = FX (height); y; y--)
+			{
+			   for (x = FX (width); x; x--)
+#ifdef HAVE_SIGNED_SHIFT
+			      *orig++ += (*mc1++ + *mc2++) >> 1;
+#else /* not HAVE_SIGNED_SHIFT */
+			   *orig++ += (*mc1++ + *mc2++) / 2;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+			   orig += FX (offset);
+			}
+		     }
+		  }
+		  break;
+	       default:
+		  break;
+	    }
+	 }
+
+   if (image->color)
+   {
+      unsigned	  n;
+      word_t	 *ptr;
+      static int *clipping = NULL;
+      unsigned	  shift    = image->format == FORMAT_4_2_0 ? 2 : 0;
+
+      if (!clipping)			/* initialize clipping table */
+      {
+	 int i;
+	    
+	 clipping = Calloc (256 * 3, sizeof (int));
+	 for (i = -128; i < 128; i++)
+	    clipping [256 + i + 128] = i;
+	 for (i = 0; i < 256; i++)
+	    clipping [i] = clipping [256];
+	 for (i = 512; i < 512 + 256; i++)
+	    clipping [i] = clipping [511];
+	 clipping += 256 + 128;
+      }
+	 
+      ptr = image->pixels [Cb];
+      for (n = (image->width * image->height) >> shift; n; n--, ptr++)
+#ifdef HAVE_SIGNED_SHIFT
+	 *ptr = clipping [*ptr >> 4] << 4;
+#else /* not HAVE_SIGNED_SHIFT */
+	 *ptr = clipping [*ptr / 16] * 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+      ptr = image->pixels [Cr];
+      for (n = (image->width * image->height) >> shift; n; n--, ptr++)
+#ifdef HAVE_SIGNED_SHIFT
+	*ptr = clipping [*ptr >> 4] << 4;
+#else /* not HAVE_SIGNED_SHIFT */
+        *ptr = clipping [*ptr / 16] * 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+   }
+   
+   Free (mcblock1);
+   Free (mcblock2);
+}
+
+void
+extract_mc_block (word_t *mcblock, unsigned width, unsigned height,
+		  const word_t *reference, unsigned ref_width,
+		  bool_t half_pixel, unsigned xo, unsigned yo,
+		  unsigned mx, unsigned my)
+/*
+ *  Extract motion compensation image 'mcblock' of size 'width'x'height'
+ *  from 'reference' image (width is given by 'ref_width').
+ *  Coordinates of reference block are given by ('xo' + 'mx', 'yo' + 'my').
+ *  Use 'half_pixel' precision if specified.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'mcblock[]'	MCPE block is filled with reference pixels 
+ */
+{
+   if (!half_pixel)			/* Fullpixel precision */
+   {
+      const word_t *rblock;		/* pointer to reference image */
+      unsigned	    y;			/* current row */
+      
+      rblock  = reference + (yo + my) * ref_width + (xo + mx);
+      for (y = height; y; y--) 
+      {
+	 memcpy (mcblock, rblock, width * sizeof (word_t));
+
+	 mcblock += width;
+	 rblock  += ref_width;
+      }
+   }
+   else					/* Halfpixel precision */
+   {
+      unsigned	    x, y;		/* current coordinates */
+      unsigned	    offset;		/* remaining pixels in row */
+      const word_t *rblock;		/* pointer to reference image */
+      const word_t *ryblock;		/* pointer to next line */
+      const word_t *rxblock;		/* pointer to next column */
+      const word_t *rxyblock;		/* pointer to next column & row */
+   
+      rblock   = reference + (yo + my / 2) * ref_width + (xo + mx / 2);
+      ryblock  = rblock + ref_width;	/* pixel in next row */
+      rxblock  = rblock + 1;		/* pixel in next column */
+      rxyblock = ryblock + 1;		/* pixel in next row & column */
+      offset   = ref_width - width;
+      
+      if ((mx & 1) == 0)
+      {
+	 if ((my & 1) == 0)		/* Don't use halfpixel refinement */
+	    for (y = height; y; y--) 
+	    {
+	       memcpy (mcblock, rblock, width * sizeof (word_t));
+	       
+	       mcblock += width;
+	       rblock  += ref_width;
+	    }
+	 else				/* Halfpixel in y direction */
+	    for (y = height; y; y--) 
+	    {
+	       for (x = width; x; x--)
+#ifdef HAVE_SIGNED_SHIFT
+		  *mcblock++ = (*rblock++ + *ryblock++) >> 1;
+#else /* not HAVE_SIGNED_SHIFT */
+		  *mcblock++ = (*rblock++ + *ryblock++) / 2;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+	       rblock  += offset;
+	       ryblock += offset;
+	    }
+      }
+      else
+      {
+	 if ((my & 1) == 0)		/* Halfpixel in x direction */
+	    for (y = height; y; y--) 
+	    {
+	       for (x = width; x; x--)
+#ifdef HAVE_SIGNED_SHIFT
+		  *mcblock++ = (*rblock++ + *rxblock++) >> 1;
+#else /* not HAVE_SIGNED_SHIFT */
+		  *mcblock++ = (*rblock++ + *rxblock++) / 2;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+	       rblock  += offset;
+	       rxblock += offset;
+	    }
+	 else				/* Halfpixel in xy direction */
+	    for (y = height; y; y--) 
+	    {
+	       for (x = width; x; x--)
+#ifdef HAVE_SIGNED_SHIFT
+		  *mcblock++ = (*rblock++ + *rxblock++
+				+ *ryblock++ + *rxyblock++) >> 2;
+#else /* not HAVE_SIGNED_SHIFT */
+		  *mcblock++ = (*rblock++ + *rxblock++
+				+ *ryblock++ + *rxyblock++) / 4;
+#endif /* not HAVE_SIGNED_SHIFT */
+	       rblock   += offset;
+	       ryblock  += offset;
+	       rxblock  += offset;
+	       rxyblock += offset;
+	    }
+      }
+   }
+}
diff --git a/converter/other/fiasco/codec/motion.h b/converter/other/fiasco/codec/motion.h
new file mode 100644
index 00000000..2ea382f7
--- /dev/null
+++ b/converter/other/fiasco/codec/motion.h
@@ -0,0 +1,35 @@
+/*
+ *  motion.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _MOTION_H
+#define _MOTION_H
+
+#include "wfa.h"
+#include "types.h"
+#include "image.h"
+
+void
+restore_mc (int enlarge_factor, image_t *image, const image_t *past,
+	    const image_t *future, const wfa_t *wfa);
+void
+extract_mc_block (word_t *mcblock, unsigned width, unsigned height,
+		  const word_t *reference, unsigned ref_width,
+		  bool_t half_pixel, unsigned xo, unsigned yo,
+		  unsigned mx, unsigned my);
+
+#endif /* not _MOTION_H */
+
diff --git a/converter/other/fiasco/codec/mwfa.c b/converter/other/fiasco/codec/mwfa.c
new file mode 100644
index 00000000..6f0af8be
--- /dev/null
+++ b/converter/other/fiasco/codec/mwfa.c
@@ -0,0 +1,864 @@
+/*
+ *  mwfa.c:		Initialization of MWFA coder
+ *
+ *  Written by:		Michael Unger
+ *			Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+
+#if HAVE_STRING_H
+#	include <string.h>
+#else /* not HAVE_STRING_H */
+#	include <strings.h>
+#endif /* not HAVE_STRING_H */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "misc.h"
+#include "cwfa.h"
+#include "image.h"
+#include "mvcode.h"
+#include "motion.h"
+#include "mwfa.h"
+
+
+static const unsigned local_range = 6;
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+get_mcpe (word_t *mcpe, const image_t *original,
+	  unsigned x0, unsigned y0, unsigned width, unsigned height,
+	  const word_t *mcblock1, const word_t *mcblock2);
+static real_t
+mcpe_norm (const image_t *original, unsigned x0, unsigned y0, unsigned width,
+	   unsigned height, const word_t *mcblock1, const word_t *mcblock2);
+static real_t 
+find_best_mv (real_t price, const image_t *original, const image_t *reference,
+	      unsigned x0, unsigned y0, unsigned width, unsigned height,
+	      real_t *bits, int *mx, int *my, const real_t *mc_norms,
+	      const wfa_info_t *wi, const motion_t *mt);
+static real_t
+find_second_mv (real_t price, const image_t *original,
+		const image_t *reference, const word_t *mcblock1,
+		unsigned xr, unsigned yr, unsigned width, unsigned height,
+		real_t *bits, int *mx, int *my, const wfa_info_t *wi,
+		const motion_t *mt);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+motion_t *
+alloc_motion (const wfa_info_t *wi)
+/*
+ *  Motion structure constructor.
+ *  Allocate memory for the motion structure and
+ *  fill in default values specified by 'wi'.
+ *
+ *  Return value:
+ *	pointer to the new option structure or NULL on error
+ */
+{
+   int	     dx;			/* motion vector coordinate */
+   unsigned  level;
+   unsigned range_size = wi->half_pixel
+			 ? square (wi->search_range)
+			 : square (2 * wi->search_range);
+   motion_t *mt        = Calloc (1, sizeof (motion_t));
+   
+   mt->original = NULL;
+   mt->past     = NULL;
+   mt->future   = NULL;
+   mt->xbits 	= Calloc (2 * wi->search_range, sizeof (real_t));
+   mt->ybits 	= Calloc (2 * wi->search_range, sizeof (real_t));
+
+   for (dx = -wi->search_range; dx < (int) wi->search_range; dx++)
+   {
+      mt->xbits [dx + wi->search_range]
+	 = mt->ybits [dx + wi->search_range]
+	 = mv_code_table [dx + wi->search_range][1];
+   }
+   
+   mt->mc_forward_norms = Calloc (MAXLEVEL, sizeof (real_t *));
+   mt->mc_backward_norms = Calloc (MAXLEVEL, sizeof (real_t *));
+   
+   for (level = wi->p_min_level; level <= wi->p_max_level; level++)
+   {
+      mt->mc_forward_norms  [level] = Calloc (range_size, sizeof (real_t));
+      mt->mc_backward_norms [level] = Calloc (range_size, sizeof (real_t));
+   }
+
+   return mt;
+}
+
+void
+free_motion (motion_t *mt)
+/*
+ *  Motion struct destructor:
+ *  Free memory of 'motion' struct.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	structure 'motion' is discarded.
+ */
+{
+   unsigned level;
+
+   Free (mt->xbits);
+   Free (mt->ybits);
+   for (level = 0; level < MAXLEVEL; level++)
+   {
+      if (mt->mc_forward_norms [level])
+	 Free (mt->mc_forward_norms [level]);
+      if (mt->mc_backward_norms [level])
+	 Free (mt->mc_backward_norms [level]);
+   }
+   Free (mt->mc_forward_norms);
+   Free (mt->mc_backward_norms);
+   Free (mt);
+}
+
+void
+subtract_mc (image_t *image, const image_t *past, const image_t *future,
+	     const wfa_t *wfa)
+/*
+ *  Subtract motion compensation from chrom channels of 'image'.
+ *  Reference frames are given by 'past' and 'future'.
+ *
+ *  No return values.
+ */
+{
+   unsigned  state, label;
+   word_t   *mcblock1 = Calloc (size_of_level (wfa->wfainfo->p_max_level),
+				sizeof (word_t));
+   word_t   *mcblock2 = Calloc (size_of_level (wfa->wfainfo->p_max_level),
+				sizeof (word_t));
+
+   for (state = wfa->basis_states; state < wfa->states; state++)
+      for (label = 0; label < MAXLABELS; label++)
+	 if (wfa->mv_tree [state][label].type != NONE)
+	 {
+	    color_e  band;		/* current color band */
+	    unsigned width, height;	/* size of mcblock */
+	    unsigned offset;		/* remaining pixels in original */
+	    
+	    width  = width_of_level (wfa->level_of_state [state] - 1);
+	    height = height_of_level (wfa->level_of_state [state] - 1);
+	    offset = image->width - width;
+	    
+	    switch (wfa->mv_tree [state][label].type)
+	    {
+	       case FORWARD:
+		  for (band  = first_band (image->color) + 1;
+		       band <= last_band (image->color); band++)
+		  {
+		     unsigned  y;	/* row of block */
+		     word_t   *mc1;	/* pixel in MC block 1 */
+		     word_t   *orig;	/* pixel in original image */
+		     
+		     extract_mc_block (mcblock1, width, height,
+				       past->pixels [band], past->width,
+				       wfa->wfainfo->half_pixel,
+				       wfa->x [state][label],
+				       wfa->y [state][label],
+				       (wfa->mv_tree [state][label].fx / 2)
+				       * 2,
+				       (wfa->mv_tree [state][label].fy / 2)
+				       * 2);
+		     mc1  = mcblock1;
+		     orig = image->pixels [band] + wfa->x [state][label]
+			    + wfa->y [state][label] * image->width;
+		     
+ 		     for (y = height; y; y--)
+		     {
+			unsigned x;	/* column of block */
+			
+			for (x = width; x; x--)
+			   *orig++ -= *mc1++;
+
+			orig += offset;
+		     }
+		  }
+		  break;
+	       case BACKWARD:
+		  for (band  = first_band (image->color) + 1;
+		       band <= last_band (image->color); band++)
+		  {
+		     unsigned  y;	/* row of block */
+		     word_t   *mc1;	/* pixel in MC block 1 */
+		     word_t   *orig;	/* pixel in original image */
+		     
+		     extract_mc_block (mcblock1, width, height,
+				       future->pixels [band], future->width,
+				       wfa->wfainfo->half_pixel,
+				       wfa->x [state][label],
+				       wfa->y [state][label],
+				       (wfa->mv_tree [state][label].bx / 2)
+				       * 2,
+				       (wfa->mv_tree [state][label].by / 2)
+				       * 2);
+		     mc1  = mcblock1;
+		     orig = image->pixels [band] + wfa->x [state][label]
+			    + wfa->y [state][label] * image->width;
+		     
+		     for (y = height; y; y--)
+		     {
+			unsigned x;	/* column of block */
+			
+			for (x = width; x; x--)
+			   *orig++ -= *mc1++;
+
+			orig += offset;
+		     }
+		  }
+		  break;
+	       case INTERPOLATED:
+		  for (band  = first_band (image->color) + 1;
+		       band <= last_band (image->color); band++)
+		  {
+		     unsigned  y;	/* row of block */
+		     word_t   *mc1;	/* pixel in MC block 1 */
+		     word_t   *mc2;	/* pixel in MC block 2 */
+		     word_t   *orig;	/* pixel in original image */
+		     
+		     extract_mc_block (mcblock1, width, height,
+				       past->pixels [band], past->width,
+				       wfa->wfainfo->half_pixel,
+				       wfa->x [state][label],
+				       wfa->y [state][label],
+				       (wfa->mv_tree[state][label].fx / 2)
+				       * 2,
+				       (wfa->mv_tree[state][label].fy / 2)
+				       * 2);
+		     extract_mc_block (mcblock2, width, height,
+				       future->pixels [band], future->width,
+				       wfa->wfainfo->half_pixel,
+				       wfa->x [state][label],
+				       wfa->y [state][label],
+				       (wfa->mv_tree[state][label].bx / 2)
+				       * 2,
+				       (wfa->mv_tree[state][label].by / 2)
+				       * 2);
+		     mc1  = mcblock1;
+		     mc2  = mcblock2;
+		     orig = image->pixels [band] + wfa->x [state][label]
+			    + wfa->y [state][label] * image->width;
+		     
+		     for (y = height; y; y--)
+		     {
+			unsigned x;	/* column of block */
+			
+			for (x = width; x; x--)
+			   *orig++ -= (*mc1++ + *mc2++) / 2;
+
+			orig += offset;
+		     }
+		  }
+		  break;
+	       default:
+		  break;
+	    }
+	 }
+
+   Free (mcblock1);
+   Free (mcblock2);
+}
+
+void
+find_P_frame_mc (word_t *mcpe, real_t price, range_t *range,
+		 const wfa_info_t *wi, const motion_t *mt)
+/*
+ *  Determine best motion vector for P-frame.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *            range->mvt_bits  (# of mv-tree bits)
+ *            range->mvxybits  (# of bits for vector components)
+ *            mt->mcpe         (MCPE in scan-order)
+ */
+{
+   unsigned  width   = width_of_level (range->level);
+   unsigned  height  = height_of_level (range->level);
+   word_t   *mcblock = Calloc (width * height, sizeof (word_t));
+   
+   range->mv_tree_bits = 1;
+   range->mv.type      = FORWARD;
+
+   /*
+    *  Find best matching forward prediction
+    */
+   find_best_mv (price, mt->original, mt->past, range->x, range->y,
+		 width, height, &range->mv_coord_bits, &range->mv.fx,
+		 &range->mv.fy, mt->mc_forward_norms [range->level], wi, mt);
+
+   /*
+    *  Compute MCPE
+    */
+   extract_mc_block (mcblock, width, height, mt->past->pixels [GRAY],
+		     mt->past->width, wi->half_pixel, range->x, range->y,
+		     range->mv.fx, range->mv.fy);
+   get_mcpe (mcpe, mt->original, range->x, range->y, width, height,
+	     mcblock, NULL);
+
+   Free (mcblock);
+}
+
+void
+find_B_frame_mc (word_t *mcpe, real_t price, range_t *range,
+		 const wfa_info_t *wi, const motion_t *mt)
+/*
+ *  Determines best motion compensation for B-frame.
+ *  Steps:
+ *         1)  find best forward motion vector
+ *         2)  find best backward motion vector
+ *         3)  try both motion vectors together (interpolation)
+ *         4)  choose best mode (FORWARD, BACKWARD or INTERPOLATED)
+ *  Bitcodes:
+ *    FORWARD      000
+ *    BACKWARD     001
+ *    INTERPOLATED  01
+ *  
+ *  Return values:
+ *            range->mvt_bits  (# of mv-tree bits)
+ *            range->mvxybits  (# of bits for vector components)
+ *            mt->mcpe         (MCPE in scan-order)
+ */
+{
+   mc_type_e  mctype;			/* type of motion compensation */
+   real_t     forward_costs;		/* costs of FORWARD mc */
+   real_t     backward_costs;		/* costs of BACKWARD mc */
+   real_t     interp_costs;		/* costs of INTERPOLATED mc */
+   real_t     forward_bits;		/* bits for FORWARD mc */
+   real_t     backward_bits;		/* bits for BACKWARD mc */
+   real_t     interp_bits;		/* bits for INTERPOLATED mc */
+   int	      fx,  fy;			/* coordinates FORWARD mc */
+   int	      bx,  by;			/* coordinates BACKWARD mc */
+   int	      ifx, ify;			/* coordinates forw. INTERPOLATED mc */
+   int	      ibx, iby;			/* coordinates back. INTERPOLATED mc */
+   unsigned   width    = width_of_level (range->level);
+   unsigned   height   = height_of_level (range->level);
+   word_t    *mcblock1 = Calloc (width * height, sizeof (word_t));
+   word_t    *mcblock2 = Calloc (width * height, sizeof (word_t));
+   
+   /*
+    *  Forward interpolation: use past frame as reference
+    */
+   forward_costs = find_best_mv (price, mt->original, mt->past,
+				 range->x, range->y, width, height,
+				 &forward_bits, &fx, &fy,
+				 mt->mc_forward_norms [range->level], wi, mt)
+		   + 3 * price; /* code 000 */
+
+   /*
+    *  Backward interpolation: use future frame as reference
+    */
+   backward_costs = find_best_mv (price, mt->original, mt->future,
+				  range->x, range->y, width, height,
+				  &backward_bits, &bx, &by,
+				  mt->mc_backward_norms [range->level], wi, mt)
+		    + 3 * price; /* code 001 */
+
+   /*
+    *  Bidirectional interpolation: use both past and future frame as reference
+    */
+   if (wi->cross_B_search) 
+   {
+      real_t icosts1;			/* costs interpolation alternative 1 */
+      real_t icosts2;			/* costs interpolation alternative 2 */
+      real_t ibackward_bits;		/* additional bits alternative 1 */
+      real_t iforward_bits;		/* additional bits alternative 1 */
+      
+      /*
+       *  Alternative 1: keep forward mv and vary backward mv locally
+       */
+      extract_mc_block (mcblock1, width, height, mt->past->pixels [GRAY],
+			mt->past->width, wi->half_pixel,
+			range->x, range->y, fx, fy);
+
+      ibx = bx;				/* start with backward coordinates */
+      iby = by;
+      icosts1 = find_second_mv (price, mt->original, mt->future,
+				mcblock1, range->x, range->y, width, height,
+				&ibackward_bits, &ibx, &iby, wi, mt)
+		+ (forward_bits + 2) * price; /* code 01 */
+
+      /*
+       *  Alternative 2: Keep backward mv and vary forward mv locally
+       */
+      extract_mc_block (mcblock1, width, height, mt->future->pixels [GRAY],
+			mt->future->width, wi->half_pixel,
+			range->x, range->y, bx, by);
+
+      ifx = fx;
+      ify = fy;
+      icosts2 = find_second_mv (price, mt->original, mt->past,
+				mcblock1, range->x, range->y, width, height,
+				&iforward_bits, &ifx, &ify, wi, mt)
+		+ (backward_bits + 2) * price; /* code 01 */
+      
+      /*
+       *  Choose best alternative
+       */
+      if (icosts1 < icosts2)
+      {
+	 ifx 	      = fx;
+	 ify 	      = fy;
+	 interp_bits  = forward_bits + ibackward_bits;
+	 interp_costs = icosts1;
+      }
+      else
+      {
+	 ibx 	      = bx;
+	 iby 	      = by;
+	 interp_bits  = iforward_bits + backward_bits;
+	 interp_costs = icosts2;
+      }
+   }
+   else					/* local exhaustive search */
+   {
+      /*
+       *  Keep forward and backward mv due to time constraints
+       */
+
+      ifx = fx;
+      ify = fy;
+      ibx = bx;
+      iby = by;
+      interp_bits = forward_bits + backward_bits;
+
+      extract_mc_block (mcblock1, width, height, mt->past->pixels [GRAY],
+			mt->past->width, wi->half_pixel,
+			range->x, range->y, fx, fy);
+      extract_mc_block (mcblock2, width, height, mt->future->pixels [GRAY],
+			mt->future->width, wi->half_pixel,
+			range->x, range->y, bx, by);
+      interp_costs = mcpe_norm (mt->original, range->x, range->y,
+				width, height, mcblock1, mcblock2)
+		     + (interp_bits + 2) * price; /* code 01 */
+   }
+
+   /*
+    *  Choose alternative with smallest costs
+    */
+   if (forward_costs <= interp_costs)
+   {
+      if (forward_costs <= backward_costs)
+	 mctype = FORWARD;
+      else
+	 mctype = BACKWARD;
+   }
+   else
+   {
+      if (backward_costs <= interp_costs)
+	 mctype = BACKWARD;
+      else
+	 mctype = INTERPOLATED;
+   }
+
+   switch (mctype)
+   {
+      case FORWARD:
+	 range->mv_tree_bits  = 3;
+	 range->mv_coord_bits = forward_bits;
+	 range->mv.type       = FORWARD;
+	 range->mv.fx         = fx;
+	 range->mv.fy         = fy;
+	 extract_mc_block (mcblock1, width, height, mt->past->pixels [GRAY],
+			   mt->past->width, wi->half_pixel,
+			   range->x, range->y, range->mv.fx, range->mv.fy);
+	 get_mcpe (mcpe, mt->original, range->x, range->y, width, height,
+		   mcblock1, NULL);
+	 break;
+      case BACKWARD:
+	 range->mv_tree_bits  = 3;
+	 range->mv_coord_bits = backward_bits;
+	 range->mv.type       = BACKWARD;
+	 range->mv.bx         = bx;
+	 range->mv.by         = by;
+	 extract_mc_block (mcblock1, width, height, mt->future->pixels [GRAY],
+			   mt->future->width, wi->half_pixel,
+			   range->x, range->y, range->mv.bx, range->mv.by);
+	 get_mcpe (mcpe, mt->original, range->x, range->y, width, height,
+		   mcblock1, NULL);
+	 break;
+      case INTERPOLATED:
+	 range->mv_tree_bits  = 2;
+	 range->mv_coord_bits = interp_bits;
+	 range->mv.type       = INTERPOLATED;
+	 range->mv.fx         = ifx;
+	 range->mv.fy         = ify;
+	 range->mv.bx         = ibx;
+	 range->mv.by         = iby;
+	 extract_mc_block (mcblock1, width, height, mt->past->pixels [GRAY],
+			   mt->past->width, wi->half_pixel,
+			   range->x, range->y, range->mv.fx, range->mv.fy);
+	 extract_mc_block (mcblock2, width, height, mt->future->pixels [GRAY],
+			   mt->future->width, wi->half_pixel,
+			   range->x, range->y, range->mv.bx, range->mv.by);
+	 get_mcpe (mcpe, mt->original, range->x, range->y, width, height,
+		   mcblock1, mcblock2);
+	 break;
+      default:
+	 break;
+   }
+
+   Free (mcblock1);
+   Free (mcblock2);
+}
+
+void
+fill_norms_table (unsigned x0, unsigned y0, unsigned level,
+		  const wfa_info_t *wi, motion_t *mt)
+/*
+ *  Compute norms of difference images for all possible displacements
+ *  in 'mc_forward_norm' and 'mc_backward_norm'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'mt->mc_backward_norms' are computed
+ *	'mt->mc_forward_norms' are computed 
+ */
+{
+   int	     mx, my;			/* coordinates of motion vector */
+   unsigned  sr;			/* mv search range +-'sr' pixels */
+   unsigned  index   = 0;		/* index of motion vector */
+   unsigned  width   = width_of_level (level);
+   unsigned  height  = height_of_level (level);
+   word_t   *mcblock = Calloc (width * height, sizeof (word_t));
+
+   sr = wi->half_pixel ? wi->search_range / 2 :  wi->search_range;
+   
+   for (my = -sr; my < (int) sr; my++)
+      for (mx = -sr; mx < (int) sr; mx++, index++)
+      {
+	  if ((int) x0 + mx < 0 ||	/* block outside visible area */
+	      x0 + mx + width > mt->original->width || 
+	      (int) y0 + my < 0 ||
+	      y0 + my + height > mt->original->height)
+	  {
+	     mt->mc_forward_norms [level][index]  = 0.0;
+	     mt->mc_backward_norms [level][index] = 0.0;
+	  }
+	  else
+	  {
+	     extract_mc_block (mcblock, width, height, mt->past->pixels [GRAY],
+			       mt->past->width, wi->half_pixel,
+			       x0, y0, mx, my);
+	     mt->mc_forward_norms [level][index]
+		= mcpe_norm (mt->original, x0, y0, width, height,
+			     mcblock, NULL);
+
+	     if (mt->frame_type == B_FRAME)
+	     {
+		extract_mc_block (mcblock, width, height,
+				  mt->future->pixels [GRAY],
+				  mt->future->width, wi->half_pixel,
+				  x0, y0, mx, my);
+		mt->mc_backward_norms[level][index]
+		   = mcpe_norm (mt->original, x0, y0, width, height,
+				mcblock, NULL); 
+	     }
+	  }
+       }
+
+   Free (mcblock);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+get_mcpe (word_t *mcpe, const image_t *original, unsigned x0, unsigned y0,
+	  unsigned width, unsigned height, const word_t *mcblock1,
+	  const word_t *mcblock2)
+/*
+ *  Compute MCPE image 'original' - reference. The reference is either
+ *  composed of 'mcblock1' or of ('mcblock1' + 'mcblock2') / 2 (if
+ *  'mcblock2' != NULL).  Coordinates of original block are given by
+ *  'x0', 'y0', 'width', and 'height'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'mcpe []' is filled with the delta image
+ */
+{
+   const word_t	*oblock;		/* pointer to original image */
+
+   assert (mcpe);
+   
+   oblock = original->pixels [GRAY] + y0 * original->width + x0;
+
+   if (mcblock2 != NULL)		/* interpolated prediction */
+   {
+      unsigned x, y;			/* current coordinates */
+      
+      for (y = height; y; y--) 
+      {
+	 for (x = width; x; x--)
+	    *mcpe++ = *oblock++ - (*mcblock1++ + *mcblock2++) / 2;
+
+	 oblock += original->width - width;
+      }
+   }
+   else					/* forward or backward prediction */
+   {
+      unsigned x, y;			/* current coordinates */
+      
+      for (y = height; y; y--) 
+      {
+	 for (x = width; x; x--)
+	    *mcpe++ = *oblock++ - *mcblock1++;
+      
+	 oblock += original->width - width;
+      }
+   }
+}
+
+static real_t
+mcpe_norm (const image_t *original, unsigned x0, unsigned y0, unsigned width,
+	   unsigned height, const word_t *mcblock1, const word_t *mcblock2)
+/*
+ *  Compute norm of motion compensation prediction error.
+ *  Coordinates of 'original' block are given by ('x0', 'y0')
+ *  and 'width', 'height'.
+ *  Reference blocks are stored in 'mcimage1' and 'mcimage2'.
+ *
+ *  Return value:
+ *	square of norm of difference image
+ */
+{
+   unsigned  n;
+   real_t    norm = 0;
+   word_t   *mcpe = Calloc (width * height, sizeof (word_t));
+   word_t   *ptr  = mcpe;
+   
+   get_mcpe (mcpe, original, x0, y0, width, height, mcblock1, mcblock2);
+
+   for (n = height * width; n; n--, ptr++) 
+      norm += square (*ptr / 16);
+   
+   Free (mcpe);
+   
+   return norm;
+}
+
+static real_t 
+find_best_mv (real_t price, const image_t *original, const image_t *reference,
+	      unsigned x0, unsigned y0, unsigned width, unsigned height,
+	      real_t *bits, int *mx, int *my, const real_t *mc_norms,
+	      const wfa_info_t *wi, const motion_t *mt)
+/*
+ *  Find best matching motion vector in image 'reference' to predict
+ *  the block ('x0', 'y0') of size 'width'x'height in image 'original'.
+ *
+ *  Return values:
+ *	prediction costs
+ *
+ *  Side effects:
+ *	'mx', 'my'		coordinates of motion vector
+ *	'bits'			number of bits to encode mv
+ */
+{
+   unsigned sr;				/* mv search range +/- 'sr' pixels */
+   unsigned index;			/* index of motion vector */
+   int 	    x, y;			/* coordinates of motion vector */
+   real_t   costs;			/* costs arising if mv is chosen */
+   real_t   mincosts = MAXCOSTS;	/* best costs so far  */
+   unsigned bitshift;			/* half_pixel coordinates multiplier */
+   
+   *mx = *my = 0;
+
+   /*
+    *  Find best fitting motion vector:
+    *  Use exhaustive search in the interval x,y +- sr (no halfpixel accuracy)
+    *					  or x,y +- sr/2  (halfpixel accuracy)
+    */
+   sr 	    = wi->half_pixel ? wi->search_range / 2 :  wi->search_range;
+   bitshift = (wi->half_pixel ? 2 : 1);	/* bit0 reserved for halfpixel pred. */
+   
+   for (index = 0, y = -sr; y < (int) sr; y++)
+      for (x = -sr; x < (int) sr; x++, index++)
+	 if ((int) x0 + x >= 0 && (int) y0 + y >= 0 &&	
+	     x0 + x + width  <= original->width && 
+	     y0 + y + height <= original->height)
+	 {
+	    /*
+	     *  Block is inside visible area.
+	     *  Compare current costs with 'mincosts'
+	     */
+	    costs = mc_norms [index]
+		    + (mt->xbits [(x + sr) * bitshift]
+		       + mt->ybits [(y + sr) * bitshift]) * price;
+
+	     if (costs < mincosts)
+	     {
+		mincosts = costs;
+		*mx      = x * bitshift;
+		*my      = y * bitshift;
+	     }
+	 }
+
+   /*
+    *  Halfpixel prediction:
+    *  Compare all nine combinations (-1, y), (0, y), (+1, y) for y = -1,0,+1
+    */
+   if (wi->half_pixel)
+   {
+      int	rx, ry;			/* halfpixel refinement */
+      unsigned	bestrx, bestry;		/* coordinates of best mv */
+      word_t   *mcblock = Calloc (width * height, sizeof (word_t));
+      
+      bestrx = bestry = 0;
+      for (rx = -1; rx <= 1; rx++)
+	 for (ry = -1; ry <= 1; ry++)
+	 {
+	    /*
+	     *  Check if the new motion vector is in allowed area
+	     */
+	    if (rx == 0 && ry == 0)	/* already tested */
+	       continue;
+	    if ((int) x0 + (*mx / 2) + rx < 0 || /* outside visible area */
+		x0 + (*mx / 2) + rx + width > original->width ||
+		(int) y0 + (*my / 2) + ry < 0 || 
+		y0 + (*my / 2) + ry + height > original->height)
+	       continue;
+	    if (*mx + rx < (int) -sr || *mx + rx >= (int) sr ||
+		*my + ry < (int) -sr || *my + ry >= (int) sr) 
+	       continue;		/* out of bounds */
+
+	    /*
+	     *  Compute costs of new motion compensation
+	     */
+	    extract_mc_block (mcblock, width, height,
+			      reference->pixels [GRAY],
+			      reference->width, wi->half_pixel,
+			      x0, y0, *mx + rx, *my + ry);
+	    costs = mcpe_norm (mt->original, x0, y0, width, height, mcblock,
+			       NULL)
+		    + (mt->xbits [*mx + rx + sr * bitshift]
+		       + mt->ybits [*my + ry + sr * bitshift]) * price;
+	    if (costs < mincosts)
+	    {
+	       bestrx   = rx;
+	       bestry   = ry;
+	       mincosts = costs;
+	    }
+	 }
+
+      *mx += bestrx;
+      *my += bestry;
+
+      Free (mcblock);
+   } /* halfpixel */
+	     
+   *bits = mt->xbits [*mx + sr * bitshift] + mt->ybits [*my + sr * bitshift];
+
+   return mincosts;
+}
+
+static real_t
+find_second_mv (real_t price, const image_t *original,
+		const image_t *reference, const word_t *mcblock1,
+		unsigned xr, unsigned yr, unsigned width, unsigned height,
+		real_t *bits, int *mx, int *my, const wfa_info_t *wi,
+		const motion_t *mt)
+/*
+ *  Search local area (*mx,*my) for best additional mv.
+ *  Overwrite mt->tmpblock.
+ *  TODO check sr = search_range
+ *
+ *  Return values:
+ *	prediction costs
+ *
+ *  Side effects:
+ *	'mx','my'	coordinates of mv
+ *      'bits'		number of bits to encode mv
+ */
+{
+   real_t    mincosts = MAXCOSTS;	/* best costs so far  */
+   unsigned  sr;			/* MV search range +/- 'sr' pixels */
+   int       x, y;			/* coordinates of motion vector */
+   int       y0, y1, x0, x1;		/* start/end coord. of search range */
+   unsigned  bitshift;			/* half_pixel coordinates multiplier */
+   word_t   *mcblock2 = Calloc (width * height, sizeof (word_t));
+
+   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);
+
+   *mx = *my = 0;
+
+   bitshift = (wi->half_pixel ? 2 : 1);	/* bit0 reserved for halfpixel pred. */
+
+   
+   for (y = y0; y < y1; y++)
+      for (x = x0; x < x1; x++)
+      {
+	 real_t costs;			/* costs arising if mv is chosen */
+	 
+	 /*
+	  *  Test each mv ('x', 'y') in the given search range:
+	  *  Get the new motion compensation image from 'reference' and compute
+	  *  the norm of the motion compensation prediction error
+	  *  'original' - 0.5 * ('firstmc' + 'reference')
+	  */
+	 if ((int) (xr * bitshift) + x < 0 ||	/* outside visible area */
+	     xr * bitshift + x > (original->width - width) * bitshift ||
+	     (int) (yr * bitshift) + y < 0 ||
+	     yr * bitshift + y > (original->height - height) * bitshift)
+	    continue;
+	 
+	 extract_mc_block (mcblock2, width, height,
+			   reference->pixels [GRAY], reference->width,
+			   wi->half_pixel, x0, y0, x, y);
+
+	 costs  = mcpe_norm (mt->original, x0, y0, width, height,
+			     mcblock1, mcblock2)
+		  + (mt->xbits [x + sr] + mt->ybits [y + sr]) * price;
+	 
+	 if (costs < mincosts)
+	 {
+	    mincosts = costs;
+	    *mx      = x;
+	    *my      = y;
+	 }
+      }
+
+   *bits = mt->xbits [*mx + sr] + mt->ybits [*my + sr];
+
+   Free (mcblock2);
+
+   return mincosts;
+}
diff --git a/converter/other/fiasco/codec/mwfa.h b/converter/other/fiasco/codec/mwfa.h
new file mode 100644
index 00000000..52f41866
--- /dev/null
+++ b/converter/other/fiasco/codec/mwfa.h
@@ -0,0 +1,44 @@
+/*
+ *  mwfa.h
+ *
+ *  Written by:		Michael Unger
+ *			Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _MWFA_H
+#define _MWFA_H
+
+#include "types.h"
+#include "image.h"
+#include "wfa.h"
+#include "cwfa.h"
+
+void
+fill_norms_table (unsigned x0, unsigned y0, unsigned level,
+		  const wfa_info_t *wi, motion_t *mt);
+void
+find_B_frame_mc (word_t *mcpe, real_t price, range_t *range,
+		 const wfa_info_t *wi, const motion_t *mt);
+void
+find_P_frame_mc (word_t *mcpe, real_t price, range_t *range,
+		 const wfa_info_t *wi, const motion_t *mt);
+void
+subtract_mc (image_t *image, const image_t *past, const image_t *future,
+	     const wfa_t *wfa);
+void
+free_motion (motion_t *mt);
+motion_t *
+alloc_motion (const wfa_info_t *wi);
+
+#endif /* not _MWFA_H */
+
diff --git a/converter/other/fiasco/codec/options.c b/converter/other/fiasco/codec/options.c
new file mode 100644
index 00000000..77dbaf00
--- /dev/null
+++ b/converter/other/fiasco/codec/options.c
@@ -0,0 +1,894 @@
+/*
+ *  options.c:		FIASCO options handling
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/10/28 17:39:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.5 $
+ *  $State: Exp $
+ */
+
+#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include "config.h"
+
+#include <string.h>
+#if STDC_HEADERS
+#	include <stdlib.h>
+#endif /* not STDC_HEADERS */
+
+#include <stdio.h>
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "misc.h"
+#include "bit-io.h"
+#include "fiasco.h"
+#include "options.h"
+
+fiasco_c_options_t *
+fiasco_c_options_new (void)
+/*
+ *  FIASCO options constructor.
+ *  Allocate memory for the FIASCO coder options structure and
+ *  fill in default values.
+ *
+ *  Return value:
+ *	pointer to the new option structure
+ */
+{
+   c_options_t 	      *options = calloc (1, sizeof (c_options_t));
+   fiasco_c_options_t *public  = calloc (1, sizeof (fiasco_c_options_t));
+
+   if (!options || !public)
+   {
+      set_error (_("Out of memory."));
+      return NULL;
+   }
+   public->private 	      = options;
+   public->delete 	      = fiasco_c_options_delete;
+   public->set_tiling 	      = fiasco_c_options_set_tiling;
+   public->set_frame_pattern  = fiasco_c_options_set_frame_pattern;
+   public->set_basisfile      = fiasco_c_options_set_basisfile;
+   public->set_chroma_quality = fiasco_c_options_set_chroma_quality;
+   public->set_optimizations  = fiasco_c_options_set_optimizations;
+   public->set_video_param    = fiasco_c_options_set_video_param;
+   public->set_quantization   = fiasco_c_options_set_quantization;
+   public->set_progress_meter = fiasco_c_options_set_progress_meter;
+   public->set_smoothing      = fiasco_c_options_set_smoothing;
+   public->set_title   	      = fiasco_c_options_set_title;
+   public->set_comment        = fiasco_c_options_set_comment;
+   
+   strcpy (options->id, "COFIASCO");
+
+   /*
+    *  Set default value of fiasco options
+    */
+   options->basis_name 		  = strdup ("small.fco");
+   options->lc_min_level 	  = 4;
+   options->lc_max_level 	  = 12;
+   options->p_min_level 	  = 8;
+   options->p_max_level 	  = 10;
+   options->images_level 	  = 5;
+   options->max_states 		  = MAXSTATES;
+   options->chroma_max_states 	  = 40;
+   options->max_elements 	  = MAXEDGES;
+   options->tiling_exponent 	  = 4;
+   options->tiling_method 	  = FIASCO_TILING_VARIANCE_DSC;
+   options->id_domain_pool 	  = strdup ("rle");
+   options->id_d_domain_pool 	  = strdup ("rle");
+   options->id_rpf_model 	  = strdup ("adaptive");
+   options->id_d_rpf_model 	  = strdup ("adaptive");
+   options->rpf_mantissa 	  = 3;
+   options->rpf_range 		  = FIASCO_RPF_RANGE_1_50;
+   options->dc_rpf_mantissa 	  = 5;
+   options->dc_rpf_range 	  = FIASCO_RPF_RANGE_1_00;
+   options->d_rpf_mantissa 	  = 3;
+   options->d_rpf_range 	  = FIASCO_RPF_RANGE_1_50;
+   options->d_dc_rpf_mantissa 	  = 5;
+   options->d_dc_rpf_range 	  = FIASCO_RPF_RANGE_1_00;
+   options->chroma_decrease 	  = 2.0;
+   options->prediction 		  = NO;
+   options->delta_domains 	  = YES;
+   options->normal_domains 	  = YES;
+   options->search_range 	  = 16;
+   options->fps 		  = 25;
+   options->pattern 		  = strdup ("IPPPPPPPPP");
+   options->reference_filename 	  = NULL;
+   options->half_pixel_prediction = NO;
+   options->cross_B_search 	  = YES;
+   options->B_as_past_ref 	  = YES;
+   options->check_for_underflow   = NO;
+   options->check_for_overflow 	  = NO;
+   options->second_domain_block   = NO;
+   options->full_search 	  = NO;
+   options->progress_meter 	  = FIASCO_PROGRESS_NONE;
+   options->smoothing 	 	  = 70;
+   options->comment 		  = strdup ("");
+   options->title 		  = strdup ("");
+   
+   return public;
+}
+
+void
+fiasco_c_options_delete (fiasco_c_options_t *options)
+/*
+ *  FIASCO options destructor.
+ *  Free memory of FIASCO options struct.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	structure 'options' is discarded.
+ */
+{
+   c_options_t *this = cast_c_options (options);
+
+   if (!this)
+      return;
+   
+   Free (this->id_domain_pool);
+   Free (this->id_d_domain_pool);
+   Free (this->id_rpf_model);
+   Free (this->id_d_rpf_model);
+   Free (this->pattern);
+   Free (this->comment);
+   Free (this->title);
+   
+   Free (this);
+
+   return;
+}
+
+int
+fiasco_c_options_set_tiling (fiasco_c_options_t *options,
+			     fiasco_tiling_e method, unsigned exponent)
+/*
+ *  Set tiling `method' and `exponent'.
+ *  See type `fiasco_tiling_e' for a list of valid  tiling `methods'.
+ *  The image is subdivied into 2^`exponent' tiles
+ *
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   switch (method)
+   {
+      case FIASCO_TILING_SPIRAL_ASC:
+      case FIASCO_TILING_SPIRAL_DSC:
+      case FIASCO_TILING_VARIANCE_ASC:
+      case FIASCO_TILING_VARIANCE_DSC:
+	 this->tiling_method = method;
+	 break;
+      default:
+	 set_error (_("Invalid tiling method `%d' specified "
+		      "(valid methods are 0, 1, 2, or 3)."), method);
+	 return 0;
+   }
+   this->tiling_exponent = exponent;
+   
+   return 1;
+}
+
+int
+fiasco_c_options_set_frame_pattern (fiasco_c_options_t *options,
+				    const char *pattern)
+/*
+ *  Set `pattern' of input frames.
+ *  `pattern' has to be a sequence of the following
+ *  characters (case insensitive):
+ *  'i' intra frame
+ *  'p' predicted frame
+ *  'b' bidirectional predicted frame
+ *  E.g. pattern = 'IBBPBBPBB'
+ *
+ *  When coding video frames the prediction type of input frame N is determined
+ *  by reading `pattern' [N] (`pattern' is periodically extended).
+ *  
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else if (!pattern)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "pattern");
+      return 0;
+   }
+   else if (strlen (pattern) < 1)
+   {
+      set_error (_("Frame type pattern doesn't contain any character."));
+      return 0;
+   }
+   else
+   {
+      const char *str;
+      bool_t 	  parse_error = NO;
+      int	  c 	      = 0;
+      
+      for (str = pattern; *str && !parse_error; str++)
+	 switch (*str)
+	 {
+	    case 'i':
+	    case 'I':
+	    case 'b':
+	    case 'B':
+	    case 'p':
+	    case 'P':
+	       break;
+	    default:
+	       c = *str;
+	       parse_error = YES;
+	 }
+
+      if (parse_error)
+      {
+	 set_error (_("Frame type pattern contains invalid character `%c' "
+		      "(choose I, B or P)."), c);
+	 return 0;
+      }
+      else
+      {
+	 Free (this->pattern);
+	 this->pattern = strdup (pattern);
+
+	 return 1;
+      }
+   }
+}
+
+int
+fiasco_c_options_set_basisfile (fiasco_c_options_t *options,
+				const char *filename)
+/*
+ *  Set `filename' of FIASCO initial basis.
+ *  
+ *  Return value:
+ *	1 on success (if the file is readable)
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else if (!filename)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "filename");
+      return 0;
+   }
+   else
+   {
+       /* Skip this because basis file may be linked with program, not
+          in a separate file.  See get_linked_basis().  NETPBM
+      FILE *file = open_file (filename, "FIASCO_DATA", READ_ACCESS);
+      if (file)
+      {
+	 fclose (file);
+	 return 1;
+      }
+      else
+      {
+	 set_error (_("Can't read basis file `%s'.\n%s."), filename,
+		    get_system_error ());
+	 return 0;
+      }
+      */ return 1;
+   }
+}
+
+int
+fiasco_c_options_set_chroma_quality (fiasco_c_options_t *options,
+				     float quality_factor,
+				     unsigned dictionary_size)
+/*
+ *  Set color compression parameters.
+ *  When coding chroma channels (Cb and Cr)
+ *  - approximation quality is given by `quality_factor' * `Y quality' and
+ *  - `dictionary_size' gives the number of dictionary elements.
+ *  
+ *  If 'quality' <= 0 then the luminancy coding quality is also during
+ *  chroma channel coding.
+ *  
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else if (!dictionary_size)
+   {
+      set_error (_("Size of chroma compression dictionary has to be "
+		   "a positive number."));
+      return 0;
+   }
+   else if (quality_factor <= 0)
+   {
+      set_error (_("Quality of chroma channel compression has to be "
+		   "positive value."));
+      return 0;
+   }
+   else
+   {
+      this->chroma_decrease   = quality_factor;
+      this->chroma_max_states = dictionary_size;
+
+      return 1;
+   }
+}
+
+int
+fiasco_c_options_set_optimizations (fiasco_c_options_t *options,
+				    unsigned min_block_level,
+				    unsigned max_block_level,
+				    unsigned max_elements,
+				    unsigned dictionary_size,
+				    unsigned optimization_level)
+/*
+ *  Set various optimization parameters.
+ *  - During compression only image blocks of size
+ *    {`min_block_level', ... ,`max_block_level'} are considered.
+ *    The smaller this set of blocks is the faster the coder runs
+ *    and the worse the image quality will be.  
+ *  - An individual approximation may use at most `max_elements'
+ *    elements of the dictionary which itself contains at most
+ *    `dictionary_size' elements. The smaller these values are
+ *    the faster the coder runs and the worse the image quality will be. 
+ *  - `optimization_level' enables some additional low level optimizations.
+ *    0: standard approximation method
+ *    1: significantly increases the approximation quality,
+ *       running time is twice as high as with the standard method
+ *    2: hardly increases the approximation quality of method 1, 
+ *       running time is twice as high as with method 1
+ *       (this method just remains for completeness)
+ *
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else if (!dictionary_size)
+   {
+      set_error (_("Size of dictionary has to be a positive number."));
+      return 0;
+   }
+   else if (!max_elements)
+   {
+      set_error (_("At least one dictionary element has to be used "
+		   "in an approximation."));
+      return 0;
+   }
+   else if (max_block_level < 4)
+   {
+      set_error (_("Maximum image block size has to be at least level 4."));
+      return 0;
+   }
+   else if (min_block_level < 4)
+   {
+      set_error (_("Minimum image block size has to be at least level 4."));
+      return 0;
+   }
+   else if (max_block_level < min_block_level)
+   {
+      set_error (_("Maximum block size has to be larger or "
+		   "equal minimum block size."));
+      return 0;
+   }
+   else
+   {
+      this->lc_min_level 	= min_block_level;
+      this->lc_max_level 	= max_block_level;
+      this->max_states 	 	= dictionary_size;
+      this->max_elements 	= max_elements;
+      this->second_domain_block = optimization_level > 0 ? YES : NO;
+      this->check_for_overflow  = optimization_level > 1 ? YES : NO;
+      this->check_for_underflow = optimization_level > 1 ? YES : NO;
+      this->full_search 	= optimization_level > 1 ? YES : NO;
+
+      return 1;
+   }
+}
+
+int
+fiasco_c_options_set_prediction (fiasco_c_options_t *options,
+				 int intra_prediction,
+				 unsigned min_block_level,
+				 unsigned max_block_level)
+/*
+ *  Set minimum and maximum size of image block prediction to
+ *  `min_block_level' and `max_block_level'.
+ *  (For either motion compensated prediction of inter frames
+ *   or DC based prediction of intra frames)
+ *  Prediction of intra frames is only used if `intra_prediction' != 0.
+ *
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else if (max_block_level < 6)
+   {
+      set_error (_("Maximum prediction block size has to be "
+		   "at least level 6"));
+      return 0;
+   }
+   else if (min_block_level < 6)
+   {
+      set_error (_("Minimum prediction block size has to be "
+		   "at least level 6"));
+      return 0;
+   }
+   else if (max_block_level < min_block_level)
+   {
+      set_error (_("Maximum prediction block size has to be larger or "
+		   "equal minimum block size."));
+      return 0;
+   }
+   else
+   {
+      this->p_min_level = min_block_level;
+      this->p_max_level = max_block_level;
+      this->prediction  = intra_prediction;
+      
+      return 1;
+   }
+}
+
+int
+fiasco_c_options_set_video_param (fiasco_c_options_t *options,
+				  unsigned frames_per_second,
+				  int half_pixel_prediction,
+				  int cross_B_search,
+				  int B_as_past_ref)
+/*
+ *  Set various parameters used for video compensation.
+ *  'frames_per_second' defines the frame rate which should be
+ *  used when the video is decoded. This value has no effect during coding,
+ *  it is just passed to the FIASCO output file.
+ *  If 'half_pixel_prediction' is not 0 then half pixel precise
+ *  motion compensated prediction is used.
+ *  If 'cross_B_search' is not 0 then the fast Cross-B-Search algorithm is
+ *  used to determine the motion vectors of interpolated prediction. Otherwise
+ *  exhaustive search (in the given search range) is used.
+ *  If 'B_as_past_ref' is not 0 then B frames are allowed to be used
+ *  for B frame predicion.
+ *  
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else
+   {
+      this->fps 	  	  = frames_per_second;
+      this->half_pixel_prediction = half_pixel_prediction;
+      this->cross_B_search 	  = cross_B_search;
+      this->B_as_past_ref 	  = B_as_past_ref;
+
+      return 1;
+   }
+}
+
+int
+fiasco_c_options_set_quantization (fiasco_c_options_t *options,
+				   unsigned mantissa,
+				   fiasco_rpf_range_e range,
+				   unsigned dc_mantissa,
+				   fiasco_rpf_range_e dc_range)
+/*
+ *  Set accuracy of coefficients quantization.
+ *  DC coefficients (of the constant dictionary vector f(x,y) = 1)
+ *  are quantized to values of the interval [-`dc_range', `dc_range'] using
+ *  #`dc_mantissa' bits. All other quantized coefficients are quantized in
+ *  an analogous way using the parameters `range' and `mantissa'.
+ *  
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else if (mantissa < 2 || mantissa > 8 || dc_mantissa < 2 || dc_mantissa > 8)
+   {
+      set_error (_("Number of RPF mantissa bits `%d', `%d' have to be in "
+		   "the interval [2,8]."), mantissa, dc_mantissa);
+      return 0;
+   }
+   else
+   {
+      if ((range == FIASCO_RPF_RANGE_0_75
+	  || range == FIASCO_RPF_RANGE_1_00
+	  || range == FIASCO_RPF_RANGE_1_50
+	   || range == FIASCO_RPF_RANGE_2_00)
+	  &&
+	  (dc_range == FIASCO_RPF_RANGE_0_75
+	   || dc_range == FIASCO_RPF_RANGE_1_00
+	   || dc_range == FIASCO_RPF_RANGE_1_50
+	   || dc_range == FIASCO_RPF_RANGE_2_00))
+      {
+	 this->rpf_range       = range;
+	 this->dc_rpf_range    = dc_range;
+	 this->rpf_mantissa    = mantissa;
+	 this->dc_rpf_mantissa = dc_mantissa;
+
+	 return 1;
+      }
+      else
+      {
+	 set_error (_("Invalid RPF ranges `%d', `%d' specified."),
+		    range, dc_range);
+	 return 0;
+      }
+   }
+}
+
+int
+fiasco_c_options_set_progress_meter (fiasco_c_options_t *options,
+				     fiasco_progress_e type)
+/*
+ *  Set type of progress meter.
+ *
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   switch (type)
+   {
+      case FIASCO_PROGRESS_BAR:
+      case FIASCO_PROGRESS_PERCENT:
+      case FIASCO_PROGRESS_NONE:
+	 this->progress_meter = type;
+	 break;
+      default:
+	 set_error (_("Invalid progress meter `%d' specified "
+		      "(valid values are 0, 1, or 2)."), type);
+	 return 0;
+   }
+   return 1;
+}
+
+int
+fiasco_c_options_set_smoothing (fiasco_c_options_t *options, int smoothing)
+/*
+ *  Define `smoothing'-percentage along partitioning borders.
+ *  
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else if (smoothing < -1 || smoothing > 100)
+   {
+      set_error (_("Smoothing percentage must be in the range [-1, 100]."));
+      return 0;
+   }
+   else
+   {
+      this->smoothing = smoothing;
+      return 1;
+   }
+}
+
+int
+fiasco_c_options_set_comment (fiasco_c_options_t *options, const char *comment)
+/*
+ *  Define `comment' of FIASCO stream.
+ *  
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else if (!comment)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "title");
+      return 0;
+   }
+   else
+   {
+      this->comment = strdup (comment);
+      return 1;
+   }
+}
+
+int
+fiasco_c_options_set_title (fiasco_c_options_t *options, const char *title)
+/*
+ *  Define `title' of FIASCO stream.
+ *  
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) cast_c_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else if (!title)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "title");
+      return 0;
+   }
+   else
+   {
+      this->title = strdup (title);
+      return 1;
+   }
+}
+
+c_options_t *
+cast_c_options (fiasco_c_options_t *options)
+/*
+ *  Cast generic pointer `options' to type c_options_t.
+ *  Check whether `options' is a valid object of type c_options_t.
+ *
+ *  Return value:
+ *	pointer to options struct on success
+ *      NULL otherwise
+ */
+{
+   c_options_t *this = (c_options_t *) options->private;
+   if (this)
+   {
+      if (!streq (this->id, "COFIASCO"))
+      {
+	 set_error (_("Parameter `options' doesn't match required type."));
+	 return NULL;
+      }
+   }
+   else
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "options");
+   }
+
+   return this;
+}
+
+/**************************************************************************
+***************************************************************************
+			       DECODER
+***************************************************************************
+**************************************************************************/
+
+fiasco_d_options_t *
+fiasco_d_options_new (void)
+/*
+ *  FIASCO options constructor.
+ *  Allocate memory for the FIASCO coder options structure and
+ *  fill in default values.
+ *
+ *  Return value:
+ *	pointer to the new option structure
+ */
+{
+   d_options_t 	      *options = calloc (1, sizeof (d_options_t));
+   fiasco_d_options_t *public  = calloc (1, sizeof (fiasco_d_options_t));
+
+   if (!options || !public)
+   {
+      set_error (_("Out of memory."));
+      return NULL;
+   }
+   public->private 	      = options;
+   public->delete 	      = fiasco_d_options_delete;
+   public->set_smoothing      = fiasco_d_options_set_smoothing;
+   public->set_magnification  = fiasco_d_options_set_magnification;
+   public->set_4_2_0_format   = fiasco_d_options_set_4_2_0_format;
+   
+   strcpy (options->id, "DOFIASCO");
+
+   /*
+    *  Set default value of fiasco decoder options
+    */
+   options->smoothing 	  = 70;
+   options->magnification = 0;
+   options->image_format  = FORMAT_4_4_4;
+   
+   return public;
+}
+
+void
+fiasco_d_options_delete (fiasco_d_options_t *options)
+/*
+ *  FIASCO options destructor.
+ *  Free memory of FIASCO options struct.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	structure 'options' is discarded.
+ */
+{
+   d_options_t *this = cast_d_options (options);
+
+   if (!this)
+      return;
+   
+   Free (this);
+
+   return;
+}
+
+int
+fiasco_d_options_set_smoothing (fiasco_d_options_t *options, int smoothing)
+/*
+ *  Define `smoothing'-percentage along partitioning borders.
+ *  
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   d_options_t *this = (d_options_t *) cast_d_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else if (smoothing < -1 || smoothing > 100)
+   {
+      set_error (_("Smoothing percentage must be in the range [-1, 100]."));
+      return 0;
+   }
+   else
+   {
+      this->smoothing = smoothing;
+      return 1;
+   }
+}
+
+int
+fiasco_d_options_set_magnification (fiasco_d_options_t *options, int level)
+/*
+ *  Set magnification-'level' of decoded image.
+ *  0: width x height of original image
+ *  1: (2 * width) x (2 * height) of original image
+ *  -1: (width / 2 ) x (height / 2) of original image
+ *  etc.
+ *
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   d_options_t *this = (d_options_t *) cast_d_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else
+   {
+      this->magnification = level;
+      return 1;
+   }
+}
+
+int
+fiasco_d_options_set_4_2_0_format (fiasco_d_options_t *options, int format)
+/*
+ *  Set image format to 4:2:0 or 4:4:4.
+ *  
+ *  Return value:
+ *	1 on success
+ *	0 otherwise
+ */
+{
+   d_options_t *this = (d_options_t *) cast_d_options (options);
+
+   if (!this)
+   {
+      return 0;
+   }
+   else
+   {
+      this->image_format = format ? FORMAT_4_2_0 : FORMAT_4_4_4;
+      return 1;
+   }
+}
+
+d_options_t *
+cast_d_options (fiasco_d_options_t *options)
+/*
+ *  Cast generic pointer `options' to type d_options_t.
+ *  Check whether `options' is a valid object of type d_options_t.
+ *
+ *  Return value:
+ *	pointer to options struct on success
+ *      NULL otherwise
+ */
+{
+   d_options_t *this = (d_options_t *) options->private;
+   
+   if (this)
+   {
+      if (!streq (this->id, "DOFIASCO"))
+      {
+	 set_error (_("Parameter `options' doesn't match required type."));
+	 return NULL;
+      }
+   }
+   else
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "options");
+   }
+
+   return this;
+}
+
+
diff --git a/converter/other/fiasco/codec/options.h b/converter/other/fiasco/codec/options.h
new file mode 100644
index 00000000..3af6be01
--- /dev/null
+++ b/converter/other/fiasco/codec/options.h
@@ -0,0 +1,80 @@
+/*
+ *  options.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/10/28 17:39:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.4 $
+ *  $State: Exp $
+ */
+
+#ifndef _OPTIONS_H
+#define _OPTIONS_H
+
+typedef struct c_options
+{
+   char      	       id [9];
+   char  	      *basis_name;
+   unsigned  	       lc_min_level;
+   unsigned  	       lc_max_level;
+   unsigned  	       p_min_level;
+   unsigned  	       p_max_level;
+   unsigned  	       images_level;
+   unsigned  	       max_states;
+   unsigned  	       chroma_max_states;
+   unsigned  	       max_elements;
+   unsigned  	       tiling_exponent;
+   fiasco_tiling_e     tiling_method;
+   char        	      *id_domain_pool;
+   char        	      *id_d_domain_pool;
+   char        	      *id_rpf_model;
+   char        	      *id_d_rpf_model;
+   unsigned  	       rpf_mantissa;
+   real_t    	       rpf_range;
+   unsigned  	       dc_rpf_mantissa;
+   fiasco_rpf_range_e  dc_rpf_range;
+   unsigned  	       d_rpf_mantissa;
+   fiasco_rpf_range_e  d_rpf_range;
+   unsigned  	       d_dc_rpf_mantissa;
+   fiasco_rpf_range_e  d_dc_rpf_range;
+   real_t    	       chroma_decrease;
+   bool_t    	       prediction;
+   bool_t    	       delta_domains;
+   bool_t    	       normal_domains;
+   unsigned  	       search_range;
+   unsigned  	       fps;
+   char        	      *pattern;
+   char        	      *reference_filename;
+   bool_t    	       half_pixel_prediction;
+   bool_t    	       cross_B_search;
+   bool_t    	       B_as_past_ref;
+   bool_t    	       check_for_underflow;
+   bool_t    	       check_for_overflow;
+   bool_t    	       second_domain_block;
+   bool_t    	       full_search;
+   fiasco_progress_e   progress_meter;
+   char 	      *title;
+   char 	      *comment;
+   unsigned    	       smoothing;
+} c_options_t;
+
+typedef struct d_options
+{
+   char     id [9];
+   unsigned smoothing;
+   unsigned magnification;
+   format_e image_format;
+} d_options_t;
+
+c_options_t *
+cast_c_options (fiasco_c_options_t *options);
+d_options_t *
+cast_d_options (fiasco_d_options_t *options);
+
+#endif /* not _OPTIONS_H */
diff --git a/converter/other/fiasco/codec/prediction.c b/converter/other/fiasco/codec/prediction.c
new file mode 100644
index 00000000..351ba9df
--- /dev/null
+++ b/converter/other/fiasco/codec/prediction.c
@@ -0,0 +1,629 @@
+/*
+ *  prediction.c:	Range image prediction with MC or ND	
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#if HAVE_STRING_H
+#	include <string.h>
+#else /* not HAVE_STRING_H */
+#	include <strings.h>
+#endif /* not HAVE_STRING_H */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "cwfa.h"
+#include "ip.h"
+#include "control.h"
+#include "misc.h"
+#include "subdivide.h"
+#include "bintree.h"
+#include "domain-pool.h"
+#include "approx.h"
+#include "wfalib.h"
+#include "mwfa.h"
+#include "prediction.h"
+
+#include "decoder.h"
+
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+typedef struct state_data
+{
+   real_t final_distribution;
+   byte_t level_of_state;
+   byte_t domain_type;
+
+   real_t *images_of_state;
+   real_t *inner_products;
+   real_t *ip_states_state [MAXLEVEL];
+
+   word_t tree [MAXLABELS];
+   mv_t	  mv_tree [MAXLABELS];
+   word_t y_state [MAXLABELS];
+   byte_t y_column [MAXLABELS];
+   byte_t prediction [MAXLABELS];
+
+   u_word_t x [MAXLABELS];
+   u_word_t y [MAXLABELS];
+
+   real_t weight [MAXLABELS][MAXEDGES + 1];
+   word_t int_weight [MAXLABELS][MAXEDGES + 1];
+   word_t into [MAXLABELS][MAXEDGES + 1];
+} state_data_t;
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static real_t
+nd_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
+	       range_t *range, wfa_t *wfa, coding_t *c);
+static real_t
+mc_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
+	       range_t *range, wfa_t *wfa, coding_t *c);
+static state_data_t *
+store_state_data (unsigned from, unsigned to, unsigned max_level,
+		  wfa_t *wfa, coding_t *c);
+static void
+restore_state_data (unsigned from, unsigned to, unsigned max_level,
+		    state_data_t *data, wfa_t *wfa, coding_t *c);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+ 
+real_t
+predict_range (real_t max_costs, real_t price, range_t *range, wfa_t *wfa,
+	       coding_t *c, unsigned band, int y_state, unsigned states,
+	       const tree_t *tree_model, const tree_t *p_tree_model,
+	       const void *domain_model, const void *d_domain_model,
+	       const void *coeff_model, const void *d_coeff_model)
+{
+   unsigned	 state;		     	/* counter */
+   void		*rec_domain_model;   	/* domain model after recursion */
+   void		*rec_d_domain_model; 	/* p domain model after recursion */
+   void		*rec_coeff_model;    	/* coeff model after recursion */
+   void		*rec_d_coeff_model;  	/* d coeff model after recursion */
+   tree_t	 rec_tree_model;	/* tree_model after '' */
+   tree_t	 rec_p_tree_model;    	/* p_tree_model after '' */
+   unsigned	 rec_states;	     	/* wfa->states after '' */
+   real_t	*rec_pixels;	     	/* c->pixels after '' */
+   state_data_t	*rec_state_data;     	/* state_data struct after '' */
+   real_t	 costs;		     	/* current approximation costs */
+   unsigned	 level;		     	/* counter */
+   state_data_t	*sd;		     	/* pointer to state_data field */
+
+   /*
+    *  Store WFA data from state 'lc_states' to 'wfa->states' - 1 and
+    *  current state of probability models.
+    */
+   rec_domain_model   = c->domain_pool->model;
+   rec_d_domain_model = c->d_domain_pool->model;
+   rec_coeff_model    = c->coeff->model;
+   rec_d_coeff_model  = c->d_coeff->model;
+   rec_tree_model     = c->tree;
+   rec_p_tree_model   = c->p_tree;
+   rec_states         = wfa->states;	
+   rec_pixels         = c->pixels;
+   rec_state_data     = store_state_data (states, rec_states - 1,
+					  c->options.lc_max_level, wfa, c);
+   
+   /*
+    *  Restore probability models to the state before the recursive subdivision
+    *  has been started.
+    */
+   wfa->states             = states;
+   c->tree                 = *tree_model;
+   c->p_tree               = *p_tree_model;
+   c->domain_pool->model   = c->domain_pool->model_duplicate (domain_model);
+   c->d_domain_pool->model = c->d_domain_pool->model_duplicate (d_domain_model);
+   c->coeff->model   	   = c->coeff->model_duplicate (c->coeff, coeff_model);
+   c->d_coeff->model   	   = c->d_coeff->model_duplicate (c->d_coeff,
+							  d_coeff_model);
+   
+   if (c->mt->frame_type == I_FRAME)
+      costs = nd_prediction (max_costs, price, band, y_state, range, wfa, c); 
+   else
+      costs = mc_prediction (max_costs, price, band, y_state, range, wfa, c);
+   
+   c->pixels = rec_pixels;
+   
+   if (costs < MAXCOSTS)
+   {
+      /*
+       *  Free the memory used by the state_data struct
+       */
+      for (state = states; state < rec_states; state++)
+      {
+	 sd = &rec_state_data [state - states];
+	 for (level = c->options.images_level + 1;
+	      level <= c->options.lc_max_level; level++)
+	    if (sd->ip_states_state [level] != NULL)
+	       Free (sd->ip_states_state [level]);
+	 if (sd->images_of_state != NULL)
+	    Free (sd->images_of_state);
+	 if (sd->inner_products != NULL)
+	    Free (sd->inner_products);
+      }
+      if (states < rec_states)
+	 Free (rec_state_data);
+      c->domain_pool->model_free (rec_domain_model);
+      c->d_domain_pool->model_free (rec_d_domain_model);
+      c->coeff->model_free (rec_coeff_model);
+      c->d_coeff->model_free (rec_d_coeff_model);
+
+      costs = (range->tree_bits + range->matrix_bits + range->weights_bits
+	       + range->mv_tree_bits + range->mv_coord_bits
+	       + range->nd_tree_bits + range->nd_weights_bits) * price
+	      + range->err;
+   }
+   else
+   {
+      /*
+       *  Restore WFA to state before function was called
+       */
+      c->domain_pool->model_free (c->domain_pool->model);
+      c->d_domain_pool->model_free (c->d_domain_pool->model);
+      c->coeff->model_free (c->coeff->model);
+      c->d_coeff->model_free (c->d_coeff->model);
+      
+      c->domain_pool->model   = rec_domain_model;
+      c->d_domain_pool->model = rec_d_domain_model;
+      c->coeff->model         = rec_coeff_model;
+      c->d_coeff->model       = rec_d_coeff_model;
+      c->tree                 = rec_tree_model;
+      c->p_tree               = rec_p_tree_model;
+      
+      range->prediction = NO;
+      
+      if (wfa->states != states)
+	 remove_states (states, wfa);
+      restore_state_data (states, rec_states - 1, c->options.lc_max_level,
+			  rec_state_data, wfa, c);
+      costs = MAXCOSTS;
+   }
+ 
+   return costs;
+} 
+
+void
+clear_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt)
+/*
+ *  Clear norms arrays.
+ *
+ *  No return value.
+ */
+{
+   unsigned  range_size = wi->half_pixel
+			  ? square (wi->search_range)
+			  : square (2 * wi->search_range);
+
+   if (level > wi->p_min_level)
+   {
+      memset (mt->mc_forward_norms [level], 0, range_size * sizeof(real_t));
+      memset (mt->mc_backward_norms [level], 0, range_size * sizeof(real_t));
+   }
+}
+
+void
+update_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt)
+/*
+ *  Norms table of levels larger than the bottom level are computed
+ *  by summing up previously calculated displacement costs of lower levels.
+ *
+ *  No return value.
+ */
+{
+   unsigned  range_size = wi->half_pixel
+			  ? square (wi->search_range)
+			  : square (2 * wi->search_range);
+   
+   if (level > wi->p_min_level)
+   {
+      unsigned index;			/* index of motion vector */
+      
+      for (index = 0; index < range_size; index++)
+	 mt->mc_forward_norms [level][index]
+	    += mt->mc_forward_norms [level - 1][index];
+      if (mt->frame_type == B_FRAME)
+	 for (index = 0; index < range_size; index++)
+	    mt->mc_backward_norms [level][index]
+	       += mt->mc_backward_norms [level - 1][index];
+   }
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static real_t
+mc_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
+	       range_t *range, wfa_t *wfa, coding_t *c)
+{
+   real_t    costs;		   	/* current approximation costs */
+   range_t   prange = *range;
+   unsigned  width  = width_of_level (range->level);
+   unsigned  height = height_of_level (range->level);
+   word_t   *mcpe   = Calloc (width * height, sizeof (word_t));
+
+   /*
+    *  If we are at the bottom level of the mc tree:
+    *  Fill in the norms table
+    */
+   if (prange.level == wfa->wfainfo->p_min_level) 
+      fill_norms_table (prange.x, prange.y, prange.level, wfa->wfainfo, c->mt);
+   /*
+    *  Predict 'range' with motion compensation according to frame type.
+    *  MCPE is returned in 'c->mcpe'
+    */
+   if (c->mt->frame_type == P_FRAME)
+      find_P_frame_mc (mcpe, price, &prange, wfa->wfainfo, c->mt);
+   else
+      find_B_frame_mc (mcpe, price, &prange, wfa->wfainfo, c->mt);
+   
+   costs = (prange.mv_tree_bits + prange.mv_coord_bits) * price;
+   
+   if (costs < max_costs)		/* motion vector not too expensive */
+   {
+      unsigned  last_state;		/* last WFA state before recursion */
+      real_t   *ipi [MAXSTATES];	/* inner products pointers */
+      unsigned  state;
+      real_t  	mvt, mvc;
+      
+      c->pixels = Calloc (width * height, sizeof (real_t));
+      cut_to_bintree (c->pixels, mcpe, width, height, 0, 0, width, height);
+   
+      /*
+       *  Approximate MCPE recursively.
+       */
+      last_state = wfa->states - 1;
+      for (state = 0; state <= last_state; state++)
+	 if (need_image (state, wfa))
+	 {
+	    ipi [state] = c->ip_images_state[state];
+	    c->ip_images_state[state]
+	       = Calloc (size_of_tree (c->products_level), sizeof (real_t));
+	 }
+
+      mvc = prange.mv_coord_bits;
+      mvt = prange.mv_tree_bits;
+      
+      prange.image           = 0;
+      prange.address         = 0;
+      prange.tree_bits       = 0;
+      prange.matrix_bits     = 0;
+      prange.weights_bits    = 0;
+      prange.mv_coord_bits   = 0;
+      prange.mv_tree_bits    = 0;
+      prange.nd_weights_bits = 0;
+      prange.nd_tree_bits    = 0;
+
+      compute_ip_images_state (prange.image, prange.address, prange.level,
+			       1, 0, wfa, c);
+      costs += subdivide (max_costs - costs, band, y_state, &prange,
+			  wfa, c, NO, YES);
+
+      if (costs < max_costs)		/* use motion compensation */
+      {
+	 unsigned img, adr;		/* temp. values */
+	 
+	 img                  = range->image;
+	 adr                  = range->address;
+	 *range               = prange;
+	 range->image         = img;
+	 range->address       = adr;
+	 range->mv_coord_bits = mvc;
+	 range->mv_tree_bits  = mvt;
+	 range->prediction    = YES;
+
+	 for (state = last_state + 1; state < wfa->states; state++)
+	    if (need_image (state, wfa))
+	       memset (c->ip_images_state [state], 0,
+		       size_of_tree (c->products_level) * sizeof (real_t));
+
+	 costs = (range->tree_bits + range->matrix_bits + range->weights_bits
+		  + range->mv_tree_bits + range->mv_coord_bits
+		  + range->nd_tree_bits + range->nd_weights_bits) * price
+		 + range->err;
+      }
+      else
+	 costs = MAXCOSTS;
+
+      for (state = 0; state <= last_state; state++)
+	 if (need_image (state, wfa))
+	 {
+	    Free (c->ip_images_state[state]);
+	    c->ip_images_state[state] = ipi [state];
+	 }
+      Free (c->pixels);
+   }
+   else
+      costs = MAXCOSTS;
+   
+   Free (mcpe);
+
+   return costs;
+}
+
+static real_t
+nd_prediction (real_t max_costs, real_t price, unsigned band, int y_state,
+	       range_t *range, wfa_t *wfa, coding_t *c)
+{
+   real_t  costs;			/* current approximation costs */
+   range_t lrange = *range;
+   
+   /*
+    *  Predict 'range' with DC component approximation
+    */
+   {
+      real_t x = get_ip_image_state (range->image, range->address,
+				     range->level, 0, c);
+      real_t y = get_ip_state_state (0, 0, range->level, c);
+      real_t w = btor (rtob (x / y, c->coeff->dc_rpf), c->coeff->dc_rpf);
+      word_t s [2] = {0, -1};
+
+      lrange.into [0] 	     = 0;
+      lrange.into [1] 	     = NO_EDGE;
+      lrange.weight [0]      = w;
+      lrange.mv_coord_bits   = 0;
+      lrange.mv_tree_bits    = 0;
+      lrange.nd_tree_bits    = tree_bits (LEAF, lrange.level, &c->p_tree);
+      lrange.nd_weights_bits = 0;
+      lrange.tree_bits       = 0;
+      lrange.matrix_bits     = 0;
+      lrange.weights_bits    = c->coeff->bits (&w, s, range->level, c->coeff);
+   }
+   costs = price * (lrange.weights_bits + lrange.nd_tree_bits);
+   
+   /*
+    *  Recursive aproximation of difference image
+    */
+   if (costs < max_costs)		
+   {
+      unsigned  state;
+      range_t  	rrange;			/* range: recursive subdivision */
+      unsigned  last_state;		/* last WFA state before recursion */
+      real_t   *ipi [MAXSTATES];	/* inner products pointers */
+      unsigned 	width  = width_of_level (range->level);
+      unsigned  height = height_of_level (range->level);
+      real_t   *pixels;
+
+      /*
+       *  Generate difference image original - approximation
+       */
+      {
+	 unsigned  n;
+	 real_t *src, *dst;		/* pointers to image data */
+	 real_t w = - lrange.weight [0] * c->images_of_state [0][0];
+		     
+	 src = c->pixels + range->address * size_of_level (range->level); 
+	 dst = c->pixels = pixels = Calloc (width * height, sizeof (real_t));
+
+	 for (n = width * height; n; n--)
+	    *dst++ = *src++ + w;
+      }
+      
+      /*
+       *  Approximate difference recursively.
+       */
+      rrange                 = *range;
+      rrange.tree_bits       = 0;
+      rrange.matrix_bits     = 0;
+      rrange.weights_bits    = 0;
+      rrange.mv_coord_bits   = 0;
+      rrange.mv_tree_bits    = 0;
+      rrange.nd_tree_bits    = 0;
+      rrange.nd_weights_bits = 0;
+      rrange.image           = 0;
+      rrange.address         = 0;
+
+      last_state = wfa->states - 1;
+      for (state = 0; state <= last_state; state++)
+	 if (need_image (state, wfa))
+	 {
+	    ipi [state] = c->ip_images_state[state];
+	    c->ip_images_state[state]
+	       = Calloc (size_of_tree (c->products_level), sizeof (real_t));
+	 }
+      
+      compute_ip_images_state (rrange.image, rrange.address, rrange.level,
+			       1, 0, wfa, c);
+      
+      costs += subdivide (max_costs - costs, band, y_state, &rrange, wfa, c,
+			  NO, YES);
+      
+      Free (pixels);
+
+      if (costs < max_costs && ischild (rrange.tree)) /* use prediction */
+      {
+	 unsigned img, adr;
+	 unsigned edge;
+
+	 img                     = range->image;
+	 adr                     = range->address;
+	 *range                  = rrange;
+	 range->image            = img;
+	 range->address          = adr;
+	 range->nd_tree_bits    += lrange.nd_tree_bits;
+	 range->nd_weights_bits += lrange.weights_bits;
+	 
+	 for (edge = 0; isedge (lrange.into [edge]); edge++)
+	 {
+	    range->into [edge]   = lrange.into [edge];
+	    range->weight [edge] = lrange.weight [edge];
+	 }
+	 range->into [edge] = NO_EDGE;
+	 range->prediction  = edge;
+
+	 for (state = last_state + 1; state < wfa->states; state++)
+	    if (need_image (state, wfa))
+	       memset (c->ip_images_state [state], 0,
+		       size_of_tree (c->products_level) * sizeof (real_t));
+      }
+      else
+	 costs = MAXCOSTS;
+      
+      for (state = 0; state <= last_state; state++)
+	 if (need_image (state, wfa))
+	 {
+	    Free (c->ip_images_state [state]);
+	    c->ip_images_state [state] = ipi [state];
+	 }
+   }
+   else
+      costs = MAXCOSTS;
+
+   return costs;
+}
+
+static state_data_t *
+store_state_data (unsigned from, unsigned to, unsigned max_level,
+		  wfa_t *wfa, coding_t *c)
+/*
+ *  Save and remove all states starting from state 'from'.
+ *
+ *  Return value:
+ *	pointer to array of state_data structs
+ */
+{
+   state_data_t *data;			/* array of savestates */
+   state_data_t *sd;			/* pointer to current savestates */
+   unsigned	 state, label, level;
+
+   if (to < from)
+      return NULL;			/* nothing to do */
+   
+   data = Calloc (to - from + 1, sizeof (state_data_t));
+   
+   for (state = from; state <= to; state++)
+   {
+      sd = &data [state - from];
+
+      sd->final_distribution = wfa->final_distribution [state];
+      sd->level_of_state     = wfa->level_of_state [state];
+      sd->domain_type        = wfa->domain_type [state];
+      sd->images_of_state    = c->images_of_state [state];
+      sd->inner_products     = c->ip_images_state [state];
+      
+      wfa->domain_type [state]   = 0;
+      c->images_of_state [state] = NULL;
+      c->ip_images_state [state] = NULL;
+				   
+      for (label = 0; label < MAXLABELS; label++) 
+      {
+	 sd->tree [label]     	= wfa->tree [state][label];
+	 sd->y_state [label]  	= wfa->y_state [state][label];
+	 sd->y_column [label] 	= wfa->y_column [state][label];
+	 sd->mv_tree [label]  	= wfa->mv_tree [state][label];
+	 sd->x [label]        	= wfa->x [state][label];
+	 sd->y [label]        	= wfa->y [state][label];
+	 sd->prediction [label] = wfa->prediction [state][label];
+
+	 memcpy (sd->weight [label], wfa->weight [state][label], 
+		 sizeof (real_t) * (MAXEDGES + 1));
+	 memcpy (sd->int_weight [label], wfa->int_weight [state][label], 
+		 sizeof (word_t) * (MAXEDGES + 1));
+	 memcpy (sd->into [label], wfa->into [state][label], 
+		 sizeof (word_t) * (MAXEDGES + 1));
+
+	 wfa->into [state][label][0] = NO_EDGE;
+	 wfa->tree [state][label]    = RANGE;
+	 wfa->y_state [state][label] = RANGE;
+      }
+      for (level = c->options.images_level + 1; level <= max_level;
+	   level++)
+      {
+	 sd->ip_states_state [level]       = c->ip_states_state [state][level];
+	 c->ip_states_state [state][level] = NULL;
+      }
+   }
+
+   return data;
+}
+
+static void
+restore_state_data (unsigned from, unsigned to, unsigned max_level,
+		    state_data_t *data, wfa_t *wfa, coding_t *c)
+/*
+ *  Restore all state data starting from state 'from'.
+ *  
+ *  No return value.
+ */
+{
+   state_data_t *sd;			/* pointer to state_data item */
+   unsigned	 state, label, level;
+
+   if (to < from)
+      return;				/* nothing to do */
+   
+   for (state = from; state <= to; state++)
+   {
+      sd = &data [state - from];
+      
+      wfa->final_distribution [state] = sd->final_distribution;
+      wfa->level_of_state [state]     = sd->level_of_state;
+      wfa->domain_type [state]        = sd->domain_type;
+      
+      if (c->images_of_state [state] != NULL)
+	 Free (c->images_of_state [state]);
+      c->images_of_state [state] = sd->images_of_state;
+      if (c->ip_images_state [state] != NULL)
+	 Free (c->ip_images_state [state]);
+      c->ip_images_state [state] = sd->inner_products;
+
+      for (label = 0; label < MAXLABELS; label++)
+      {
+	 wfa->tree [state][label]     	= sd->tree [label];
+	 wfa->y_state [state][label]  	= sd->y_state [label];
+	 wfa->y_column [state][label] 	= sd->y_column [label];
+	 wfa->mv_tree [state][label]  	= sd->mv_tree [label];
+	 wfa->x [state][label]        	= sd->x [label];
+	 wfa->y [state][label]        	= sd->y [label];
+	 wfa->prediction [state][label] = sd->prediction [label];
+	 
+	 memcpy (wfa->weight [state][label], sd->weight [label], 
+		 sizeof(real_t) * (MAXEDGES + 1));
+	 memcpy (wfa->int_weight [state][label], sd->int_weight [label], 
+		 sizeof(word_t) * (MAXEDGES + 1));
+	 memcpy (wfa->into [state][label], sd->into [label],  
+		 sizeof(word_t) * (MAXEDGES + 1));
+      }	 
+      for (level = c->options.images_level + 1; level <= max_level;
+	   level++)
+      {
+	 if (c->ip_states_state [state][level] != NULL)
+	    Free (c->ip_states_state [state][level]);
+	 c->ip_states_state [state][level] = sd->ip_states_state [level];
+      }
+   }
+
+   Free (data);
+   wfa->states = to + 1;
+}
diff --git a/converter/other/fiasco/codec/prediction.h b/converter/other/fiasco/codec/prediction.h
new file mode 100644
index 00000000..1068501a
--- /dev/null
+++ b/converter/other/fiasco/codec/prediction.h
@@ -0,0 +1,36 @@
+/*
+ *  prediction.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _PREDICTION_H
+#define _PREDICTION_H
+
+#include "types.h"
+#include "cwfa.h"
+
+real_t
+predict_range (real_t max_costs, real_t price, range_t *range, wfa_t *wfa,
+	       coding_t *c, unsigned band, int y_state, unsigned states,
+	       const tree_t *tree_model, const tree_t *p_tree_model,
+	       const void *domain_model, const void *d_domain_model,
+	       const void *coeff_model, const void *d_coeff_model);
+void
+update_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt);
+void
+clear_norms_table (unsigned level, const wfa_info_t *wi, motion_t *mt);
+
+#endif /* not _PREDICTION_H */
+
diff --git a/converter/other/fiasco/codec/subdivide.c b/converter/other/fiasco/codec/subdivide.c
new file mode 100644
index 00000000..b7982716
--- /dev/null
+++ b/converter/other/fiasco/codec/subdivide.c
@@ -0,0 +1,650 @@
+/*
+ *  subdivide.c:	Recursive subdivision of range images
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/07/15 17:59:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.4 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#if HAVE_STRING_H
+#	include <string.h>
+#else /* not HAVE_STRING_H */
+#	include <strings.h>
+#endif /* not HAVE_STRING_H */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "image.h"
+#include "cwfa.h"
+#include "approx.h"
+#include "ip.h"
+#include "bintree.h"
+#include "control.h"
+#include "prediction.h"
+#include "domain-pool.h"
+#include "mwfa.h"
+#include "misc.h"
+#include "subdivide.h"
+#include "list.h"
+#include "coeff.h"
+#include "wfalib.h"
+
+/*****************************************************************************
+
+				prototypes
+
+*****************************************************************************/
+
+static void
+init_new_state (bool_t auxiliary_state, bool_t delta, range_t *range,
+		const range_t *child, const int *y_state,
+		wfa_t *wfa, coding_t *c);
+static void
+init_range (range_t *range, const image_t *image, unsigned band,
+	    const wfa_t *wfa, coding_t *c);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+real_t 
+subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
+	   wfa_t *wfa, coding_t *c, bool_t prediction, bool_t delta)
+/*
+ *  Subdivide the current 'range' recursively and decide whether
+ *  a linear combination, a recursive subdivision, or a prediction is
+ *  the best choice of approximation.
+ *  'band' is the current color band, 'y_state' is the corresponding
+ *  state of the Y color component (color image compression only).
+ *  If 'prediction' is TRUE then also test motion compensation or
+ *  nondeterministic approximation.
+ *  If 'delta' is TRUE then current range is already predicted.
+ *  
+ *  Return value:
+ *	costs of the best approximation or MAXCOSTS if costs exceed 'max_costs'
+ *
+ *  Side effects:
+ *	'range'	factors and costs of linear combination are modified
+ *      'wfa'	new transitions and prediction coefficients are added
+ *	'c'	pixels and inner products are updated
+ */
+{
+   real_t    subdivide_costs;        /* Costs arising from approx. the current
+				       range with two childs */
+   real_t    lincomb_costs;          /* Costs arising from approx. the current
+				       range with a linear combination */
+   int	     new_y_state [MAXLABELS];	/* Corresponding state of Y */
+   real_t    price;			/* Approximation costs multiplier */
+   bool_t    try_mc;			/* YES: try MC prediction */
+   bool_t    try_nd;			/* YES: try ND prediction */
+   unsigned  states;			/* Number of states before the
+					   recursive subdivision starts */
+   void     *domain_model;		/* copy of domain pool model */      
+   void     *d_domain_model;		/* copy of delta domain pool model */
+   void     *lc_domain_model;		/* copy of domain pool model */
+   void     *lc_d_domain_model;		/* copy of delta domain pool model */
+   void	    *coeff_model;	        /* copy of coefficients model */
+   void	    *d_coeff_model;		/* copy of delta coefficients model */
+   void	    *lc_coeff_model;	        /* copy of coefficients model */
+   void	    *lc_d_coeff_model;		/* copy of delta coefficients model */
+   tree_t    tree_model;		/* copy of tree model */
+   tree_t    p_tree_model;		/* copy of pred. tree model */
+   range_t   lrange;			/* range of lin. comb. approx. */
+   range_t   rrange;			/* range of recursive approx. */
+   range_t   child [MAXLABELS];		/* new childs of the current range */
+   static unsigned percent = 0;		/* status of progress meter */
+
+   if (wfa->wfainfo->level == range->level)
+      percent = 0;
+   
+   range->into [0] = NO_EDGE;		/* default approximation: empty */
+   range->tree     = RANGE;
+
+   if (range->level < 3)		/* Don't process small ranges */
+      return MAXCOSTS;	
+
+   /*
+    *  If image permutation (tiling) is performed and the tiling level
+    *  is reached then get coordinates of the new block.
+    */
+   if (c->tiling->exponent
+       && range->level == wfa->wfainfo->level - c->tiling->exponent)
+   {
+      unsigned width, height;		/* size of range (dummies)*/
+      
+      if (c->tiling->vorder [range->global_address] < 0)
+	 return 0;			/* nothing to do */
+      else
+	 locate_subimage (wfa->wfainfo->level, range->level,
+			  c->tiling->vorder [range->global_address],
+			  &range->x, &range->y, &width, &height);
+   }
+
+   if (range->x >= c->mt->original->width ||
+       range->y >= c->mt->original->height)
+      return 0;				/* range is not visible */
+
+   /*
+    *  Check whether prediction is allowed or not
+    *  mc == motion compensation, nd == nondeterminism
+    */
+   try_mc = (prediction && c->mt->frame_type != I_FRAME			
+	     && range->level >= wfa->wfainfo->p_min_level
+	     && range->level <= wfa->wfainfo->p_max_level
+	     && (range->x + width_of_level (range->level)
+		 <= c->mt->original->width)
+	     && (range->y + height_of_level (range->level)
+		 <= c->mt->original->height));
+
+   try_nd = (prediction && c->mt->frame_type == I_FRAME
+	     && range->level >= wfa->wfainfo->p_min_level
+	     && range->level <= wfa->wfainfo->p_max_level);
+
+   if (try_mc)
+      clear_norms_table (range->level, wfa->wfainfo, c->mt);
+
+   
+   /*
+    *  Check if current range must be initialized. I.e. range pixels must
+    *  be copied from entire image to bintree pixel buffer. Moreover,
+    *  all inner products tables must be initialized.
+    */
+   if (range->level == c->options.lc_max_level)	
+      init_range (range, c->mt->original, band, wfa, c);
+   
+   price = c->price;
+   if (band != Y)			
+      price *= c->options.chroma_decrease; /* less quality for chroma bands */
+
+   /*
+    *  Compute childs of corresponding state in Y band
+    */
+   if (band != Y)			/* Cb and Cr bands only */
+   {
+      unsigned label;
+
+      for (label = 0; label < MAXLABELS; label++)
+	 if (ischild (y_state))
+	    new_y_state [label] = wfa->tree [y_state][label];
+	 else
+	    new_y_state [label] = RANGE;
+   }
+   else
+      new_y_state [0] = new_y_state [1] = RANGE;
+   
+   /*
+    *  Store contents of all models that may get modified during recursion
+    */
+   domain_model   = c->domain_pool->model_duplicate (c->domain_pool->model);
+   d_domain_model = c->d_domain_pool->model_duplicate (c->d_domain_pool->model);
+   coeff_model    = c->coeff->model_duplicate (c->coeff, c->coeff->model);
+   d_coeff_model  = c->d_coeff->model_duplicate (c->d_coeff, c->d_coeff->model);
+   tree_model     = c->tree;
+   p_tree_model   = c->p_tree;
+   states         = wfa->states;	
+   
+   /*
+    *  First alternative of range approximation:
+    *  Compute costs of linear combination.
+    */
+   if (range->level <= c->options.lc_max_level) /* range is small enough */
+   {
+      lrange                 = *range;
+      lrange.tree            = RANGE;
+      lrange.tree_bits       = tree_bits (LEAF, lrange.level, &c->tree);
+      lrange.matrix_bits     = 0;
+      lrange.weights_bits    = 0;
+      lrange.mv_tree_bits    = try_mc ? 1 : 0; /* mc allowed but not used */
+      lrange.mv_coord_bits   = 0;
+      lrange.nd_tree_bits    = 0;	
+      lrange.nd_weights_bits = 0;	
+      lrange.prediction	     = NO;
+      
+      lincomb_costs
+	 = approximate_range (max_costs, price, c->options.max_elements,
+			      y_state, &lrange,
+			      (delta ? c->d_domain_pool : c->domain_pool),
+			      (delta ? c->d_coeff : c->coeff), wfa, c);
+   }
+   else
+      lincomb_costs = MAXCOSTS;		
+
+   /*
+    *  Store contents of models that have been modified
+    *  by approximate_range () above ...
+    */
+   lc_domain_model   = c->domain_pool->model;
+   lc_d_domain_model = c->d_domain_pool->model;
+   lc_coeff_model    = c->coeff->model;
+   lc_d_coeff_model  = c->d_coeff->model;
+   /*
+    *  ... and restore them with values before lc
+    */
+   c->domain_pool->model   = c->domain_pool->model_duplicate (domain_model);
+   c->d_domain_pool->model = c->d_domain_pool->model_duplicate (d_domain_model);
+   c->coeff->model         = c->coeff->model_duplicate (c->coeff, coeff_model);
+   c->d_coeff->model       = c->d_coeff->model_duplicate (c->d_coeff,
+							  d_coeff_model);
+   
+   /*
+    *  Second alternative of range approximation:
+    *  Compute costs of recursive subdivision.
+    */
+   if (range->level > c->options.lc_min_level) /* range is large enough */
+   {
+      unsigned label;
+      
+      memset (&child [0], 0, 2 * sizeof (range_t)); /* initialize childs */
+
+      /*
+       *  Initialize a new range for recursive approximation
+       */
+      rrange                 = *range;
+      rrange.tree_bits       = tree_bits (CHILD, rrange.level, &c->tree);
+      rrange.matrix_bits     = 0;
+      rrange.weights_bits    = 0;
+      rrange.err             = 0;
+      rrange.mv_tree_bits    = try_mc ? 1 : 0;	/* mc allowed but not used */
+      rrange.mv_coord_bits   = 0;
+      rrange.nd_tree_bits    = try_nd ?
+			       tree_bits (CHILD, lrange.level, &c->p_tree): 0;
+      rrange.nd_weights_bits = 0;	
+      rrange.prediction	     = NO;
+
+      /*
+       *  Initialize the cost function and subdivide the current range.
+       *  Every child is approximated by a recursive call of subdivide()
+       */
+      subdivide_costs = (rrange.tree_bits + rrange.weights_bits
+			 + rrange.matrix_bits + rrange.mv_tree_bits
+			 + rrange.mv_coord_bits + rrange.nd_tree_bits
+			 + rrange.nd_weights_bits) * price;
+      
+      for (label = 0; label < MAXLABELS; label++) 
+      {
+	 real_t remaining_costs;	/* upper limit for next recursion */
+	 
+	 child[label].image          = rrange.image * MAXLABELS + label + 1;
+	 child[label].address        = rrange.address * MAXLABELS + label;
+	 child[label].global_address = rrange.global_address * MAXLABELS
+				       + label;
+	 child[label].level          = rrange.level - 1;
+	 child[label].x	= rrange.level & 1
+			  ? rrange.x
+			  : (rrange.x
+			     + label * width_of_level (rrange.level - 1));
+	 child[label].y = rrange.level & 1
+			  ? (rrange.y
+			     + label * height_of_level (rrange.level - 1))
+			  : rrange.y;
+	 
+	 /* 
+	  *  If neccessary 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)
+	    compute_ip_images_state (child[label].image, child[label].address,
+				     child[label].level, 1, states, wfa, c);
+	 /*
+	  *  Call subdivide() for both childs. 
+	  *  Abort the recursion if 'subdivide_costs' exceed 'lincomb_costs'
+	  *  or 'max_costs'.
+	  */
+	 remaining_costs = min (lincomb_costs, max_costs) - subdivide_costs;
+
+	 if (remaining_costs > 0)	/* still a way for improvement */
+	 {
+	    subdivide_costs += subdivide (remaining_costs, band,
+					  new_y_state [label], &child [label],
+					  wfa, c, prediction, delta);
+	 }
+	 else if (try_mc && child[label].level >= wfa->wfainfo->p_min_level)
+	 {
+	    fill_norms_table (child[label].x, child[label].y,
+			      child[label].level, wfa->wfainfo, c->mt);
+	 }
+	 
+	 if (try_mc)
+	    update_norms_table (rrange.level, wfa->wfainfo, c->mt);
+	 
+	 /*
+	  *  Update of progress meter
+	  */
+	 if (c->options.progress_meter != FIASCO_PROGRESS_NONE)
+	 {
+	    if (c->options.progress_meter == FIASCO_PROGRESS_PERCENT)
+	    {
+	       unsigned	new_percent; 	/* new status of progress meter */
+	 
+	       new_percent = (child[label].global_address + 1) * 100.0
+			     / (1 << (wfa->wfainfo->level - child[label].level));
+	       if (new_percent > percent)
+	       {
+		  percent = new_percent;
+		  info ("%3d%%  \r", percent);
+	       }
+	    }
+	    else if (c->options.progress_meter == FIASCO_PROGRESS_BAR)
+	    {
+	       unsigned	new_percent;	/* new status of progress meter */
+	 
+	       new_percent = (child[label].global_address + 1) * 50.0
+			     / (1 << (wfa->wfainfo->level
+				      - child[label].level));
+	       for (; new_percent > percent; percent++)
+	       {
+		  info ("#");
+	       }
+	    }
+	 }
+   
+	 /*
+	  *  If costs of subdivision exceed costs of linear combination 
+	  *  then abort recursion.
+	  */
+	 if (subdivide_costs >= min (lincomb_costs, max_costs)) 
+	 {
+	    subdivide_costs = MAXCOSTS;
+	    break; 
+	 }
+	 rrange.err             += child [label].err;
+	 rrange.tree_bits       += child [label].tree_bits;
+	 rrange.matrix_bits     += child [label].matrix_bits;
+	 rrange.weights_bits    += child [label].weights_bits;
+	 rrange.mv_tree_bits    += child [label].mv_tree_bits;
+	 rrange.mv_coord_bits   += child [label].mv_coord_bits;
+	 rrange.nd_weights_bits += child [label].nd_weights_bits;
+	 rrange.nd_tree_bits    += child [label].nd_tree_bits;
+
+	 tree_update (ischild (child [label].tree) ? CHILD : LEAF,
+		      child [label].level, &c->tree);
+	 tree_update (child [label].prediction ? LEAF : CHILD,
+		      child [label].level, &c->p_tree);
+      }
+   }
+   else
+      subdivide_costs = MAXCOSTS;
+
+   /*
+    *  Third alternative of range approximation:
+    *  Predict range via motion compensation or nondeterminism and 
+    *  approximate delta image. 
+    */
+   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);
+	 
+	 return prediction_costs;
+      }
+   }
+
+   if (lincomb_costs >= MAXCOSTS && subdivide_costs >= MAXCOSTS)
+   {
+      /*
+       *  Return MAXCOSTS if neither a linear combination nor a recursive
+       *  subdivision yield costs less than 'max_costs'
+       */
+      c->domain_pool->model_free (c->domain_pool->model);
+      c->d_domain_pool->model_free (c->d_domain_pool->model);
+      c->domain_pool->model_free (lc_domain_model);
+      c->d_domain_pool->model_free (lc_d_domain_model);
+
+      c->coeff->model_free (c->coeff->model);
+      c->d_coeff->model_free (c->d_coeff->model);
+      c->coeff->model_free (lc_coeff_model);
+      c->d_coeff->model_free (lc_d_coeff_model);
+	 
+      c->domain_pool->model   = domain_model;
+      c->d_domain_pool->model = d_domain_model;
+      c->coeff->model	      = coeff_model;
+      c->d_coeff->model	      = d_coeff_model;
+      c->tree                 = tree_model;
+      c->p_tree               = p_tree_model;
+      
+      if (wfa->states != states)
+	 remove_states (states, wfa);
+
+      return MAXCOSTS;
+   }
+   else if (lincomb_costs < subdivide_costs) 
+   {
+      /*
+       *  Use the linear combination: The factors of the linear combination
+       *  are stored already in 'range', so revert the probability models
+       *  only. 
+       */
+      c->domain_pool->model_free (c->domain_pool->model);
+      c->d_domain_pool->model_free (c->d_domain_pool->model);
+      c->domain_pool->model_free (domain_model);
+      c->d_domain_pool->model_free (d_domain_model);
+
+      c->coeff->model_free (c->coeff->model);
+      c->d_coeff->model_free (c->d_coeff->model);
+      c->coeff->model_free (coeff_model);
+      c->d_coeff->model_free (d_coeff_model);
+      
+      c->domain_pool->model   = lc_domain_model;
+      c->d_domain_pool->model = lc_d_domain_model;
+      c->coeff->model	      = lc_coeff_model;
+      c->d_coeff->model	      = lc_d_coeff_model;
+      c->tree                 = tree_model;
+      c->p_tree               = p_tree_model;
+
+      *range = lrange;
+      
+      if (wfa->states != states)
+	 remove_states (states, wfa);
+
+      return lincomb_costs;
+   }
+   else
+   {
+      /*
+       *  Use the recursive subdivision: Generate a new state with transitions
+       *  given in child[].
+       *  Don't use state in linear combinations in any of the following cases:
+       *  - if color component is Cb or Cr
+       *  - if level of state > tiling level 
+       *  - if state is (partially) outside image geometry 
+       */
+      if (band > Y
+	  || (c->tiling->exponent
+	      && rrange.level > wfa->wfainfo->level - c->tiling->exponent)
+	  || (range->x + width_of_level (range->level)
+	      > c->mt->original->width)
+	  || (range->y + height_of_level (range->level)
+	      > c->mt->original->height))
+	 init_new_state (YES, delta, &rrange, child, new_y_state, wfa, c);
+      else
+	 init_new_state (NO, delta, &rrange, child, new_y_state, wfa, c);
+
+      *range = rrange;
+
+      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 subdivide_costs;
+   }
+}
+
+void
+cut_to_bintree (real_t *dst, const word_t *src,
+		unsigned src_width, unsigned src_height,
+		unsigned x0, unsigned y0, unsigned width, unsigned height)
+/*
+ *  Cut region ('x0', 'y0', 'width', 'height') of the pixel array 'src'.
+ *  Size of image is given by 'src_width' x 'src_height'.
+ *  'dst' pixels are converted to bintree order and real format.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'dst []' is filled with corresponding region.
+ */
+{
+   const unsigned mask01      = 0x555555; /* binary ...010101010101 */
+   const unsigned mask10      = 0xaaaaaa; /* binary ...101010101010 */
+   const unsigned mask01plus1 = mask01 + 1; /* binary ...010101010110 */
+   const unsigned mask10plus1 = mask10 + 1; /* binary ...101010101011 */
+   unsigned  	  x, y;			/* pixel coordinates */
+   unsigned  	  xmask, ymask;		/* address conversion */
+
+   if (width != height && width != (height >> 1))
+      error ("Bintree cutting requires special type of images.");
+
+   ymask = 0;
+   for (y = y0; y < y0 + height; y++, ymask = (ymask + mask10plus1) & mask01)
+   {
+      xmask = 0;
+      for (x = x0; x < x0 + width; x++, xmask = (xmask + mask01plus1) & mask10)
+      {
+	 if (y >= src_height || x >= src_width)
+	    dst [xmask | ymask] = 0;
+	 else
+	    dst [xmask | ymask] = src [y * src_width + x] / 16;
+      }
+   }
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+init_new_state (bool_t auxiliary_state, bool_t delta, range_t *range,
+		const range_t *child, const int *y_state,
+		wfa_t *wfa, coding_t *c)
+/*
+ *  Initializes a new state with all parameters needed for the encoding step.
+ *  If flag 'auxiliary_state' is set then don't insert state into domain pools.
+ *  If flag 'delta' is set then state represents a delta image (prediction via
+ *  nondeterminism or motion compensation).
+ *  'range' the current range image,
+ *   'child []' the left and right childs of 'range'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	New state is appended to 'wfa' (and also its inner products and images
+ *      are computed and stored in 'c')
+ */
+{
+   unsigned label;
+   bool_t   state_is_domain = NO;
+
+   if (!auxiliary_state)
+   {
+      if (!delta || c->options.delta_domains)
+	 state_is_domain = c->domain_pool->append (wfa->states, range->level,
+						   wfa, c->domain_pool->model);
+      if (delta || c->options.normal_domains)
+	 state_is_domain = c->d_domain_pool->append (wfa->states, range->level,
+						     wfa,
+						     c->d_domain_pool->model)
+			   || state_is_domain;
+   }
+   else
+      state_is_domain = NO;
+   
+   range->into [0] = NO_EDGE;
+   range->tree     = wfa->states;
+   
+   for (label = 0; label < MAXLABELS; label++) 
+   {
+      wfa->tree [wfa->states][label]       = child [label].tree;
+      wfa->y_state [wfa->states][label]    = y_state [label];
+      wfa->mv_tree [wfa->states][label]    = child [label].mv;
+      wfa->x [wfa->states][label]          = child [label].x;
+      wfa->y [wfa->states][label]          = child [label].y;
+      wfa->prediction [wfa->states][label] = child [label].prediction;
+
+      append_transitions (wfa->states, label, child [label].weight,
+			  child [label].into, wfa);
+   }
+   wfa->delta_state [wfa->states] = delta;
+
+   if (range->err < 0)
+      warning ("Negative image norm: %f, %f", child [0].err, child [1].err);
+
+/*    state_is_domain = YES; */
+   
+   append_state (!state_is_domain,
+		 compute_final_distribution (wfa->states, wfa),
+		 range->level, wfa, c);
+}
+
+static void
+init_range (range_t *range, const image_t *image, unsigned band,
+	    const wfa_t *wfa, coding_t *c)
+/*
+ *  Read a new 'range' of the image 'image_name' (current color component
+ *  is 'band') and compute the new inner product arrays.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'c->pixels' are filled with pixel values of image block 
+ *	'c->ip_images_state' are computed with respect to new image block 
+ *	'range->address' and 'range->image' are initialized with zero
+ */
+{
+   unsigned state;
+   
+   /*
+    *  Clear already computed products
+    */
+   for (state = 0; state < wfa->states; state++)
+      if (need_image (state, wfa))
+	 memset (c->ip_images_state[state], 0,
+		 size_of_tree (c->products_level) * sizeof(real_t));
+
+   cut_to_bintree (c->pixels, image->pixels [band],
+		   image->width, image->height,
+		   range->x, range->y, width_of_level (range->level),
+		   height_of_level (range->level));
+   
+   range->address = range->image = 0;
+   compute_ip_images_state (0, 0, range->level, 1, 0, wfa, c);
+}
+
+
diff --git a/converter/other/fiasco/codec/subdivide.h b/converter/other/fiasco/codec/subdivide.h
new file mode 100644
index 00000000..b6840e58
--- /dev/null
+++ b/converter/other/fiasco/codec/subdivide.h
@@ -0,0 +1,33 @@
+/*
+ *  subdivide.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _SUBDIVIDE_H
+#define _SUBDIVIDE_H
+
+#include "types.h"
+#include "cwfa.h"
+
+real_t 
+subdivide (real_t max_costs, unsigned band, int y_state, range_t *range,
+	   wfa_t *wfa, coding_t *c, bool_t prediction, bool_t delta);
+void
+cut_to_bintree (real_t *dst, const word_t *src,
+		unsigned src_width, unsigned src_height,
+		unsigned x0, unsigned y0, unsigned width, unsigned height);
+
+#endif /* not _SUBDIVIDE_H */
+
+
diff --git a/converter/other/fiasco/codec/tiling.c b/converter/other/fiasco/codec/tiling.c
new file mode 100644
index 00000000..e820f7fb
--- /dev/null
+++ b/converter/other/fiasco/codec/tiling.c
@@ -0,0 +1,239 @@
+/*
+ *  tiling.c:		Subimage permutation
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#if STDC_HEADERS
+#	include <stdlib.h>
+#endif /* not STDC_HEADERS */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "image.h"
+#include "misc.h"
+#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
+{
+   int	  address;			/* bintree address */
+   real_t variance;			/* variance of tile */
+} var_list_t;
+
+tiling_t *
+alloc_tiling (fiasco_tiling_e method, unsigned tiling_exponent,
+	      unsigned image_level)
+/*
+ *  Image tiling constructor.
+ *  Allocate memory for the tiling_t structure.
+ *  `method' defines the tiling method (spiral or variance,
+ *  ascending or descending).
+ *  In case of invalid parameters, a structure with tiling.exponent == 0 is
+ *  returned. 
+ *
+ *  Return value
+ *	pointer to the new tiling structure on success
+ */
+{
+   tiling_t *tiling = Calloc (1, sizeof (tiling_t));
+
+   if ((int) image_level - (int) tiling_exponent < 6)
+   {
+      tiling_exponent = 6;
+      warning (_("Image tiles must be at least 8x8 pixels large.\n"
+		 "Setting tiling size to 8x8 pixels."));
+   }
+   
+   switch (method)
+   {
+      case FIASCO_TILING_SPIRAL_ASC:
+      case FIASCO_TILING_SPIRAL_DSC:
+      case FIASCO_TILING_VARIANCE_ASC:
+      case FIASCO_TILING_VARIANCE_DSC:
+	 tiling_exponent = tiling_exponent;
+	 break;
+      default:
+	 warning (_("Invalid tiling method specified. Disabling tiling."));
+	 tiling_exponent = 0;
+	 break;
+   }
+
+   return tiling;
+}
+
+void
+free_tiling (tiling_t *tiling)
+/*
+ *  Tiling struct destructor:
+ *  Free memory of 'tiling' struct.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	structure 'tiling' is discarded.
+ */
+{
+   if (tiling->vorder)
+      Free (tiling->vorder);
+   Free (tiling);
+}
+
+void
+perform_tiling (const image_t *image, tiling_t *tiling)
+/*
+ *  Compute image tiling permutation.
+ *  The image is split into 2**'tiling->exponent' tiles.
+ *  Depending on 'tiling->method', the following algorithms are used:
+ *  "VARIANCE_ASC" :  Tiles are sorted by variance.
+ *                    The first tile has the lowest variance
+ *  "VARIANCE_DSC" :  Tiles are sorted by variance.
+ *                    The first tile has the largest variance
+ *  "SPIRAL_ASC" :    Tiles are sorted like a spiral starting
+ *                    in the middle of the image.
+ *  "SPIRAL_DSC" :    Tiles are sorted like a spiral starting
+ *                    in the upper left corner.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	The tiling permutation is stored in 'tiling->vorder'.
+ */
+{
+   if (tiling->exponent)
+   {
+      unsigned 	tiles = 1 << tiling->exponent; /* number of image tiles */
+      bool_t   *tile_valid;		/* tile i is in valid range ? */
+      
+      tiling->vorder = Calloc (tiles, sizeof (int));
+      tile_valid     = Calloc (tiles, sizeof (bool_t));
+
+      if (tiling->method == FIASCO_TILING_VARIANCE_ASC
+	  || tiling->method == FIASCO_TILING_VARIANCE_DSC)
+      {
+	 unsigned    address;		/* bintree address of tile */
+	 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);
+	 var_list_t *var_list = Calloc (tiles, sizeof (var_list_t));
+	 
+	 /*
+	  *  Compute variances of image tiles
+	  */
+	 for (number = 0, address = 0; address < tiles; address++)
+	 {
+	    unsigned width, height;	/* size of image tile */
+	    unsigned x0, y0;		/* NW corner of image tile */
+      
+	    locate_subimage (level, level - tiling->exponent, address,
+			     &x0, &y0, &width, &height);
+	    if (x0 < image->width && y0 < image->height) /* valid range */
+	    {
+	       if (x0 + width > image->width)	/* outside image area */
+		  width = image->width - x0;
+	       if (y0 + height > image->height) /* outside image area */
+		  height = image->height - y0;
+
+	       var_list [number].variance
+		  = variance (image->pixels [GRAY], x0, y0,
+			      width, height, image->width);
+	       var_list [number].address  = address;
+	       number++;
+	       tile_valid [address] = YES;
+	    }
+	    else
+	       tile_valid [address] = NO;
+	 }
+
+	 /*
+	  *  Sort image tiles according to sign of 'tiling->exp'
+	  */
+	 if (tiling->method == FIASCO_TILING_VARIANCE_DSC)
+	    qsort (var_list, number, sizeof (var_list_t), cmpdecvar);
+	 else
+	    qsort (var_list, number, sizeof (var_list_t), cmpincvar);
+
+	 for (number = 0, address = 0; address < tiles; address++)
+	    if (tile_valid [address])
+	    {
+	       tiling->vorder [address] = var_list [number].address;
+	       number++;
+	       debug_message ("tile number %d has original address %d",
+			      number, tiling->vorder [address]);
+	    }
+	    else
+	       tiling->vorder [address] = -1;
+
+	 Free (var_list);
+      }
+      else if (tiling->method == FIASCO_TILING_SPIRAL_DSC
+	       || tiling->method == FIASCO_TILING_SPIRAL_ASC)
+      {
+	 compute_spiral (tiling->vorder, image->width, image->height,
+			 tiling->exponent,
+			 tiling->method == FIASCO_TILING_SPIRAL_ASC);
+      }
+      else
+      {
+	 warning ("Unsupported image 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/tiling.h b/converter/other/fiasco/codec/tiling.h
new file mode 100644
index 00000000..2eb04fe0
--- /dev/null
+++ b/converter/other/fiasco/codec/tiling.h
@@ -0,0 +1,40 @@
+/*
+ *  tiling.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _TILING_H
+#define _TILING_H
+
+#include "image.h"
+#include "fiasco.h"
+
+typedef struct tiling
+{
+   unsigned    	    exponent;		/* Image is split in 2^exp tiles */
+   fiasco_tiling_e  method;		/* Method of Image tiling */
+   int	      	   *vorder;		/* Block permutation (size = 2^exp)
+					   -1 indicates empty block */
+} tiling_t;
+
+void
+perform_tiling (const image_t *image, tiling_t *tiling);
+tiling_t *
+alloc_tiling (fiasco_tiling_e method, unsigned tiling_exponent,
+	      unsigned image_level);
+void
+free_tiling (tiling_t *tiling);
+
+#endif /* not _TILING_H */
+
diff --git a/converter/other/fiasco/codec/wfa.h b/converter/other/fiasco/codec/wfa.h
new file mode 100644
index 00000000..8b9793f2
--- /dev/null
+++ b/converter/other/fiasco/codec/wfa.h
@@ -0,0 +1,141 @@
+/*
+ *  wfa.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/07/18 15:44:57 $
+ *  $Author: hafner $
+ *  $Revision: 5.3 $
+ *  $State: Exp $
+ */
+
+#ifndef _WFA_H
+#define _WFA_H
+
+#define MAXEDGES  5
+#define MAXSTATES 6000
+#define MAXLABELS 2			/* only bintree supported anymore */
+#define MAXLEVEL  22 
+
+#define FIASCO_BINFILE_RELEASE   2
+#define FIASCO_MAGIC	         "FIASCO" /* FIASCO magic number */
+#define FIASCO_BASIS_MAGIC       "Fiasco" /* FIASCO initial basis */
+
+#define NO_EDGE		-1
+#define RANGE		-1
+#define NO_RANGE	 0
+
+#define CHILD		 1
+#define LEAF		 0
+
+#define MAX_PROB	 9
+#define MIN_PROB	 1
+
+/*
+ *  WFA state types:
+ *	0:		 state is not allowed to be used in an
+ *			 approximation and it's image is not needed
+ *			 for ip computations.
+ *	AUXILIARY_MASK:  state is required for computation of ip's but is not
+ *			 allowed to be used in an approximation.
+ *	USE_DOMAIN_MASK: state is allowed to be used in an approximation.
+ */
+enum state_types {AUXILIARY_MASK = 1 << 0, USE_DOMAIN_MASK = 1 << 1};
+
+#define isedge(x)	   ((x) != NO_EDGE)
+#define isdomain(x)	   ((x) != NO_EDGE)
+#define isrange(x)	   ((x) == RANGE)
+#define ischild(x)	   ((x) != RANGE)
+#define isauxiliary(d,wfa) ((wfa)->domain_type[d] & AUXILIARY_MASK)
+#define usedomain(d, wfa)  ((wfa)->domain_type[d] & USE_DOMAIN_MASK)
+#define need_image(d,wfa)  (isauxiliary ((d), (wfa)) || usedomain ((d), (wfa)))
+
+typedef enum mc_type {NONE, FORWARD, BACKWARD, INTERPOLATED} mc_type_e;
+typedef enum frame_type {I_FRAME, P_FRAME, B_FRAME} frame_type_e;
+typedef enum header {HEADER_END, HEADER_TITLE, HEADER_COMMENT} header_type_e;
+
+typedef struct mv
+/*
+ *  Motion vector components
+ */
+{
+   mc_type_e type;			/* motion compensation type */
+   int       fx, fy;			/* forward vector coordinates */
+   int       bx, by;			/* backward vector coordinates */
+} mv_t;
+
+typedef struct range_info
+{
+   unsigned x, y;			/* coordinates of upper left corner */
+   unsigned level;			/* bintree level of range */
+} range_info_t;
+
+#include "image.h"
+#include "rpf.h"
+#include "bit-io.h"
+
+typedef struct wfa_info
+{
+   char	    *wfa_name;			/* filename of the WFA */
+   char	    *basis_name;		/* filename of the initial basis */
+   char     *title;			/* title of FIASCO stream */
+   char     *comment;			/* comment for FIASCO stream */
+   
+   unsigned  max_states;		/* max. cardinality of domain pool */
+   unsigned  chroma_max_states;		/* max. cardinality of domain pool for
+					   chroma band coding */
+   bool_t    color;			/* color image */
+   unsigned  width;			/* image width */
+   unsigned  height;			/* image height */
+   unsigned  level;			/* image level */
+   rpf_t    *rpf;			/* Standard reduced precision format */
+   rpf_t    *dc_rpf;			/* DC reduced precision format */
+   rpf_t    *d_rpf;			/* Delta reduced precision format */
+   rpf_t    *d_dc_rpf;			/* Delta DC reduced precision format */
+   unsigned  frames;			/* number of frames in the video */
+   unsigned  fps;			/* number of frames per second */
+   unsigned  p_min_level;		/* min. level of prediction */
+   unsigned  p_max_level;		/* max. level of prediction */
+   unsigned  search_range;		/* motion vector interval */
+   bool_t    half_pixel;		/* usage of half pixel precision */
+   bool_t    cross_B_search;		/* usage of Cross-B-Search */
+   bool_t    B_as_past_ref;		/* usage of B frames as ref's */
+   unsigned  smoothing;			/* smoothing of image along borders */
+   unsigned  release;			/* FIASCO file format release */
+} wfa_info_t;
+
+typedef struct wfa
+/*
+ *  Used to store all informations and data structures of a WFA
+ */
+{
+   wfa_info_t	*wfainfo;		/* misc. information about the WFA */
+   frame_type_e frame_type;		/* intra, predicted, bi-directional */
+   unsigned	states;			/* number of states */
+   unsigned	basis_states;		/* number of states in the basis */
+   unsigned	root_state;		/* root of the tree */
+   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
+					   Bit_1==1: used for Y compr */
+   mv_t		(*mv_tree)[MAXLABELS];	/* motion vectors */
+   word_t	(*tree)[MAXLABELS];	/* bintree partitioning */
+   u_word_t	(*x)[MAXLABELS];	/* range coordinate */
+   u_word_t	(*y)[MAXLABELS];	/* range coordinate */
+   word_t	(*into)[MAXLABELS][MAXEDGES + 1];   /* domain references */
+   real_t	(*weight)[MAXLABELS][MAXEDGES + 1]; /* lin.comb. coefficients */
+   word_t	(*int_weight)[MAXLABELS][MAXEDGES + 1]; /* bin. representation */
+   word_t	(*y_state)[MAXLABELS];	/* bintree of Y component */
+   byte_t	(*y_column)[MAXLABELS];	/* array for Y component references */
+   byte_t	(*prediction)[MAXLABELS]; /* DC prediction */
+   bool_t	(*delta_state);		/* delta state */
+} wfa_t;
+
+#endif /* not _WFA_H */
+
diff --git a/converter/other/fiasco/codec/wfalib.c b/converter/other/fiasco/codec/wfalib.c
new file mode 100644
index 00000000..a3acb975
--- /dev/null
+++ b/converter/other/fiasco/codec/wfalib.c
@@ -0,0 +1,774 @@
+/*
+ *  wfalib.c:		Library functions both for encoding and decoding
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/07/18 15:57:28 $
+ *  $Author: hafner $
+ *  $Revision: 5.5 $
+ *  $State: Exp $
+ */
+
+#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include "config.h"
+
+#if STDC_HEADERS
+#	include <stdlib.h>
+#endif /* not STDC_HEADERS */
+
+#include <string.h>
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "misc.h"
+#include "wfalib.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static unsigned
+xy_to_address (unsigned x, unsigned y, unsigned level, unsigned n);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+wfa_t *
+alloc_wfa (bool_t coding)
+/*
+ *  WFA constructor:
+ *  Initialize the WFA structure 'wfa' and allocate memory.
+ *  Flag 'coding' indicates whether WFA is used for coding or decoding.
+ *
+ *  Return value:
+ *	pointer to the new WFA structure
+ */
+{
+   wfa_t *wfa = Calloc (1, sizeof (wfa_t));
+		 
+   /*
+    *  Allocate memory
+    */
+   wfa->final_distribution = Calloc (MAXSTATES, sizeof (real_t));
+   wfa->level_of_state     = Calloc (MAXSTATES, sizeof (byte_t));
+   wfa->domain_type        = Calloc (MAXSTATES, sizeof (byte_t));
+   wfa->delta_state        = Calloc (MAXSTATES, sizeof (bool_t));
+   wfa->tree               = Calloc (MAXSTATES * MAXLABELS, sizeof (word_t));
+   wfa->x                  = Calloc (MAXSTATES * MAXLABELS, sizeof (word_t));
+   wfa->y                  = Calloc (MAXSTATES * MAXLABELS, sizeof (word_t));
+   wfa->mv_tree            = Calloc (MAXSTATES * MAXLABELS, sizeof (mv_t));
+   wfa->y_state            = Calloc (MAXSTATES * MAXLABELS, sizeof (word_t));
+   wfa->into               = Calloc (MAXSTATES * MAXLABELS * (MAXEDGES + 1),
+				     sizeof (word_t));
+   wfa->weight             = Calloc (MAXSTATES * MAXLABELS * (MAXEDGES + 1),
+				     sizeof (real_t));
+   wfa->int_weight         = Calloc (MAXSTATES * MAXLABELS * (MAXEDGES + 1),
+				     sizeof (word_t));
+   wfa->wfainfo            = Calloc (1, sizeof (wfa_info_t));;
+   wfa->prediction         = Calloc (MAXSTATES * MAXLABELS, sizeof (byte_t));
+
+   wfa->wfainfo->wfa_name   = NULL;
+   wfa->wfainfo->basis_name = NULL;
+   wfa->wfainfo->title 	    = strdup ("");
+   wfa->wfainfo->comment    = strdup ("");
+
+   /*
+    *  Initialize structure
+    */
+   {
+      unsigned  state, label;
+
+      wfa->states       = 0;
+      wfa->basis_states = 0;
+      wfa->root_state   = 0;
+      for (state = 0; state < MAXSTATES; state++) 
+      {
+	 wfa->final_distribution [state] = 0;
+	 wfa->domain_type [state]        = 0;
+	 for (label = 0; label < MAXLABELS; label++)
+	 {
+	    wfa->into [state][label][0] = NO_EDGE;
+	    wfa->tree [state][label]    = RANGE;
+	    wfa->y_state [state][label] = RANGE;
+	 }
+      }
+   }
+
+   if (coding)				/* initialize additional variables */
+      wfa->y_column = Calloc (MAXSTATES * MAXLABELS, sizeof (byte_t));
+   else
+      wfa->y_column = NULL;
+   
+   return wfa;
+}
+
+void
+free_wfa (wfa_t *wfa)
+/*
+ *  WFA destructor:
+ *  Free memory of given 'wfa'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'wfa' struct is discarded.
+ */
+{
+   if (wfa->wfainfo->wfa_name)
+      Free (wfa->wfainfo->wfa_name);
+   if (wfa->wfainfo->basis_name)
+      Free (wfa->wfainfo->basis_name);
+   if (wfa->wfainfo->title)
+      Free (wfa->wfainfo->title);
+   if (wfa->wfainfo->comment)
+      Free (wfa->wfainfo->comment);
+
+   Free (wfa->final_distribution);
+   Free (wfa->level_of_state);
+   Free (wfa->domain_type);
+   Free (wfa->tree);
+   Free (wfa->x);
+   Free (wfa->y);
+   Free (wfa->mv_tree);
+   Free (wfa->y_state);
+   Free (wfa->into);
+   Free (wfa->weight);
+   Free (wfa->int_weight);
+   Free (wfa->wfainfo);
+   Free (wfa->prediction);
+   Free (wfa->delta_state);
+   if (wfa->y_column)
+      Free (wfa->y_column);
+   Free (wfa);
+}
+
+real_t 
+compute_final_distribution (unsigned state, const wfa_t *wfa)
+/*
+ *  Compute the final distribution of the given 'state'.
+ *  Uses the fact that the generated 'wfa' is average preserving.
+ *
+ *  Return value:
+ *	final distribution
+ */
+{
+   unsigned label;
+   real_t   final = 0;
+
+   for (label = 0; label < MAXLABELS; label++)
+   {
+      unsigned edge;
+      int      domain;
+      
+      if (ischild (domain = wfa->tree [state][label]))
+	 final += wfa->final_distribution [domain];
+      for (edge = 0; isedge (domain = wfa->into [state][label][edge]); edge++)
+	 final += wfa->weight [state][label][edge]
+		  * wfa->final_distribution [domain];
+   }
+   
+   return final / MAXLABELS;
+}
+
+word_t *
+compute_hits (unsigned from, unsigned to, unsigned n, const wfa_t *wfa)
+/*
+ *  Selects the 'n' most popular domain images of the given 'wfa'.
+ *  Consider only linear combinations of state images
+ *  {i | 'from' <= i <= 'to'}. I.e. domains are in {i | from <= i < 'to'}
+ *  Always ensure that state 0 is among selected states even though from
+ *  may be > 0.
+ *  
+ *  Return value:
+ *	pointer to array of the most popular state images
+ *	sorted by increasing state numbers and terminated by -1
+ */
+{
+   word_t   *domains;
+   unsigned  state, label, edge;
+   int       domain;
+   pair_t   *hits = Calloc (to, sizeof (pair_t));
+
+   for (domain = 0; domain < (int) to; domain++)
+   {
+      hits [domain].value = domain;
+      hits [domain].key   = 0;
+   }
+   
+   for (state = from; state <= to; state++)
+      for (label = 0; label < MAXLABELS; label++)
+	 for (edge = 0; isedge (domain = wfa->into [state][label][edge]);
+	      edge++)
+	    hits [domain].key++;
+
+   qsort (hits + 1, to - 1, sizeof (pair_t), sort_desc_pair);
+
+   n       = min (to, n);
+   domains = Calloc (n + 1, sizeof (word_t));
+
+   for (domain = 0; domain < (int) n && (!domain || hits [domain].key);
+	domain++)
+      domains [domain] = hits [domain].value;
+   if (n != domain)
+      debug_message ("Only %d domains have been used in the luminance.",
+		     domain);
+   n = domain;
+   qsort (domains, n, sizeof (word_t), sort_asc_word);
+   domains [n] = -1;
+   
+   Free (hits);
+   
+   return domains;
+}
+
+void
+append_edge (unsigned from, unsigned into, real_t weight,
+	     unsigned label, wfa_t *wfa)
+/*
+ *  Append an edge from state 'from' to state 'into' with
+ *  the given 'label' and 'weight' to the 'wfa'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'wfa' structure is changed.
+ */
+{
+   unsigned new;			/* position of the new edge */
+   unsigned edge;
+
+   /*
+    *  First look where to insert the new edge:
+    *  edges are sorted by increasing 'into' values
+    */
+   for (new = 0; (isedge (wfa->into [from][label][new])
+		  && wfa->into [from][label][new] < (int) into); new++)
+      ;
+   /*
+    *  Move the edges 'n' to position 'n+1', for n = max, ..., 'new'
+    */
+   for (edge = new; isedge (wfa->into [from][label][edge]); edge++)
+      ;
+   for (edge++; edge != new; edge--)
+   {
+      wfa->into [from][label][edge]    = wfa->into [from][label][edge - 1];
+      wfa->weight [from][label][edge]  = wfa->weight [from][label][edge - 1];
+      wfa->int_weight [from][label][edge]
+	 = wfa->int_weight [from][label][edge - 1];
+   }
+   /*
+    *  Insert the new edge
+    */
+   wfa->into [from][label][edge]       = into;
+   wfa->weight [from][label][edge]     = weight;
+   wfa->int_weight [from][label][edge] = weight * 512 + 0.5;
+}
+
+void 
+remove_states (unsigned from, wfa_t *wfa)
+/* 
+ *  Remove 'wfa' states 'wfa->basis_states',...,'wfa->states' - 1.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'wfa' structure is cleared for the given states.
+ */
+{
+   unsigned state;
+
+   for (state = from; state < wfa->states; state++)
+   {
+      unsigned label;
+      
+      for (label = 0; label < MAXLABELS; label++) 
+      {
+	 wfa->into [state][label][0]      = NO_EDGE;
+	 wfa->tree [state][label]         = RANGE;
+	 wfa->prediction [state][label]   = FALSE;
+	 wfa->y_state [state][label]      = RANGE;
+	 wfa->mv_tree [state][label].type = NONE;
+	 wfa->mv_tree [state][label].fx   = 0;
+	 wfa->mv_tree [state][label].fy   = 0;
+	 wfa->mv_tree [state][label].bx   = 0;
+	 wfa->mv_tree [state][label].by   = 0;
+      }
+      wfa->domain_type [state] = 0;
+      wfa->delta_state [state] = FALSE;
+   }
+
+   wfa->states = from;
+}
+
+void
+copy_wfa (wfa_t *dst, const wfa_t *src)
+/*
+ *  Copy WFA struct 'src' to WFA struct 'dst'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'dst' is filled with same data as 'src'
+ *
+ *  NOTE: size of WFA 'dst' must be at least size of WFA 'src'
+ */
+{
+   unsigned state;
+
+   memset (dst->final_distribution, 0, MAXSTATES * sizeof (real_t));
+   memset (dst->level_of_state, 0, MAXSTATES * sizeof (byte_t));
+   memset (dst->domain_type, 0, MAXSTATES * sizeof (byte_t));
+   memset (dst->mv_tree, 0, MAXSTATES * MAXLABELS * sizeof (mv_t));
+   memset (dst->tree, 0, MAXSTATES * MAXLABELS * sizeof (word_t));
+   memset (dst->x, 0, MAXSTATES * MAXLABELS * sizeof (word_t));
+   memset (dst->y, 0, MAXSTATES * MAXLABELS * sizeof (word_t));
+   memset (dst->y_state, 0, MAXSTATES * MAXLABELS * sizeof (word_t));
+   memset (dst->into, NO_EDGE,
+	   MAXSTATES * MAXLABELS * (MAXEDGES + 1) * sizeof (word_t));
+   memset (dst->weight, 0,
+	   MAXSTATES * MAXLABELS * (MAXEDGES + 1) * sizeof (real_t));
+   memset (dst->int_weight, 0,
+	   MAXSTATES * MAXLABELS * (MAXEDGES + 1) * sizeof (word_t));
+   memset (dst->prediction, 0, MAXSTATES * MAXLABELS * sizeof (byte_t));
+   memset (dst->delta_state, 0, MAXSTATES * sizeof (bool_t));
+   if (dst->y_column)
+      memset (dst->y_column, 0, MAXSTATES * MAXLABELS * sizeof (byte_t));
+
+   for (state = 0; state < MAXSTATES; state++) /* clear WFA struct */
+   {
+      unsigned label;
+      
+      for (label = 0; label < MAXLABELS; label++)
+      {
+	 dst->into [state][label][0]      = NO_EDGE;
+	 dst->tree [state][label]         = RANGE;
+	 dst->mv_tree [state][label].type = NONE;
+	 dst->y_state[state][label]       = RANGE;
+      }
+      dst->delta_state [state] = NO;
+      dst->domain_type [state] = 0;
+   }
+   
+   dst->frame_type   = src->frame_type;
+   dst->states 	     = src->states;
+   dst->basis_states = src->basis_states;
+   dst->root_state   = src->root_state;
+
+   memcpy (dst->wfainfo, src->wfainfo, sizeof (wfa_info_t));
+
+   if (dst->states == 0)		/* nothing to do */
+      return;
+
+   memcpy (dst->final_distribution, src->final_distribution,
+	   src->states * sizeof (real_t));
+   memcpy (dst->level_of_state, src->level_of_state,
+	   src->states * sizeof (byte_t));
+   memcpy (dst->domain_type, src->domain_type,
+	   src->states * sizeof (byte_t));
+   memcpy (dst->delta_state, src->delta_state,
+	   src->states * sizeof (bool_t));
+   memcpy (dst->mv_tree, src->mv_tree,
+	   src->states * MAXLABELS * sizeof (mv_t));
+   memcpy (dst->tree, src->tree,
+	   src->states * MAXLABELS * sizeof (word_t));
+   memcpy (dst->x, src->x,
+	   src->states * MAXLABELS * sizeof (word_t));
+   memcpy (dst->y, src->y,
+	   src->states * MAXLABELS * sizeof (word_t));
+   memcpy (dst->y_state, src->y_state,
+	   src->states * MAXLABELS * sizeof (word_t));
+   memcpy (dst->into, src->into,
+	   src->states * MAXLABELS * (MAXEDGES + 1) * sizeof (word_t));
+   memcpy (dst->weight, src->weight,
+	   src->states * MAXLABELS * (MAXEDGES + 1) * sizeof (real_t));
+   memcpy (dst->int_weight, src->int_weight,
+	   src->states * MAXLABELS * (MAXEDGES + 1) * sizeof (word_t));
+   memcpy (dst->prediction, src->prediction,
+	   src->states * MAXLABELS * sizeof (byte_t));
+   if (dst->y_column)
+      memcpy (dst->y_column, src->y_column,
+	      src->states * MAXLABELS * sizeof (byte_t));
+}
+
+void
+locate_subimage (unsigned orig_level, unsigned level, unsigned bintree,
+		 unsigned *x, unsigned *y, unsigned *width, unsigned *height)
+/*
+ *  Compute pixel coordinates of the subimage which 'bintree' address is given.
+ *  The level of the original image is 'orig_level' and the level of the
+ *  subimage is 'level'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'*x', '*y'		coordinates of the upper left corner
+ *      '*width', '*height'	size of image
+ */
+{
+   /*
+    *  Compute coordinates of the subimage
+    */
+   *x = *y = 0;				/* start at NW corner */
+   *width  = width_of_level (level);
+   *height = height_of_level (level);
+
+   if (level > orig_level)
+   {
+      error ("size of tile must be less or equal than image size.");
+      return;
+   }
+   else if (bintree >= (unsigned) (1 << (orig_level - level)))
+   {
+      error ("address out of bounds.");
+      return;
+   }
+   else if (level < orig_level)
+   {
+      unsigned mask;			/* mask for bintree -> xy conversion */
+      bool_t   hor;			/* 1 next subdivision is horizontal
+					   0 next subdivision is vertical */
+      unsigned l = orig_level - 1;	/* current level */
+      
+      hor = orig_level % 2;		/* start with vertival subdivision
+					   for square image and vice versa */
+   
+      for (mask = 1 << (orig_level - level - 1); mask; mask >>= 1, hor = !hor)
+      {
+	 if (bintree & mask)		/* change coordinates */
+	 {
+	    if (hor)			/* horizontal subdivision */
+	       *y += height_of_level (l);
+	    else			/* vertical subdivision */
+	       *x += width_of_level (l);
+	 }
+	 l--;
+      }
+   }
+}
+
+void
+compute_spiral (int *vorder, unsigned image_width, unsigned image_height,
+		unsigned tiling_exp, bool_t inc_spiral)
+/*
+ *  Compute image tiling with spiral order.
+ *  'inc_spiral' specifies whether the spiral starts in the middle
+ *  of the image (TRUE) or at the border (FALSE).
+ *  'image_width'x'image_height' define the size of the image.
+ *  The image is split into 'tiling->exp' tiles.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	vorder[] is filled with tiling permutation
+ */
+{
+   unsigned x, y;			/* current position */
+   unsigned xmin, xmax, ymin, ymax;	/* boundaries for current line */
+   unsigned width, height;		/* offset for each tile */
+   unsigned lx, ly, level;		/* level x and y */
+   unsigned tiles;			/* total number of tiles */
+   unsigned address;			/* bintree address */
+   
+   lx     = log2 (image_width - 1) + 1;
+   ly     = log2 (image_height - 1) + 1;
+   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);
+   for (address = 0; address < tiles; address++)
+   {
+      unsigned x0, y0, width, height;
+      
+      locate_subimage (level, level - tiling_exp, address,
+		       &x0, &y0, &width, &height);
+      vorder [address] = (x0 < image_width && y0 < image_height) ? 0 : -1;
+   }
+
+   xmin    = 0;
+   xmax    = width_of_level (level);
+   ymin    = 0;
+   ymax    = height_of_level (level);
+   address = 0;
+
+   /*
+    *  1234
+    *  CDE5  Traverse image in spiral order 
+    *  BGF6  starting at the top left corner
+    *  A987
+    */
+   while (TRUE)
+   {
+      for (x = xmin, y = ymin; x < xmax; x += width) /* W>E */
+      {
+	 while (vorder [address] == -1)
+	    address++;
+	 if (x < image_width && y < image_height) /* valid range */
+	    vorder [address++] = xy_to_address (x, y, level, tiling_exp);
+	 while (address < tiles && vorder [address] == -1)
+	    address++;
+      }
+      ymin += height;
+
+      if (address >= tiles)
+	 break;
+      
+      for (x = xmax - width, y = ymin; y < ymax; y += height) /* N>S  */
+      {
+	 while (vorder [address] == -1)
+	    address++;
+	 if (x <= image_width && y <= image_height) /* valid range */
+	    vorder [address++] = xy_to_address (x, y, level, tiling_exp);
+	 while (address < tiles && vorder [address] == -1)
+	    address++;
+      }
+      xmax -= width;
+
+      if (address >= tiles)
+	 break;
+
+      for (x = xmax - width, y = ymax - width; x >= xmin; x -= width) /* E<W */
+      {
+	 while (vorder [address] == -1)
+	    address++;
+	 if (x <= image_width && y <= image_height) /* valid range */
+	    vorder [address++] = xy_to_address (x, y, level, tiling_exp);
+	 while (address < tiles && vorder [address] == -1)
+	    address++;
+      }
+      ymax -= height;
+
+      if (address >= tiles)
+	 break;
+
+      for (x = xmin, y = ymax - height; y >= ymin; y -= height)	/* S>N */
+      {
+	 while (vorder [address] == -1)
+	    address++;
+	 if (x <= image_width && y <= image_height) /* valid range */
+	    vorder [address++] = xy_to_address (x, y, level, tiling_exp);
+	 while (address < tiles && vorder [address] == -1)
+	    address++;
+      }
+      xmin += width;
+	 
+      if (address >= tiles)
+	 break;
+   }
+
+   if (inc_spiral)
+   {
+      int i = 0, j = tiles - 1;
+
+      while (i < j)
+      {
+	 int tmp;
+	    
+	 while (vorder [i] == -1)
+	    i++;
+	 while (vorder [j] == -1)
+	    j--;
+	    
+	 tmp 	       = vorder [i];
+	 vorder [i] = vorder [j];
+	 vorder [j] = tmp;
+	 i++;
+	 j--;
+      }
+   }
+   /*
+    *  Print tiling info
+    */
+   {
+      unsigned number;
+      
+      for (number = 0, address = 0; address < tiles; address++)
+	 if (vorder [address] != -1)
+	    debug_message ("number %d: address %d",
+			   number++, vorder [address]);
+   }
+}
+
+bool_t
+find_range (unsigned x, unsigned y, unsigned band,
+	    const wfa_t *wfa, unsigned *range_state, unsigned *range_label)
+/*
+ *  Find a range ('*range_state', '*range_label') that contains
+ *  pixel ('x', 'y') in the iven color 'band'.
+ *
+ *  Return value:
+ *	TRUE on success, or FALSE if there is no such range
+ *
+ *  Side effects:
+ *	'*range_state' and '*range_label' are modified on success.
+ */
+{
+   unsigned state, label;
+   unsigned first_state, last_state;
+   bool_t   success = NO;
+   
+   first_state = wfa->basis_states;
+   last_state  = wfa->states;
+   if (wfa->wfainfo->color)
+      switch (band)
+      {
+	 case Y:
+	    first_state = wfa->basis_states;
+	    last_state  = wfa->tree [wfa->tree [wfa->root_state][0]][0];
+	    break;
+	 case Cb:
+	    first_state = wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1;
+	    last_state  = wfa->tree [wfa->tree [wfa->root_state][0]][1];
+	    break;
+	 case Cr:
+	    first_state = wfa->tree [wfa->tree [wfa->root_state][0]][1] + 1;
+	    last_state  = wfa->states;
+	    break;
+	 default:
+	    error ("unknown color component.");
+      }
+
+   for (state = first_state; state < last_state; state++)
+      for (label = 0; label < MAXLABELS; label++)
+	 if (isrange (wfa->tree [state][label]))
+	    if (x >= wfa->x [state][label] && y >= wfa->y [state][label]
+		&& x < (unsigned) (wfa->x [state][label]
+			+ width_of_level (wfa->level_of_state [state] - 1))
+		&& y < (unsigned) (wfa->y [state][label]
+			+ height_of_level (wfa->level_of_state [state] - 1))) 
+	    {
+	       success      = YES;
+	       *range_state = state;
+	       *range_label = label;
+
+	       return success;
+	    }
+
+   return success;
+}
+
+void
+sort_ranges (unsigned state, unsigned *domain,
+	     range_sort_t *rs, const wfa_t *wfa)
+/*
+ *  Generate list of ranges in coder order.
+ *  'state' is the current state of the call tree while 'domain' is the
+ *  index of the last added WFA state.
+ *
+ *  Side effects:
+ *	'domain' is incremented after recursion returns
+ *	'rs'	 is filled accordingly
+ *
+ *  No return value.
+ */
+{
+   unsigned label;
+   
+   for (label = 0; label < MAXLABELS; label++)
+   {
+      if (isrange (wfa->tree [state][label]))
+	 rs->range_subdivided [rs->range_no] = NO;
+      else
+      {
+	 sort_ranges (wfa->tree [state][label], domain, rs, wfa);
+	 rs->range_subdivided [rs->range_no] = YES;
+      }
+
+      rs->range_state [rs->range_no]      = state;
+      rs->range_label [rs->range_no]      = label;
+      rs->range_max_domain [rs->range_no] = *domain;
+      while (!usedomain (rs->range_max_domain [rs->range_no], wfa))
+	 rs->range_max_domain [rs->range_no]--;
+
+      if (label == 1 || !rs->range_subdivided [rs->range_no])
+	 rs->range_no++;
+   }
+   
+   (*domain)++;
+}
+
+bool_t
+locate_delta_images (wfa_t *wfa)
+/*
+ *  Locate all WFA states that are part of a delta approximation.
+ *  I.e., these states are assigned to ranges that have been predicted
+ *  via MC or ND.
+ *
+ *  Return value:
+ *	TRUE	at least one state is part of a delta approximation
+ *	FALSE	no delta approximations in this WFA
+ *
+ *  Side effects:
+ *	'wfa->delta [state][label]' is set accordingly.
+ */
+{
+   unsigned state, label;
+   bool_t   delta = NO;
+
+   for (state = wfa->root_state; state >= wfa->basis_states; state--)
+      wfa->delta_state [state] = NO;
+
+   for (state = wfa->root_state; state >= wfa->basis_states; state--)
+      for (label = 0; label < MAXLABELS; label++)
+	 if (ischild (wfa->tree [state][label]))
+	    if (wfa->mv_tree [state][label].type != NONE
+		|| isedge (wfa->into [state][label][0])
+		|| wfa->delta_state [state])
+	    {
+	       delta = YES;
+	       wfa->delta_state [wfa->tree [state][label]] = YES;
+	    }
+
+   return delta;
+}
+
+/*****************************************************************************
+
+				private code
+  
+******************************************************************************/
+
+static unsigned
+xy_to_address (unsigned x, unsigned y, unsigned level, unsigned n)
+/*
+ *  Compute bintree address of subimage at coordinates ('x', 'y').
+ *  Size of original image is determined by 'level'.
+ *  'n' specifies number of iterations.
+ *
+ *  Return value:
+ *	address of subimage
+ */ 
+{ 
+   unsigned address = 0;
+
+   while (n--)
+   {
+      address <<= 1;
+      if (--level % 2) 
+      {
+	 if (x & width_of_level (level))
+	    address++;
+      }
+      else
+      {
+	 if (y & height_of_level (level))
+	    address++;
+      }
+   }
+   
+   return address;
+}
diff --git a/converter/other/fiasco/codec/wfalib.h b/converter/other/fiasco/codec/wfalib.h
new file mode 100644
index 00000000..4622fcd2
--- /dev/null
+++ b/converter/other/fiasco/codec/wfalib.h
@@ -0,0 +1,66 @@
+/*
+ *  wfalib.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _WFALIB_H
+#define _WFALIB_H
+
+#include "types.h"
+#include "wfa.h"
+#include "list.h"
+
+typedef struct range_sort
+{
+   u_word_t *range_state;
+   byte_t   *range_label;
+   u_word_t *range_max_domain;
+   bool_t   *range_subdivided;
+   unsigned  range_no;
+} range_sort_t;
+
+bool_t
+locate_delta_images (wfa_t *wfa);
+void
+sort_ranges (unsigned state, unsigned *domain,
+	     range_sort_t *rs, const wfa_t *wfa);
+bool_t
+find_range (unsigned x, unsigned y, unsigned band,
+	    const wfa_t *wfa, unsigned *range_state, unsigned *range_label);
+void
+compute_spiral (int *vorder, unsigned image_width, unsigned image_height,
+		unsigned tiling_exp, bool_t inc_spiral);
+void
+locate_subimage (unsigned orig_level, unsigned level, unsigned bintree,
+		 unsigned *x, unsigned *y, unsigned *width, unsigned *height);
+void
+copy_wfa (wfa_t *dst, const wfa_t *src);
+void 
+remove_states (unsigned from, wfa_t *wfa);
+void
+append_edge (unsigned from, unsigned into, real_t weight,
+	     unsigned label, wfa_t *wfa);
+word_t *
+compute_hits (unsigned from, unsigned to, unsigned n, const wfa_t *wfa);
+real_t 
+compute_final_distribution (unsigned state, const wfa_t *wfa);
+wfa_t *
+alloc_wfa (bool_t coding);
+void
+free_wfa (wfa_t *wfa);
+bool_t
+locate_delta_images (wfa_t *wfa);
+
+#endif /* not _WFALIB_H */
+
diff --git a/converter/other/fiasco/config.h b/converter/other/fiasco/config.h
new file mode 100644
index 00000000..d6b15a84
--- /dev/null
+++ b/converter/other/fiasco/config.h
@@ -0,0 +1,96 @@
+/* config.h.  Generated automatically by configure.  */
+/* But then manually maintained as part of Netpbm! */
+
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define to empty if the keyword does not work.  */
+/* #undef const */
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+/* #undef HAVE_DOPRNT */
+
+/* Define if you have the vprintf function.  */
+#define HAVE_VPRINTF 1
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+/* #undef size_t */
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if your processor stores words with the most significant
+   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define if the X Window System is missing or not being used.  */
+#define X_DISPLAY_MISSING 1
+
+/* Define if shifting of signed integers works */
+#define HAVE_SIGNED_SHIFT 1
+
+/* Define if you don't have the CLOCKS_PER_SEC define in <time.h>. */
+/* #undef CLOCKS_PER_SEC */
+
+/* The number of bytes in a char.  */
+#define SIZEOF_CHAR 1
+
+/* The number of bytes in a int.  */
+#define SIZEOF_INT 4
+
+/* The number of bytes in a short.  */
+#define SIZEOF_SHORT 2
+
+/* Define if you have the log2 function.  */
+/* #undef HAVE_LOG2 */
+/* For Netpbm, we won't use log2() because it might not exist.  In
+   Netpbm, misc.c contains Log2(), so we just define log2 as Log2 here.
+   But first, we include <math.h> because if we don't it may get included
+   after config.h, and then there could be a redefinition issue with log2.
+*/
+#include <math.h>
+#undef log2
+#define log2 Log2
+
+/* Define if you have the memmove function.  */
+#define HAVE_MEMMOVE 1
+
+/* 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 <X11/extensions/XShm.h> header file.  */
+/* #undef HAVE_X11_EXTENSIONS_XSHM_H */
+
+/* Define if you have the <assert.h> header file.  */
+#define HAVE_ASSERT_H 1
+
+/* Define if you have the <features.h> header file.  */
+#define HAVE_FEATURES_H 1
+
+/* Define if you have the <setjmp.h> header file.  */
+#define HAVE_SETJMP_H 1
+
+/* Define if you have the <string.h> header file.  */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/time.h> header file.  */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <unistd.h> header file.  */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the m library (-lm).  */
+#define HAVE_LIBM 1
+
+/* Name of package */
+#define PACKAGE "fiasco"
+
+/* Version number of package */
+#define VERSION "1.0"
+
+#define FIASCO_SHARE "/etc/"
diff --git a/converter/other/fiasco/display.c b/converter/other/fiasco/display.c
new file mode 100644
index 00000000..9e531149
--- /dev/null
+++ b/converter/other/fiasco/display.c
@@ -0,0 +1,422 @@
+/*
+ *  display.c:		X11 display of frames
+ *
+ *  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 <hafner@bigfoot.de>
+ *		
+ *  Based on mpeg2decode, (C) 1994, MPEG Software Simulation Group
+ *  and      mpeg2play,   (C) 1994 Stefan Eckart
+ *                                 <stefan@lis.e-technik.tu-muenchen.de>
+ *  and      tmndec       (C) 1995, 1996  Telenor R&D, Norway
+ */
+
+/*
+ *  $Date: 2000/07/03 19:35:59 $
+ *  $Author: hafner $
+ *  $Revision: 5.2 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#ifndef X_DISPLAY_MISSING
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+
+#if STDC_HEADERS
+#	include <stdlib.h>
+#	include <string.h>
+#else /* not STDC_HEADERS */
+#	if HAVE_STRING_H
+#		include <string.h>
+#	else /* not HAVE_STRING_H */
+#		include <strings.h>
+#	endif /* not HAVE_STRING_H */
+#endif /* not STDC_HEADERS */
+
+#include "types.h"
+#include "macros.h"
+#include "display.h"
+#include "binerror.h"
+
+/*****************************************************************************
+
+	       shared memory functions (if USE_SHM is defined)
+  
+*****************************************************************************/
+
+#ifdef USE_SHM
+
+#ifdef HAVE_FEATURES_H
+#include <features.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+
+int
+XShmQueryExtension (Display *dpy);
+int
+XShmGetEventBase (Display *dpy);
+
+static int
+HandleXError (Display *dpy, XErrorEvent *event);
+static void
+InstallXErrorHandler (x11_info_t *xinfo);
+static void
+DeInstallXErrorHandler (x11_info_t *xinfo);
+
+static int		shmem_flag;
+static XShmSegmentInfo	shminfo1, shminfo2;
+static int		gXErrorFlag;
+static int		CompletionType = -1;
+
+static int
+HandleXError (Display *dpy, XErrorEvent *event)
+{
+   gXErrorFlag = 1;
+   
+   return 0;
+}
+
+static void
+InstallXErrorHandler (x11_info_t *xinfo)
+{
+   XSetErrorHandler (HandleXError);
+   XFlush (xinfo->display);
+}
+
+static void
+DeInstallXErrorHandler (x11_info_t *xinfo)
+{
+   XSetErrorHandler (NULL);
+   XFlush (xinfo->display);
+}
+
+#endif /* USE_SHM */
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+display_image (unsigned x0, unsigned y0, x11_info_t *xinfo)
+/*
+ *  Display 'image' at pos ('x0', 'y0') in the current window
+ *  (given by 'xinfo->window'). 
+ *
+ *  No return value.
+ */
+{
+   int byte_order_check = 1;
+   
+   /*
+    *  Always work in native bit and byte order. This tells Xlib to
+    *  reverse bit and byte order if necessary when crossing a
+    *  network. Frankly, this part of XImages is somewhat
+    *  underdocumented, so this may not be exactly correct.
+    */
+   if (*(char *) & byte_order_check == 1)
+   {
+      xinfo->ximage->byte_order       = LSBFirst;
+      xinfo->ximage->bitmap_bit_order = LSBFirst;
+   }
+   else
+   {
+      xinfo->ximage->byte_order       = MSBFirst;
+      xinfo->ximage->bitmap_bit_order = MSBFirst;
+   }    
+
+   /* Display dithered image */
+#ifdef USE_SHM
+   if (shmem_flag)
+   {
+      XEvent xev;
+      
+      XShmPutImage (xinfo->display, xinfo->window, xinfo->gc, xinfo->ximage,
+		    0, 0, x0, y0, xinfo->ximage->width, xinfo->ximage->height,
+		    True);
+      XFlush (xinfo->display);
+      
+      while (!XCheckTypedEvent (xinfo->display, CompletionType, &xev))
+	 ;
+   }
+   else 
+#endif /* USE_SHM */
+   {
+      xinfo->ximage->data = (char *) xinfo->pixels; 
+      XPutImage (xinfo->display, xinfo->window, xinfo->gc, xinfo->ximage, 0, 0,
+		 x0, y0, xinfo->ximage->width, xinfo->ximage->height);
+   }
+}
+
+void
+close_window (x11_info_t *xinfo)
+{
+#ifdef USE_SHM
+   if (shmem_flag && xinfo->ximage)
+   {
+      XShmDetach (xinfo->display, &shminfo1);
+      XDestroyImage (xinfo->ximage);
+      xinfo->ximage = NULL;
+      shmdt (shminfo1.shmaddr);
+   }
+   else
+#endif /* USE_SHM */
+   if (xinfo->ximage)
+   {
+      XDestroyImage (xinfo->ximage);
+      xinfo->ximage = NULL;
+   }
+   if (xinfo->display)
+   {
+      XCloseDisplay (xinfo->display);
+      xinfo->display = NULL;
+   }
+}
+
+x11_info_t *
+open_window (const char *titlename, const char *iconname,
+	     unsigned width, unsigned height)
+/*
+ *  Open a X11 window of size 'width'x'height'.
+ *  If 'color' is false then allocate a colormap with grayscales.
+ *  Window and icon titles are given by 'titlename' and 'iconname',
+ *  respectively.
+ *
+ *  Return value:
+ *	X11 info struct containing display, gc, window ID and colormap.
+ */
+{
+   XVisualInfo		visual_template; /* template for XGetVisualInfo() */
+   XVisualInfo		visual_info;	/* return value of XGetVisualInfo() */
+   int			visual_n;	/* # of matches of XGetVisualInfo */
+   XEvent		xev;		
+   XSizeHints		hint;		
+   XSetWindowAttributes xswa;		
+   unsigned int		fg, bg;		/* foreground and background color */
+   unsigned int		mask;		/* event mask */
+   x11_info_t		*xinfo = calloc (1, sizeof (x11_info_t));
+   long                 visual_mask;
+   
+   if (!xinfo)
+      error ("Out of memory");
+   /*
+    *  Initialization of display
+    */
+   xinfo->display = XOpenDisplay (NULL);
+   if (xinfo->display == NULL)
+      error ("Can't open display.\n"
+	     "Make sure that your environment variable DISPLAY "
+	     "is set correctly.");
+
+   xinfo->screen = DefaultScreen (xinfo->display);
+   xinfo->gc     = DefaultGC (xinfo->display, xinfo->screen);
+
+   {
+      unsigned   depth [] 	= {32, 24, 16};
+      int        class [] 	= {TrueColor, PseudoColor};
+      const char *class_text [] = {"TrueColor", "PseudoColor"};
+      Status     found 		= 0;
+      unsigned   d, c;
+
+      for (d = 0; !found && d < sizeof (depth) / sizeof (unsigned); d++)
+	 for (c = 0; !found && c < sizeof (class) / sizeof (int); c++)
+	 {
+	    found = XMatchVisualInfo (xinfo->display, xinfo->screen,
+				      depth [d], class [c], &visual_info);
+	    if (found)
+	       fprintf (stderr, "%s : %d bit colordepth.\n",
+			class_text [c], depth [d]);
+	 }
+      if (!found && fiasco_get_verbosity ())
+	 error ("Can't find a 16/24/32 bit TrueColor/DirectColor display");
+   }
+   
+   /* Width and height of the display window */
+   hint.x = hint.y = 0;
+   hint.min_width  = hint.max_width  = hint.width  = width;
+   hint.min_height = hint.max_height = hint.height = height;
+   hint.flags = PSize | PMinSize | PMaxSize;
+
+   /* Get some colors */
+   bg = WhitePixel (xinfo->display, xinfo->screen);
+   fg = BlackPixel (xinfo->display, xinfo->screen);
+
+   /* Make the window */
+   mask = CWBackPixel | CWBorderPixel;
+   if (visual_info.depth >= 16)
+   {
+      mask |= CWColormap;
+      xswa.colormap = XCreateColormap (xinfo->display,
+				       DefaultRootWindow (xinfo->display),
+				       visual_info.visual, AllocNone);
+   }
+   xswa.background_pixel = bg;
+   xswa.border_pixel     = fg;
+   xinfo->window = XCreateWindow (xinfo->display,
+				  DefaultRootWindow (xinfo->display), 0, 0,
+				  width, height, 1, visual_info.depth,
+				  InputOutput, visual_info.visual,
+				  mask, &xswa);
+
+   XSelectInput (xinfo->display, xinfo->window, StructureNotifyMask);
+
+   /* Tell other applications about this window */
+   XSetStandardProperties (xinfo->display, xinfo->window, titlename, iconname,
+			   None, NULL, 0, &hint);
+
+   /* Map window. */
+   XMapWindow (xinfo->display, xinfo->window);
+
+   /* Wait for map. */
+   do
+   {
+      XNextEvent (xinfo->display, &xev);
+   }
+   while (xev.type != MapNotify || xev.xmap.event != xinfo->window);
+
+   /* Allocate colors */
+
+   return xinfo;
+}
+
+void
+alloc_ximage (x11_info_t *xinfo, unsigned width, unsigned height)
+/*
+ *  Allocate ximage of size 'width'x'height'.
+ *  If USE_SHM is defined then use shared memory extensions.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'ximage->ximage' and 'ximage->pixels' are set to useful values.
+ */
+{
+   char dummy;
+   
+#ifdef USE_SHM
+   if (XShmQueryExtension(xinfo->display))
+   {
+      if (fiasco_get_verbosity ())
+	 fprintf (stderr, "Trying shared memory.\n");
+      shmem_flag = 1;
+   }
+   else
+   {
+      shmem_flag = 0;
+      if (fiasco_get_verbosity ())
+	 fprintf (stderr,
+		  "Shared memory not supported\nReverting to normal Xlib.\n");
+   }
+
+   if (shmem_flag)
+      CompletionType = XShmGetEventBase (xinfo->display) + ShmCompletion;
+
+   InstallXErrorHandler (xinfo);
+
+   if (shmem_flag)
+   {
+      xinfo->ximage = XShmCreateImage (xinfo->display,
+				       DefaultVisual (xinfo->display,
+						      xinfo->screen),
+				       DefaultDepth (xinfo->display,
+						     xinfo->screen), ZPixmap,
+				       NULL, &shminfo1, width, height);
+
+      /* If no go, then revert to normal Xlib calls. */
+
+      if (xinfo->ximage == NULL)
+      {
+	 if (fiasco_get_verbosity ())
+	    fprintf (stderr,
+		     "Shared memory error, disabling (Ximage error).\n");
+	 goto shmemerror;
+      }
+
+      /* Success here, continue. */
+
+      shminfo1.shmid = shmget (IPC_PRIVATE, xinfo->ximage->bytes_per_line
+			       * xinfo->ximage->height, IPC_CREAT | 0777);
+
+      if (shminfo1.shmid < 0)
+      {
+	 XDestroyImage (xinfo->ximage);
+	 if (fiasco_get_verbosity ())
+	    fprintf (stderr,
+		     "Shared memory error, disabling (seg id error).\n");
+	 goto shmemerror;
+      }
+
+      shminfo1.shmaddr = (char *) shmat (shminfo1.shmid, 0, 0);
+      shminfo2.shmaddr = (char *) shmat (shminfo2.shmid, 0, 0);
+
+      if (shminfo1.shmaddr == ((char *) -1))
+      {
+	 XDestroyImage (xinfo->ximage);
+	 if (shminfo1.shmaddr != ((char *) -1))
+	    shmdt (shminfo1.shmaddr);
+	 if (fiasco_get_verbosity ())
+	    fprintf (stderr,
+		     "Shared memory error, disabling (address error).\n");
+	 goto shmemerror;
+      }
+
+      xinfo->ximage->data = shminfo1.shmaddr;
+      xinfo->pixels       = (byte_t *) xinfo->ximage->data;
+      shminfo1.readOnly   = False;
+
+      XShmAttach (xinfo->display, &shminfo1);
+      XSync (xinfo->display, False);
+
+      if (gXErrorFlag)
+      {
+	 /* Ultimate failure here. */
+	 XDestroyImage (xinfo->ximage);
+	 shmdt (shminfo1.shmaddr);
+	 if (fiasco_get_verbosity ())
+	    fprintf (stderr, "Shared memory error, disabling.\n");
+	 gXErrorFlag = 0;
+	 goto shmemerror;
+      }
+      else
+	 shmctl (shminfo1.shmid, IPC_RMID, 0);
+      if (fiasco_get_verbosity ())
+	 fprintf (stderr, "Sharing memory.\n");
+   }
+   else
+   {
+     shmemerror:
+      shmem_flag = 0;
+#endif /* USE_SHM */
+
+      xinfo->ximage = XCreateImage (xinfo->display,
+				    DefaultVisual (xinfo->display,
+						   xinfo->screen),
+				    DefaultDepth (xinfo->display,
+						  xinfo->screen),
+				    ZPixmap, 0, &dummy, width, height, 8, 0);
+      xinfo->pixels = calloc (width * height,
+			      xinfo->ximage->depth <= 8
+			      ? sizeof (byte_t)
+			      : (xinfo->ximage->depth <= 16
+				 ? sizeof (u_word_t) : sizeof (unsigned int)));
+      if (!xinfo->pixels)
+	 error ("Out of memory.");
+    
+#ifdef USE_SHM
+   }
+
+   DeInstallXErrorHandler (xinfo);
+#endif /* USE_SHM */
+}
+
+#endif /* not X_DISPLAY_MISSING */
diff --git a/converter/other/fiasco/display.h b/converter/other/fiasco/display.h
new file mode 100644
index 00000000..5f30b117
--- /dev/null
+++ b/converter/other/fiasco/display.h
@@ -0,0 +1,49 @@
+/*
+ *  display.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:51:17 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _DISPLAY_H
+#define _DISPLAY_H
+
+#ifndef X_DISPLAY_MISSING
+
+#include <X11/Xlib.h>
+
+#include "types.h"
+#include "image.h"
+
+typedef struct x11_info
+{
+   Display *display;
+   int	    screen;			/* default screen number */
+   Window   window;			
+   XImage  *ximage;
+   GC	    gc;
+   byte_t  *pixels;
+} x11_info_t;
+
+void
+display_image (unsigned x0, unsigned y0, x11_info_t *xinfo);
+void
+close_window (x11_info_t *xinfo);
+x11_info_t *
+open_window (const char *titlename, const char *iconname,
+	     unsigned width, unsigned height);
+void
+alloc_ximage (x11_info_t *xinfo, unsigned width, unsigned height);
+
+#endif /* X_DISPLAY_MISSING */
+
+#endif /* not _DISPLAY_H */
diff --git a/converter/other/fiasco/doc/README.LIB b/converter/other/fiasco/doc/README.LIB
new file mode 100644
index 00000000..4bf8c382
--- /dev/null
+++ b/converter/other/fiasco/doc/README.LIB
@@ -0,0 +1,51 @@
+---------------------------------------------------------------------------
+	 FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+		       Copyright (C) 1994-2000
+     Ullrich Hafner <hafner@bigfoot.de>, http://ulli.linuxave.net
+			     Version 1.0
+---------------------------------------------------------------------------
+
+FIASCO is an image and video compression system based on fractal
+coding which outperforms the well known JPEG and MPEG
+standards. FIASCO has been developed during my Ph.D. thesis "Low
+Bit-Rate Image and Video Coding with Weighted Finite Automata", Mensch
+& Buch Verlag, ISBN 3-89820-002-7.
+
+Some information about the FIASCO compression library:
+The library consists of the five "classes"
+
+	- fiasco_coder: used to encode a still image or a sequence of
+	  frames to a FIASCO stream, see fiasco_coder(3) or the file
+	  bin/cwfa.c for details.
+
+	- fiasco_decoder: used to decode the individual frames step by
+	  step, see fiasco_decoder(3) or the file bin/dwfa.c for
+	  details. 
+
+	- fiasco_image: internal representation of an decoded FIASCO
+	  image, see fiasco_image(3) or the file bin/dwfa.c for
+	  details. 
+
+	- fiasco_renderer: used to render the generated image object
+	  to one of the supported X11 output formats, see
+	  fiasco_render(3) or the files bin/dwfa.c or bin/pnmpsnr.c for
+	  details.
+
+	- fiasco_options: used to control various decoder and encoder
+	  options, see fiasco_options(3) or the files bin/cwfa.c,
+	  bin/dwfa.c or bin/pnmpsnr.c for details.
+
+
+Since the coder doesn't store any internal information, the only
+method of this class is the function fiasco_coder ().
+
+For all other classes, a new object is created with the
+fiasco_[object]_new () function, e.g., fiasco_decoder_new () creates a
+new fiasco_decoder_t object. Each object has to be deleted manually by
+calling the destructor fiasco_[object]_delete () (or by calling the
+method object->delete (object)). If you prefer C++ calls: every
+function of the type fiasco_[object]_[method] can be called via
+[object]->[method] ([object], args), too.
+
+Note: PLEASE use only functions, which are noted in the fiasco.h file
+(i.e., all functions and types with the prefix fiasco_)!
diff --git a/converter/other/fiasco/doc/fiasco_c_options.3 b/converter/other/fiasco/doc/fiasco_c_options.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_delete.3 b/converter/other/fiasco/doc/fiasco_c_options_delete.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_delete.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_new.3 b/converter/other/fiasco/doc/fiasco_c_options_new.3
new file mode 100644
index 00000000..52efb86c
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_new.3
@@ -0,0 +1,432 @@
+.\" $Id: fiasco_c_options_new.3,v 1.1 2000/10/28 17:35:06 hafner Exp $
+.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec"
+
+.SH NAME
+.B fiasco_c_options_new, fiasco_c_options_delete,
+.B fiasco_c_options_set_progress_meter, fiasco_c_options_set_basisfile,
+.B fiasco_c_options_set_smoothing, fiasco_c_options_set_tiling, 
+.B fiasco_c_options_set_chroma_quality, fiasco_c_options_set_optimizations,
+.B fiasco_c_options_set_prediction, fiasco_c_options_set_video_param,
+.B fiasco_c_options_set_quantization, fiasco_c_options_set_frame_pattern
+.B fiasco_c_options_set_title, fiasco_c_options_set_comment
+\- define additional options of FIASCO coder and decoder 
+
+.SH SYNOPSIS
+.B #include <fiasco.h>
+.sp
+.BI "fiasco_c_options_t *"
+.fi
+.BI "fiasco_c_options_new"
+.fi
+.BI "   (void);"
+.sp
+.BI "void"
+.fi
+.BI "fiasco_c_options_delete"
+.fi
+.BI "   (fiasco_c_options_t * "options );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_basisfile"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    const char * "filename );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_chroma_quality"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    float "quality_factor ,
+.fi
+.BI "    unsigned "dictionary_size );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_comment"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    const char * "comment );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_frame_pattern"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    const char * "pattern );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_optimizations"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    unsigned "min_block_level ,
+.fi
+.BI "    unsigned "max_block_level ,
+.fi
+.BI "    unsigned "max_elements ,
+.fi
+.BI "    unsigned "dictionary_size ,
+.fi
+.BI "    unsigned "optimization_level );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_quantization"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    unsigned "mantissa ,
+.fi
+.BI "    fiasco_rpf_range_e "range ,
+.fi
+.BI "    unsigned "dc_mantissa ,
+.fi
+.BI "    fiasco_rpf_range_e "dc_range );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_prediction"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    int "intra_prediction ,
+.fi
+.BI "    unsigned "min_block_level ,
+.fi
+.BI "    unsigned "max_block_level );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_progress_meter"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    fiasco_progress_e "type );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_smoothing"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    unsigned "smoothing );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_tiling"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    fiasco_tiling_e "method ,
+.fi
+.BI "    unsigned "exponent );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_title"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    const char * "title );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_c_options_set_video_param"
+.fi
+.BI "   (fiasco_c_options_t * "options ,
+.fi
+.BI "    unsigned "frames_per_second ,
+.fi
+.BI "    int "half_pixel_prediction ,
+.fi
+.BI "    int "cross_B_search ,
+.fi
+.BI "    int "B_as_past_ref );
+.fi
+
+.SH DESCRIPTION
+The \fBfiasco_c_options_new()\fP function allocates and initializes a
+FIASCO options object which is used to control additional compression
+ parameters.
+
+Conversely, the function \fBfiasco_c_options_delete()\fP discards the
+given FIASCO coder options object.
+
+Several member functions are available to modify the default behavior
+of the FIASCO coder.
+
+\fBfiasco_c_options_set_smoothing()\fP sets the
+\fIsmoothing\fP-percentage along partitioning borders when the image
+is regenerated; default is 70. This value is stored in the FIASCO file
+and is used as default smoothing percentage in the decoder.
+
+\fBfiasco_c_options_set_frame_pattern()\fP sets the type of inter frame
+compression which should be applied to individual frames of a video
+stream; default is "IPPPPPPPPP". 
+
+\fBfiasco_c_options_set_tiling()\fP sets \fImethod\fP and \fIexponent\fP
+of the image tiling algorithm which runs as initial step of the
+encoder; by default the image is subdivided into 16 tiles which
+are sorted by decreasing variance. 
+
+\fBfiasco_c_options_set_basisfile()\fP sets the \fIfilename\fP of
+the FIASCO initial basis (codebook of dictionary vectors); default is
+"small.fco". 
+
+\fBfiasco_c_options_set_chroma_quality()\fP sets the quality used when
+coding the chroma channels of a color image to the term "\fIquality\fP
+of luminance / \fIquality_factor\fP"; default is 2. Moreover, the size
+of the codebook is limited by \fIdictionary_size\fP; default is 40
+elements. 
+
+\fBfiasco_c_options_set_comment()\fP sets a \fIcomment\fP string to be
+stored in the FIASCO file; default is the empty string. 
+
+\fBfiasco_c_options_set_title()\fP sets a \fItitle\fP string to be
+stored in the FIASCO file; default is the empty string. 
+
+\fBfiasco_c_options_set_optimizations()\fP toggles various coding
+optimizations. E.g., the size of the dictionary (default is 10000),
+the subset of dictionary elements to use for an individual
+approximation (default is 5), the size of the image blocks to consider
+(4x4, ..., 64x64), and some additional low level
+optimizations (default level is 1). 
+
+\fBfiasco_c_options_set_prediction()\fP enables an additional intra
+block prediction by using a DC component approximation. By giving
+levels \fImin_block_level\fP and \fImax_block_level\fP the prediction
+can be limited to a small range of blocks only. By default, this
+method is disabled. 
+
+\fBfiasco_c_options_set_video_param()\fP defines the framerate (default
+is 25) and toggles whether to use half pixel precise motion
+compensated prediction (disabled by default), whether to determine
+motion vectors of interpolated prediction with the Cross-B-Search
+algorithm (disabled by default), and whether to allow B frames to be
+used for B frame predicion (disabled by default).
+
+\fBfiasco_c_options_set_quantization()\fP defines the quantization
+parameters of the approximation coefficients. By default the range of
+DC coefficients is [-1,+1] using a mantissa of 5 bits (and one sign
+bit). By default, all other coefficients are quantized with 3 mantissa
+bits in the interval [-1.5,+1.5].
+
+\fBfiasco_c_options_set_progress_meter()\fP sets the type of progress
+meter to be used during coding. By default, an RPM style progress bar
+using 50 hash marks (####) is used.
+
+.SH ARGUMENTS
+.TP
+options
+This object encapsulates various coding parameters.  
+
+.TP
+smoothing
+This percentage (range is 0 - i.e., no smoothing - to 100) defines how
+much the regenerated image is smoothed along the partitioning borders.
+
+.TP
+method
+Defines the algorithm which should be used to sort the image tiles
+which are generated in the initial coding step. If \fImethod\fP is
+\fBFIASCO_VARIANCE_ASC\fP then the tiles are sorted by variance - the
+first tile has the lowest variance. Conversely, when using
+\fBFIASCO_VARIANCE_DSC\fP the first tile has the largest variance. If
+\fImethod\fP is \fBFIASCO_SPIRAL_ASC\fP then the tiles are sorted like
+a spiral starting in the middle of the image. Conversely, when using
+\fBFIASCO_SPIRAL_DSC\fP the tiles are sorted like a spiral starting in
+the upper left corner.
+
+.TP
+exponent
+This value sets the number of image tiles - which are generated in the
+initial step of the encoder - to 2^\fIexponent\fP.
+
+.TP
+title
+This value is the title string of the FIASCO file. It is displayed, e.g.,
+in the window title of the decoder.
+
+.TP
+comment
+This value defines an optional comment to be stored in the FIASCO file.
+
+.TP
+pattern
+This string defines the sequence of frame types. Character \fIn\fP of
+the string defines the type of frame \fIn\fP (\fIpattern\fP is
+periodically extended). Three different frame types are available
+(case insensitive): choose 'i' for intra-frames (no inter frame
+prediction is used), 'p' for predicted frames (a frame of the
+past is used for prediction), or 'b' for bi-directional predicted
+frames (both a frame of the past and the future is used for
+prediction).
+
+.TP
+filename
+The initial basis (codebook) of the coder is loaded from this
+(ASCII) file. Files that already come with FIASCO are "small.fco" (3 elements),
+"medium.fco" (132 elements), and "large.fco" (219 elements). 
+
+.TP
+quality_factor
+When coding chroma channels (Cb and Cr band) the approximation quality
+is determined by the term `quality of Y component' / \fIquality_factor\fP.
+
+.TP
+dictionary_size
+FIASCO uses a dictionary (codebook) of variable size to approximate
+individual image blocks. The size of the codebook can be limited by
+\fIdictionary_size\fP to reduce the coding time, however, at the cost
+of decreasing quality. 
+
+.TP
+min_block_level
+During coding only those image blocks are considered for approximation
+(or prediction) which binary tree level is larger than
+\fImin_block_level\fP (minimum value is 3). (Since FIASCO internally
+works with binary trees, the size of an image block is determined by
+the \fIlevel\fP of the corresponding binary tree). Refer to following
+table to convert these values:
+
+.ce
+level | width | height
+.fi
+------+-------+--------
+.fi
+  0   |    1  |    1  
+.fi
+  1   |    1  |    2  
+.fi
+  2   |    2  |    2  
+.fi
+  3   |    2  |    4  
+.fi
+  4   |    4  |    4  
+.fi
+  5   |    4  |    8  
+.fi
+  6   |    8  |    8  
+.fi
+  7   |    8  |   16
+.fi
+------+-------+--------
+.fi
+The larger this value is the faster the coder runs but the worse the
+image quality will be.
+
+.TP
+max_block_level
+During coding only those image blocks are considered for approximation
+(or prediction) which binary tree level is smaller than
+\fImax_block_level\fP. The smaller this value is the faster the coder
+runs but the worse the image quality will be.
+
+.TP
+max_elements
+This value defines how many dictionary elements can be
+used to approximate an individual image block. The smaller this positive
+value (range is 1 to 5) is the faster the coder runs but the worse the
+image quality will be. 
+
+.TP
+optimization_level
+Additional low level optimizations are available by setting
+\fIoptimization_level\fP to one of the following values:
+.fi
+0 standard approximation method
+.fi
+1 slightly increases the approximation quality, running time is
+twice as high as with the standard method 
+.fi
+2 hardly increases the approximation quality of method 1, running time
+is twice as high as with method 1 (this method just remains for
+completeness) 
+.fi
+
+.TP
+intra_prediction
+If \fIintra_prediction\fP is set to a non-zero value then an
+additional block prediction of intra-frames is enabled. For some
+images, the image quality is slightly improved, however, at the cost of
+a significantly increased running time of the coder. 
+
+.TP
+frames_per_second
+This value defines the frame rate, i.e., how many frames per second
+should be displayed. This value has no effect during coding, it is just
+passed to the FIASCO output file where it is read and used by the
+decoder.
+
+.TP
+half_pixel_prediction
+A non-zero value enables half pixel precise motion compensated
+prediction. 
+
+.TP
+cross_B_search
+A non-zero value enables the fast Cross-B-Search algorithm to determine
+the motion vectors of an interpolated prediction. Otherwise,
+exhaustive search (in the given search range) is used. 
+
+.TP
+B_as_past_ref
+A non-zero value allows not only I- and P-frames but also B-frames to be
+used for a forward or bi-directional predicion.
+
+.TP
+mantissa, range
+Approximation coefficients are quantized to a small number of
+values (in fixed point format) in the interval [-\fIrange\fP,
++\fIrange\fP]. The number of \fImantissa\fP bits defines the accuracy of
+quantization.
+
+.TP
+dc_mantissa, dc_range
+Approximation coefficients of the DC component are quantized in a
+different way: the number of mantissa bits is given by
+\fIdc_mantissa\fP whereas the quantization interval is given by
+[-\fIdc_range\fP, +\fBdc_range\fP].
+
+.TP
+type
+This value sets the \fItype\fP of progress meter which should be used
+during coding. The following types are available:
+.fi
+\fBFIASCO_PROGRESS_NONE\fP:  no output at all
+.fi
+\fBFIASCO_PROGRESS_BAR\fP: print hash marks (###)
+\fBFIASCO_PROGRESS_PERCENT\fP: percentage meter (50%)
+
+.SH RETURN VALUES
+The function \fBfiasco_c_options_new()\fP returns a pointer to the
+newly allocated coder option object. If an error has been catched, a
+NULL pointer is returned.
+
+All set functions return 1 on success and 0 if an error has been
+catched.  
+
+In case of an error, use the function fiasco_get_error_message(3) to
+get a string with the last error message of FIASCO.
+
+.SH "SEE ALSO"
+.br
+.BR fiasco_decoder "(3), " fiasco_coder (3)
+
+Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger.
+\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on
+Selected Areas In Communications, January 1998
+.br
+Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted
+Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN
+3-89820-002-7, October 1999.
+
+.SH AUTHOR
+Ullrich Hafner <hafner@bigfoot.de>
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_basisfile.3 b/converter/other/fiasco/doc/fiasco_c_options_set_basisfile.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_basisfile.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_chroma_quality.3 b/converter/other/fiasco/doc/fiasco_c_options_set_chroma_quality.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_chroma_quality.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_comment.3 b/converter/other/fiasco/doc/fiasco_c_options_set_comment.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_comment.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_frame_pattern.3 b/converter/other/fiasco/doc/fiasco_c_options_set_frame_pattern.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_frame_pattern.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_optimizations.3 b/converter/other/fiasco/doc/fiasco_c_options_set_optimizations.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_optimizations.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_prediction.3 b/converter/other/fiasco/doc/fiasco_c_options_set_prediction.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_prediction.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_progress_meter.3 b/converter/other/fiasco/doc/fiasco_c_options_set_progress_meter.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_progress_meter.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_quantization.3 b/converter/other/fiasco/doc/fiasco_c_options_set_quantization.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_quantization.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_smoothing.3 b/converter/other/fiasco/doc/fiasco_c_options_set_smoothing.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_smoothing.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_tiling.3 b/converter/other/fiasco/doc/fiasco_c_options_set_tiling.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_tiling.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_title.3 b/converter/other/fiasco/doc/fiasco_c_options_set_title.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_title.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_c_options_set_video_param.3 b/converter/other/fiasco/doc/fiasco_c_options_set_video_param.3
new file mode 100644
index 00000000..58b2da44
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_c_options_set_video_param.3
@@ -0,0 +1 @@
+.so man3/fiasco_c_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_coder.3 b/converter/other/fiasco/doc/fiasco_coder.3
new file mode 100644
index 00000000..3d1c6b87
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_coder.3
@@ -0,0 +1,106 @@
+.\" $Id: fiasco_coder.3,v 1.2 2000/10/28 17:39:32 hafner Exp $
+.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec"
+
+.SH NAME
+.B  fiasco_coder
+\- compress image files to a FIASCO file
+
+.SH SYNOPSIS
+.B #include <fiasco.h>
+.sp
+.BI "int "
+.fi
+.BI "fiasco_coder (char const * const * "image_names ,
+.fi
+.BI "              const char * "fiasco_name ,
+.fi
+.BI "              float "quality ,
+.fi
+.BI "              const fiasco_c_options_t * "options );
+.fi
+
+.SH DESCRIPTION
+The \fBfiasco-coder()\fP function compresses the image file(s) given
+by the list of \fIimage_names\fP and creates the new FIASCO output file
+\fIfiasco_name\fP. Besides the approximation \fIquality\fP, several
+compression parameters can be adjusted by the class \fBoptions\fP (see
+fiasco_c_options_new(3)).
+
+.SH ARGUMENTS
+
+.TP
+image_names
+NULL terminated array of image filenames to process. If the first
+array element is "-" or a NULL pointer then FIASCO reads the image
+from standard input. Each array element either has to be an image
+filename or a template of the form:
+
+.ce
+prefix[start-end{+,-}step]suffix
+
+Templates are useful when compressing video streams: e.g., if the template
+"img0[12-01-2].pgm" is given as array element, then FIASCO compresses the
+images img012.pgm, img010.pgm, ..., img002.pgm (in this order).
+
+If a filename is a relative path then the images are searched for in
+the current directory and in the (colon-separated) list of directories
+given by the environment variable \fBFIASCO_IMAGES\fP.
+
+.TP
+fiasco_name
+Name of the FIASCO output file. If the name is "-" or NULL then the
+file is produced on standard output.
+
+If \fIfiasco_name\fP is a relative path and the environment variable
+\fBFIASCO_DATA\fP is a (colon-separated) list of directories, then the
+output file is written to the first (writable) directory of this
+list. Otherwise, the current directory is used to store the output
+file.
+
+.TP
+quality
+Defines the quality of compression. Quality has to be a positive
+value, its typical range is 1.0 (worst) to 100.0 (best). Larger values
+are also allowed - at the cost of exploding encoding times.
+
+.TP
+options
+This "class" encapsulates the various coding and decoding
+parameters. Use the functions fiasco_c_options_new(3) and
+fiasco_c_options_delete(3) to create and delete an object of this
+class. Several member functions (see fiasco_c_options(3)) are
+available to change the default values.
+
+.SH RETURN VALUE
+The function \fBfiasco_coder()\fP returns 1 if the FIASCO file has
+been successfully written. If an error has been catched during
+compression, 0 is returned - use the function
+fiasco_get_error_message(3) to get the last error message of FIASCO.
+
+.SH ENVIRONMENT
+.PD 0
+.TP
+.B FIASCO_IMAGES
+Search path for image files. Default is "./".
+.TP
+.B FIASCO_DATA
+Search and save path for FIASCO files. Default is "./".
+.PD 
+
+.SH "SEE ALSO"
+.br
+.BR fiasco_c_options_new "(3), " fiasco_c_options_delete (3), 
+.br
+.BR fiasco_c_options "(3), " fiasco_get_error_message (3)
+.br
+
+Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger.
+\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on
+Selected Areas In Communications, January 1998
+.br
+Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted
+Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN
+3-89820-002-7, October 1999.
+
+.SH AUTHOR
+Ullrich Hafner <hafner@bigfoot.de>
diff --git a/converter/other/fiasco/doc/fiasco_d_options.3 b/converter/other/fiasco/doc/fiasco_d_options.3
new file mode 100644
index 00000000..21f1db63
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_d_options.3
@@ -0,0 +1 @@
+.so man3/fiasco_d_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_d_options_delete.3 b/converter/other/fiasco/doc/fiasco_d_options_delete.3
new file mode 100644
index 00000000..21f1db63
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_d_options_delete.3
@@ -0,0 +1 @@
+.so man3/fiasco_d_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_d_options_new.3 b/converter/other/fiasco/doc/fiasco_d_options_new.3
new file mode 100644
index 00000000..4294330a
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_d_options_new.3
@@ -0,0 +1,122 @@
+.\" $Id: fiasco_d_options_new.3,v 1.1 2000/10/28 17:35:12 hafner Exp $
+.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec"
+
+.SH NAME
+.B  fiasco_d_options_new, fiasco_d_options_set_magnification,
+.B fiasco_d_options_delete, fiasco_d_options_set_smoothing
+.B fiasco_d_options_set_4_2_0_format
+\- define additional options of FIASCO decoder 
+
+.SH SYNOPSIS
+.B #include <fiasco.h>
+.sp
+.BI "fiasco_d_options_t *"
+.fi
+.BI "fiasco_d_options_new"
+.fi
+.BI "   (void);"
+.sp
+.BI "void"
+.fi
+.BI "fiasco_d_options_delete"
+.fi
+.BI "   (fiasco_d_options_t * "options );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_d_options_set_4_2_0_format"
+.fi
+.BI "   (fiasco_d_options_t * "options ,
+.fi
+.BI "    int "format );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_d_options_set_magnification"
+.fi
+.BI "   (fiasco_d_options_t * "options ,
+.fi
+.BI "    int "level );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_d_options_set_smoothing"
+.fi
+.BI "   (fiasco_d_options_t * "options ,
+.fi
+.BI "    unsigned "smoothing );
+.fi
+
+.SH DESCRIPTION
+The \fBfiasco_d_options_new()\fP function allocates and initializes a
+FIASCO options object which is used to control additional
+decompression parameters.
+
+Conversely, the function \fBfiasco_d_options_delete()\fP discards the
+given FIASCO decoder options object.
+
+Several member functions are available to modify the default behavior
+of the FIASCO decoder.
+
+\fBfiasco_d_options_set_smoothing()\fP sets the
+\fIsmoothing\fP-percentage along partitioning borders when the images
+are regenerated; default is 70.
+
+\fBfiasco_d_options_set_magnification()\fP sets the \fImagnification\fP
+of the regenerated image; default is 0, i.e., the image geometry is
+not changed.
+
+\fBfiasco_d_options_set_4_2_0_format()\fP defines whether the decoder
+should use the default 4:4:4 format or the 4:2:0 format. The latter
+one significantly reduces the decoding time at the cost of some
+additional blocking artefacts.
+
+.SH ARGUMENTS
+.TP
+options
+This object encapsulates various decoding parameters.  
+
+.TP
+smoothing
+This percentage (range is 0 - i.e., no smoothing - to 100) defines how
+much the regenerated image is smoothed along the partitioning borders.
+
+.TP
+level
+This value gives the magnification of the decoded image with respect
+to the original size. Positive values increase and negative values
+decrease the width and height of the image by a factor of
+2^abs(\fIlevel\fP).
+
+.TP
+format
+If \fIformat\fP is 0 then the 4:4:4 color image format is used, i.e.,
+the chroma channel are of the same size as the luminance. Otherwise,
+the 4:2:0 format is used. Then, width and height of each chroma
+channel is only one half of the width and height of the luminance.
+
+.SH RETURN VALUES
+The function \fBfiasco_d_options_new()\fP returns a pointer to the
+newly allocated decoder option object. If an error has been catched, a
+NULL pointer is returned.
+
+All set functions return 1 on success and 0 if an error has been
+catched.  
+
+In case of an error, use the function fiasco_get_error_message(3) to
+get a string with the last error message of FIASCO.
+
+.SH "SEE ALSO"
+.br
+.BR fiasco_decoder "(3), " fiasco_coder (3)
+
+Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger.
+\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on
+Selected Areas In Communications, January 1998
+.br
+Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted
+Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN
+3-89820-002-7, October 1999.
+
+.SH AUTHOR
+Ullrich Hafner <hafner@bigfoot.de>
diff --git a/converter/other/fiasco/doc/fiasco_d_options_set_4_2_0_format.3 b/converter/other/fiasco/doc/fiasco_d_options_set_4_2_0_format.3
new file mode 100644
index 00000000..21f1db63
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_d_options_set_4_2_0_format.3
@@ -0,0 +1 @@
+.so man3/fiasco_d_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_d_options_set_magnification.3 b/converter/other/fiasco/doc/fiasco_d_options_set_magnification.3
new file mode 100644
index 00000000..21f1db63
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_d_options_set_magnification.3
@@ -0,0 +1 @@
+.so man3/fiasco_d_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_d_options_set_smoothing.3 b/converter/other/fiasco/doc/fiasco_d_options_set_smoothing.3
new file mode 100644
index 00000000..21f1db63
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_d_options_set_smoothing.3
@@ -0,0 +1 @@
+.so man3/fiasco_d_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder.3 b/converter/other/fiasco/doc/fiasco_decoder.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder_delete.3 b/converter/other/fiasco/doc/fiasco_decoder_delete.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_delete.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_comment.3 b/converter/other/fiasco/doc/fiasco_decoder_get_comment.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_get_comment.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_frame.3 b/converter/other/fiasco/doc/fiasco_decoder_get_frame.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_get_frame.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_framerate.3 b/converter/other/fiasco/doc/fiasco_decoder_get_framerate.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_get_framerate.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_height.3 b/converter/other/fiasco/doc/fiasco_decoder_get_height.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_get_height.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_length.3 b/converter/other/fiasco/doc/fiasco_decoder_get_length.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_get_length.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_title.3 b/converter/other/fiasco/doc/fiasco_decoder_get_title.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_get_title.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder_get_width.3 b/converter/other/fiasco/doc/fiasco_decoder_get_width.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_get_width.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder_is_color.3 b/converter/other/fiasco/doc/fiasco_decoder_is_color.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_is_color.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_decoder_new.3 b/converter/other/fiasco/doc/fiasco_decoder_new.3
new file mode 100644
index 00000000..05e981a9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_new.3
@@ -0,0 +1,194 @@
+.\" $Id: fiasco_decoder_new.3,v 1.5 2000/10/28 17:39:32 hafner Exp $
+.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec"
+
+.SH NAME
+.B  fiasco_decoder_new, fiasco_decoder_delete,
+.B fiasco_decoder_write_frame, fiasco_decoder_get_frame,
+.B fiasco_decoder_get_length, fiasco_decoder_get_rate,
+.B fiasco_decoder_get_width, fiasco_decoder_get_height
+.B fiasco_decoder_get_title, fiasco_decoder_get_comment
+.B fiasco_decoder_is_color
+\- decompress a FIASCO file
+
+.SH SYNOPSIS
+.B #include <fiasco.h>
+.sp
+.BI "fiasco_decoder_t *"
+.fi
+.BI "fiasco_decoder_new (const char * "fiasco_name ,
+.fi
+.BI "                    const fiasco_d_options_t * "options );
+.sp
+.BI "void"
+.fi
+.BI "fiasco_decoder_delete (fiasco_decoder_t * "decoder );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_decoder_write_frame (fiasco_decoder_t * "decoder ,
+.fi
+.BI "                            const char * "image_name );
+.sp
+.BI "fiasco_image_t *"
+.fi
+.BI "fiasco_decoder_get_frame (fiasco_decoder_t * "decoder );
+.sp
+.BI "unsigned"
+.fi
+.BI "fiasco_decoder_get_length (fiasco_decoder_t * "decoder );
+.sp
+.BI "unsigned"
+.fi
+.BI "fiasco_decoder_get_rate (fiasco_decoder_t * "decoder );
+.sp
+.BI "unsigned"
+.fi
+.BI "fiasco_decoder_get_width (fiasco_decoder_t * "decoder );
+.sp
+.BI "unsigned"
+.fi
+.BI "fiasco_decoder_get_height (fiasco_decoder_t * "decoder );
+.sp
+.BI "const char *"
+.fi
+.BI "fiasco_decoder_get_title (fiasco_decoder_t * "decoder );
+.sp
+.BI "const char *"
+.fi
+.BI "fiasco_decoder_get_comment (fiasco_decoder_t * "decoder );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_decoder_is_color (fiasco_decoder_t * "decoder );
+.fi
+
+.SH DESCRIPTION
+The \fBfiasco_decoder_new()\fP function initializes the decompression
+of FIASCO file \fIfiasco_name\fP. Several decompression parameters
+can be adjusted by the class \fIoptions\fP (see
+fiasco_d_options_new(3)).
+
+The individual frames of a FIASCO video can be decompressed by calling
+successively either function \fBfiasco_decoder_write_frame()\fP or
+\fBfiasco_decoder_get_frame()\fP.
+
+The function \fBfiasco_decoder_write_frame()\fP decompresses the
+current frame and writes it in raw pgm(5) or ppm(5) format to the file
+\fIimage_name\fP. If \fIimage_name\fP=- or a NULL pointer then the
+image file is produced on the standard output. If \fIimage_name\fP is a
+relative path and the environment variable \fBFIASCO_IMAGES\fP is a
+(colon-separated) list of directories, then the output file is
+written to the first (writable) directory of this list. Otherwise, the
+current directory is used to store the file.
+
+The function \fBfiasco_decoder_get_frame()\fP decompresses the
+current frame and returns the computed image object. Use the function
+fiasco_renderer_new(3) to create a renderer object that converts the
+FIASCO image to the desired format. 
+
+After all frames have been decompressed, the function
+\fBfiasco_decoder_delete()\fP should be called to close the input file
+and to free temporarily allocated memory.
+
+Number of available frames, frame rate and frames geometry, type of the
+FIASCO file are accessible through member functions
+\fBfiasco_decoder_get_length()\fP,
+\fBfiasco_decoder_get_rate()\fP,  
+\fBfiasco_decoder_get_width()\fP,
+\fBfiasco_decoder_get_height()\fP,
+and \fBfiasco_decoder_is_color()\fP. Use \fBfiasco_decoder_get_title()\fP,
+\fBfiasco_decoder_get_comment()\fP to read title and comment strings of the
+FIASCO file. 
+
+.SH ARGUMENTS
+
+.TP
+fiasco_name
+Filename of the FIASCO input file. If \fIfiasco_name\fP is a NULL pointer
+or "-" then the decoder reads from standard input. If the file is not
+found in the current directory and the environment variable
+\fBFIASCO_DATA\fP is a (colon-separated) list of directories, then the
+input file is searched for in these directories, too.
+
+.TP
+options
+This "class" encapsulates the various coding and decoding
+parameters. Use the functions fiasco_d_options_new(3) and
+fiasco_d_options_delete(3) to create and delete an object of this
+class. Several member functions (see fiasco_d_options(3)) are
+available to change the default values.
+
+.TP
+decoder
+The decoder "class" encapsulates the FIASCO decoder. It is used to
+store the internal state of the decoder.
+
+.SH RETURN VALUES
+The function \fBfiasco_decoder_new()\fP returns a pointer to the newly
+allocated decoder object. If an error has been catched, a NULL pointer
+is returned.
+
+The function \fBfiasco_decoder_write_frame()\fP returns 1 if the file
+has been successfully written. Otherwise, the function returns 0.
+
+The function \fBfiasco_decoder_get_frame()\fP returns a pointer to the
+newly allocated FIASCO image object. If an error has been catched, a NULL
+pointer is returned.
+
+The function \fBfiasco_decoder_get_length()\fP returns the number of
+frames of the FIASCO file. If an error has been catched, 0 is
+returned. 
+
+The function \fBfiasco_decoder_get_rate()\fP returns the
+framerate (number of frames per second) of the FIASCO file. If an
+error has been catched, 0 is returned.
+
+The function \fBfiasco_decoder_get_width()\fP returns the width of the
+decoded frames of the FIASCO file. If an error has been catched, 0 is
+returned.
+
+The function \fBfiasco_decoder_get_height()\fP returns the height of the
+decoded frames of the FIASCO file. If an error has been catched, 0 is
+returned.
+
+The function \fBfiasco_decoder_get_title()\fP returns an optional
+title of the FIASCO file. If an error has been catched, 0 is returned.
+
+The function \fBfiasco_decoder_get_comment()\fP returns an optional
+comment of the FIASCO file. If an error has been catched, 0 is returned.
+
+The function \fBfiasco_decoder_is_color()\fP returns 0 if the decoded
+frames are grayscale images, otherwise a non-zero value is
+returned.
+
+In case of an error in one of the above functions, use the function
+fiasco_get_error_message(3) to get a string describing the last error
+message of FIASCO.
+
+.SH ENVIRONMENT
+.PD 0
+.TP
+.B FIASCO_IMAGES
+Search path for image files. Default is "./".
+.TP
+.B FIASCO_DATA
+Search and save path for FIASCO files. Default is "./".
+.PD 
+
+.SH "SEE ALSO"
+.br
+.BR fiasco_d_options_new "(3), " fiasco_d_options_delete (3), 
+.br
+.BR fiasco_d_options "(3), " fiasco_get_error_message (3)
+.br
+
+Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger.
+\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on
+Selected Areas In Communications, January 1998
+.br
+Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted
+Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN
+3-89820-002-7, October 1999.
+
+.SH AUTHOR
+Ullrich Hafner <hafner@bigfoot.de>
diff --git a/converter/other/fiasco/doc/fiasco_decoder_write_frame.3 b/converter/other/fiasco/doc/fiasco_decoder_write_frame.3
new file mode 100644
index 00000000..33c0d21b
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_decoder_write_frame.3
@@ -0,0 +1 @@
+.so man3/fiasco_decoder_new.3
diff --git a/converter/other/fiasco/doc/fiasco_get_error_message.3 b/converter/other/fiasco/doc/fiasco_get_error_message.3
new file mode 100644
index 00000000..09d593fb
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_get_error_message.3
@@ -0,0 +1,41 @@
+.\" $Id: fiasco_get_error_message.3,v 1.1 2000/06/14 19:07:02 hafner Exp $
+.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec"
+
+.SH NAME
+.B  fiasco_get_error_message
+\- return string describing last error catched in FIASCO library
+
+.SH SYNOPSIS
+.B #include <fiasco.h>
+.sp
+.BI "const char * "
+.fi
+.BI "fiasco_get_error_message (void);"
+.fi
+
+.SH DESCRIPTION
+The \fBfiasco_get_error_message()\fP function returns a string
+describing the last error that has been catched in the FIASCO library.
+
+.SH RETURN VALUE
+The function \fBfiasco_get_error_message()\fP returns the appropriate
+description string, or an empty string if no error has been catched so
+far.
+
+.SH "SEE ALSO"
+.br
+.BR fiasco_options "(3), " fiasco_coder (3), 
+.br
+.BR fiasco_decoder "(3), " fiasco_renderer (3)
+.br
+
+Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger.
+\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on
+Selected Areas In Communications, January 1998
+.br
+Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted
+Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN
+3-89820-002-7, October 1999.
+
+.SH AUTHOR
+Ullrich Hafner <hafner@bigfoot.de>
diff --git a/converter/other/fiasco/doc/fiasco_get_verbosity.3 b/converter/other/fiasco/doc/fiasco_get_verbosity.3
new file mode 100644
index 00000000..884cd19e
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_get_verbosity.3
@@ -0,0 +1 @@
+.so man3/fiasco_set_verbosity.3
diff --git a/converter/other/fiasco/doc/fiasco_image.3 b/converter/other/fiasco/doc/fiasco_image.3
new file mode 100644
index 00000000..f8df38d5
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_image.3
@@ -0,0 +1 @@
+.so man3/fiasco_image_new.3
diff --git a/converter/other/fiasco/doc/fiasco_image_delete.3 b/converter/other/fiasco/doc/fiasco_image_delete.3
new file mode 100644
index 00000000..f8df38d5
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_image_delete.3
@@ -0,0 +1 @@
+.so man3/fiasco_image_new.3
diff --git a/converter/other/fiasco/doc/fiasco_image_get_height.3 b/converter/other/fiasco/doc/fiasco_image_get_height.3
new file mode 100644
index 00000000..f8df38d5
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_image_get_height.3
@@ -0,0 +1 @@
+.so man3/fiasco_image_new.3
diff --git a/converter/other/fiasco/doc/fiasco_image_get_width.3 b/converter/other/fiasco/doc/fiasco_image_get_width.3
new file mode 100644
index 00000000..f8df38d5
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_image_get_width.3
@@ -0,0 +1 @@
+.so man3/fiasco_image_new.3
diff --git a/converter/other/fiasco/doc/fiasco_image_is_color.3 b/converter/other/fiasco/doc/fiasco_image_is_color.3
new file mode 100644
index 00000000..f8df38d5
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_image_is_color.3
@@ -0,0 +1 @@
+.so man3/fiasco_image_new.3
diff --git a/converter/other/fiasco/doc/fiasco_image_new.3 b/converter/other/fiasco/doc/fiasco_image_new.3
new file mode 100644
index 00000000..10625b63
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_image_new.3
@@ -0,0 +1,95 @@
+.\" $Id: fiasco_image_new.3,v 1.2 2000/06/14 19:26:06 hafner Exp $
+.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec"
+
+.SH NAME
+.B  fiasco_image_new, fiasco_image_delete, fiasco_image_get_width,
+.B  fiasco_image_get_height,  fiasco_image_is_color
+\- handle FIASCO image objects
+
+.SH SYNOPSIS
+.B #include <fiasco.h>
+.sp
+.BI "fiasco_image_t *"
+.fi
+.BI "fiasco_image_new (const char * "filename );
+.sp
+.BI "void"
+.fi
+.BI "fiasco_image_delete (fiasco_image_t * "image );
+.sp
+.BI "unsigned"
+.fi
+.BI "fiasco_image_get_width (const fiasco_image_t * "image );
+.sp
+.BI "unsigned"
+.fi
+.BI "fiasco_image_get_height (const fiasco_image_t * "image );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_image_is_color (const fiasco_image_t * "image );
+.fi
+
+.SH DESCRIPTION
+The \fBfiasco_image_new()\fP function reads the given image file and
+allocates and initializes a FIASCO image object. Use the function
+fiasco_renderer_new(3) to create a renderer object that converts the
+FIASCO image to the desired image format.
+
+The function \fBfiasco_image_delete()\fP deletes the image object and
+frees the image buffer. 
+
+Image geometry and type are accessible through member functions
+\fBfiasco_image_get_width()\fP,
+\fBfiasco_image_get_height()\fP,
+and \fBfiasco_image_is_color()\fP. 
+
+.SH ARGUMENTS
+
+.TP
+image
+The image "class" encapsulates the FIASCO image object. It is used to
+store the pixel values of the decoded or read image.
+
+.TP
+filename
+Image filename to process. If \fIfilename\fP is "-" or a NULL pointer
+then the image is read from standard input. If a filename is a
+relative path then the images are searched for in the current
+directory and in the (colon-separated) list of directories given by
+the environment variable \fBFIASCO_IMAGES\fP.
+
+.SH RETURN VALUE
+The function \fBfiasco_image_new()\fP returns a pointer to the newly
+allocated image object. If an error has been catched, a NULL pointer
+is returned.
+
+The function \fBfiasco_image_get_width()\fP returns the width of the
+image. If an error has been catched, 0 is returned.
+
+The function \fBfiasco_image_get_height()\fP returns the height of the
+image. If an error has been catched, 0 is returned.
+
+The function \fBfiasco_image_is_color()\fP returns 0 if the image
+object is a grayscale image, otherwise a non-zero value is returned.
+
+In case of an error in one of the above functions, use the function
+fiasco_get_error_message(3) to get a string with the last error
+message of FIASCO.
+
+.SH "SEE ALSO"
+.br
+.BR fiasco_decoder_get_frame "(3), " fiasco_get_error_message (3)
+.BR fiasco_renderer_new (3)
+.br
+
+Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger.
+\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on
+Selected Areas In Communications, January 1998
+.br
+Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted
+Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN
+3-89820-002-7, October 1999.
+
+.SH AUTHOR
+Ullrich Hafner <hafner@bigfoot.de>
diff --git a/converter/other/fiasco/doc/fiasco_options.3 b/converter/other/fiasco/doc/fiasco_options.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_delete.3 b/converter/other/fiasco/doc/fiasco_options_delete.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_delete.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_new.3 b/converter/other/fiasco/doc/fiasco_options_new.3
new file mode 100644
index 00000000..26e070ca
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_new.3
@@ -0,0 +1,441 @@
+.\" $Id: fiasco_options_new.3,v 1.2 2000/06/25 16:38:06 hafner Exp $
+.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec"
+
+.SH NAME
+.B  fiasco_options_new, fiasco_options_set_magnification,
+.B fiasco_options_delete, fiasco_options_set_progress_meter,
+.B fiasco_options_set_smoothing, fiasco_options_set_tiling, 
+.B fiasco_options_set_4_2_0_format, fiasco_options_set_basisfile,
+.B fiasco_options_set_chroma_quality, fiasco_options_set_optimizations,
+.B fiasco_options_set_prediction, fiasco_options_set_video_param,
+.B fiasco_options_set_quantization, fiasco_options_set_frame_pattern
+\- define additional options of FIASCO coder and decoder 
+
+.SH SYNOPSIS
+.B #include <fiasco.h>
+.sp
+.BI "fiasco_options_t *"
+.fi
+.BI "fiasco_options_new"
+.fi
+.BI "   (void);"
+.sp
+.BI "void"
+.fi
+.BI "fiasco_options_delete"
+.fi
+.BI "   (fiasco_options_t * "options );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_4_2_0_format"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    int "format );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_basisfile"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    const char * "filename );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_chroma_quality"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    float "quality_factor ,
+.fi
+.BI "    unsigned "dictionary_size );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_frame_pattern"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    const char * "pattern );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_magnification"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    int "level );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_optimizations"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    unsigned "min_block_level ,
+.fi
+.BI "    unsigned "max_block_level ,
+.fi
+.BI "    unsigned "max_elements ,
+.fi
+.BI "    unsigned "dictionary_size ,
+.fi
+.BI "    unsigned "optimization_level );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_quantization"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    unsigned "mantissa ,
+.fi
+.BI "    fiasco_rpf_range_e "range ,
+.fi
+.BI "    unsigned "dc_mantissa ,
+.fi
+.BI "    fiasco_rpf_range_e "dc_range );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_prediction"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    int "intra_prediction ,
+.fi
+.BI "    unsigned "min_block_level ,
+.fi
+.BI "    unsigned "max_block_level );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_progress_meter"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    fiasco_progress_e "type );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_smoothing"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    unsigned "smoothing );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_tiling"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    fiasco_tiling_e "method ,
+.fi
+.BI "    unsigned "exponent );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_options_set_video_param"
+.fi
+.BI "   (fiasco_options_t * "options ,
+.fi
+.BI "    unsigned "frames_per_second ,
+.fi
+.BI "    int "half_pixel_prediction ,
+.fi
+.BI "    int "cross_B_search ,
+.fi
+.BI "    int "B_as_past_ref );
+.fi
+
+.SH DESCRIPTION
+The \fBfiasco_options_new()\fP function allocates and initializes a
+FIASCO options object which is used to control additional compression and
+decompression parameters.
+
+Conversely, the function \fBfiasco_options_delete()\fP discards the
+given FIASCO options object.
+
+Several member functions are available to modify the default behavior
+of the FIASCO coder and decoder. 
+
+\fBfiasco_options_set_smoothing()\fP sets the
+\fIsmoothing\fP-percentage along partitioning borders when the image
+is regenerated; default is 70. This option is used both by the decoder
+and encoder. You should use the \fIsmoothing\fP value specified in the
+FIASCO file when you are decoding video frames.
+
+\fBfiasco_options_set_magnification()\fP sets the \fImagnification\fP
+of the regenerated image; default is 0, i.e., the image geometry is
+not changed. This option is used by the decoder only.
+
+\fBfiasco_options_set_4_2_0_format()\fP defines whether the decoder
+should use the default 4:4:4 format or the 4:2:0 format. The latter
+one significantly reduces the decoding time at the cost of some
+additional blocking artefacts. This option is used by the decoder only.
+
+\fBfiasco_options_set_frame_pattern()\fP sets the type of inter frame
+compression which should be applied to individual frames of a video
+stream; default is "IPPPPPPPPP". 
+
+\fBfiasco_options_set_tiling()\fP sets \fImethod\fP and \fIexponent\fP
+of the image tiling algorithm which runs as initial step of the
+encoder; by default the image is subdivided into 16 tiles which
+are sorted by decreasing variance. 
+
+\fBfiasco_options_set_basisfile()\fP sets the \fIfilename\fP of
+the FIASCO initial basis (codebook of dictionary vectors); default is
+"small.fco". 
+
+\fBfiasco_options_set_chroma_quality()\fP sets the quality used when
+coding the chroma channels of a color image to the term "\fIquality\fP
+of luminance / \fIquality_factor\fP"; default is 2. Moreover, the size
+of the codebook is limited by \fIdictionary_size\fP; default is 40
+elements. 
+
+\fBfiasco_options_set_optimizations()\fP toggles various coding
+optimizations. E.g., the size of the dictionary (default is 10000),
+the subset of dictionary elements to use for an individual
+approximation (default is 5), the size of the image blocks to consider
+(4x4, ..., 64x64), and some additional low level
+optimizations (default level is 1). 
+
+\fBfiasco_options_set_prediction()\fP enables an additional intra
+block prediction by using a DC component approximation. By giving
+levels \fImin_block_level\fP and \fImax_block_level\fP the prediction
+can be limited to a small range of blocks only. By default, this
+method is disabled. 
+
+\fBfiasco_options_set_video_param()\fP defines the framerate (default
+is 25) and toggles whether to use half pixel precise motion
+compensated prediction (disabled by default), whether to determine
+motion vectors of interpolated prediction with the Cross-B-Search
+algorithm (disabled by default), and whether to allow B frames to be
+used for B frame predicion (disabled by default).
+
+\fBfiasco_options_set_quantization()\fP defines the quantization
+parameters of the approximation coefficients. By default the range of
+DC coefficients is [-1,+1] using a mantissa of 5 bits (and one sign
+bit). By default, all other coefficients are quantized with 3 mantissa
+bits in the interval [-1.5,+1.5].
+
+\fBfiasco_options_set_progress_meter()\fP sets the type of progress
+meter to be used during coding. By default, an RPM style progress bar
+using 50 hash marks (####) is used.
+
+.SH ARGUMENTS
+.TP
+options
+This object encapsulates the various coding and decoding parameters.  
+
+.TP
+smoothing
+This percentage (range is 0 - i.e., no smoothing - to 100) defines how
+much the regenerated image is smoothed along the partitioning borders.
+
+.TP
+level
+This value gives the magnification of the decoded image with respect
+to the original size. Positive values increase and negative values
+decrease the width and height of the image by a factor of
+2^abs(\fIlevel\fP).
+
+.TP
+format
+If \fIformat\fP is 0 then the 4:4:4 color image format is used, i.e.,
+the chroma channel are of the same size as the luminance. Otherwise,
+the 4:2:0 format is used. Then, width and height of each chroma
+channel is only one half of the width and height of the luminance.
+
+.TP
+method
+Defines the algorithm which should be used to sort the image tiles
+which are generated in the initial coding step. If \fImethod\fP is
+\fBFIASCO_VARIANCE_ASC\fP then the tiles are sorted by variance - the
+first tile has the lowest variance. Conversely, when using
+\fBFIASCO_VARIANCE_DSC\fP the first tile has the largest variance. If
+\fImethod\fP is \fBFIASCO_SPIRAL_ASC\fP then the tiles are sorted like
+a spiral starting in the middle of the image. Conversely, when using
+\fBFIASCO_SPIRAL_DSC\fP the tiles are sorted like a spiral starting in
+the upper left corner.
+
+.TP
+exponent
+This value sets the number of image tiles - which are generated in the
+initial step of the encoder - to 2^\fIexponent\fP.
+
+.TP
+pattern
+This string defines the sequence of frame types. Character \fIn\fP of
+the string defines the type of frame \fIn\fP (\fIpattern\fP is
+periodically extended). Three different frame types are available
+(case insensitive): choose 'i' for intra-frames (no inter frame
+prediction is used), 'p' for predicted frames (a frame of the
+past is used for prediction), or 'b' for bi-directional predicted
+frames (both a frame of the past and the future is used for
+prediction).
+
+.TP
+filename
+The initial basis (codebook) of the coder is loaded from this
+(ASCII) file. Files that already come with FIASCO are "small.fco" (3 elements),
+"medium.fco" (132 elements), and "large.fco" (219 elements). 
+
+.TP
+quality_factor
+When coding chroma channels (Cb and Cr band) the approximation quality
+is determined by the term `quality of Y component' / \fIquality_factor\fP.
+
+.TP
+dictionary_size
+FIASCO uses a dictionary (codebook) of variable size to approximate
+individual image blocks. The size of the codebook can be limited by
+\fIdictionary_size\fP to reduce the coding time, however, at the cost
+of decreasing quality. 
+
+.TP
+min_block_level
+During coding only those image blocks are considered for approximation
+(or prediction) which binary tree level is larger than
+\fImin_block_level\fP (minimum value is 3). (Since FIASCO internally
+works with binary trees, the size of an image block is determined by
+the \fIlevel\fP of the corresponding binary tree). Refer to following
+table to convert these values:
+
+.ce
+level | width | height
+.fi
+------+-------+--------
+.fi
+  0   |    1  |    1  
+.fi
+  1   |    1  |    2  
+.fi
+  2   |    2  |    2  
+.fi
+  3   |    2  |    4  
+.fi
+  4   |    4  |    4  
+.fi
+  5   |    4  |    8  
+.fi
+  6   |    8  |    8  
+.fi
+  7   |    8  |   16
+.fi
+------+-------+--------
+.fi
+The larger this value is the faster the coder runs but the worse the
+image quality will be.
+
+.TP
+max_block_level
+During coding only those image blocks are considered for approximation
+(or prediction) which binary tree level is smaller than
+\fImax_block_level\fP. The smaller this value is the faster the coder
+runs but the worse the image quality will be.
+
+.TP
+max_elements
+This value defines how many dictionary elements can be
+used to approximate an individual image block. The smaller this positive
+value (range is 1 to 5) is the faster the coder runs but the worse the
+image quality will be. 
+
+.TP
+optimization_level
+Additional low level optimizations are available by setting
+\fIoptimization_level\fP to one of the following values:
+.fi
+0 standard approximation method
+.fi
+1 slightly increases the approximation quality, running time is
+twice as high as with the standard method 
+.fi
+2 hardly increases the approximation quality of method 1, running time
+is twice as high as with method 1 (this method just remains for
+completeness) 
+.fi
+
+.TP
+intra_prediction
+If \fIintra_prediction\fP is set to a non-zero value then an
+additional block prediction of intra-frames is enabled. For some
+images, the image quality is slightly improved, however, at the cost of
+a significantly increased running time of the coder. 
+
+.TP
+frames_per_second
+This value defines the frame rate, i.e., how many frames per second
+should be displayed. This value has no effect during coding, it is just
+passed to the FIASCO output file where it is read and used by the
+decoder.
+
+.TP
+half_pixel_prediction
+A non-zero value enables half pixel precise motion compensated
+prediction. 
+
+.TP
+cross_B_search
+A non-zero value enables the fast Cross-B-Search algorithm to determine
+the motion vectors of an interpolated prediction. Otherwise,
+exhaustive search (in the given search range) is used. 
+
+.TP
+B_as_past_ref
+A non-zero value allows not only I- and P-frames but also B-frames to be
+used for a forward or bi-directional predicion.
+
+.TP
+mantissa, range
+Approximation coefficients are quantized to a small number of
+values (in fixed point format) in the interval [-\fIrange\fP,
++\fIrange\fP]. The number of \fImantissa\fP bits defines the accuracy of
+quantization.
+
+.TP
+dc_mantissa, dc_range
+Approximation coefficients of the DC component are quantized in a
+different way: the number of mantissa bits is given by
+\fIdc_mantissa\fP whereas the quantization interval is given by
+[-\fIdc_range\fP, +\fBdc_range\fP].
+
+.TP
+type
+This value sets the \fItype\fP of progress meter which should be used
+during coding. The following types are available:
+.fi
+\fBFIASCO_PROGRESS_NONE\fP:  no output at all
+.fi
+\fBFIASCO_PROGRESS_BAR\fP: print hash marks (###)
+\fBFIASCO_PROGRESS_PERCENT\fP: percentage meter (50%)
+
+.SH RETURN VALUES
+The function \fBfiasco_decoder_new()\fP returns a pointer to the newly
+allocated option object. If an error has been catched, a NULL pointer
+is returned.
+
+All set functions return 1 on success and 0 if an error has been
+catched.  
+
+In case of an error, use the function fiasco_get_error_message(3) to
+get a string with the last error message of FIASCO.
+
+.SH "SEE ALSO"
+.br
+.BR fiasco_decoder "(3), " fiasco_coder (3)
+
+Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger.
+\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on
+Selected Areas In Communications, January 1998
+.br
+Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted
+Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN
+3-89820-002-7, October 1999.
+
+.SH AUTHOR
+Ullrich Hafner <hafner@bigfoot.de>
diff --git a/converter/other/fiasco/doc/fiasco_options_set_4_2_0_format.3 b/converter/other/fiasco/doc/fiasco_options_set_4_2_0_format.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_4_2_0_format.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_basisfile.3 b/converter/other/fiasco/doc/fiasco_options_set_basisfile.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_basisfile.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_chroma_quality.3 b/converter/other/fiasco/doc/fiasco_options_set_chroma_quality.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_chroma_quality.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_frame_pattern.3 b/converter/other/fiasco/doc/fiasco_options_set_frame_pattern.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_frame_pattern.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_magnification.3 b/converter/other/fiasco/doc/fiasco_options_set_magnification.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_magnification.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_optimizations.3 b/converter/other/fiasco/doc/fiasco_options_set_optimizations.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_optimizations.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_prediction.3 b/converter/other/fiasco/doc/fiasco_options_set_prediction.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_prediction.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_progress_meter.3 b/converter/other/fiasco/doc/fiasco_options_set_progress_meter.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_progress_meter.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_quantization.3 b/converter/other/fiasco/doc/fiasco_options_set_quantization.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_quantization.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_smoothing.3 b/converter/other/fiasco/doc/fiasco_options_set_smoothing.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_smoothing.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_tiling.3 b/converter/other/fiasco/doc/fiasco_options_set_tiling.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_tiling.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_options_set_video_param.3 b/converter/other/fiasco/doc/fiasco_options_set_video_param.3
new file mode 100644
index 00000000..493fcce9
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_options_set_video_param.3
@@ -0,0 +1 @@
+.so man3/fiasco_options_new.3
diff --git a/converter/other/fiasco/doc/fiasco_renderer.3 b/converter/other/fiasco/doc/fiasco_renderer.3
new file mode 100644
index 00000000..0aec996e
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_renderer.3
@@ -0,0 +1 @@
+.so man3/fiasco_renderer_new.3
diff --git a/converter/other/fiasco/doc/fiasco_renderer_delete.3 b/converter/other/fiasco/doc/fiasco_renderer_delete.3
new file mode 100644
index 00000000..0aec996e
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_renderer_delete.3
@@ -0,0 +1 @@
+.so man3/fiasco_renderer_new.3
diff --git a/converter/other/fiasco/doc/fiasco_renderer_new.3 b/converter/other/fiasco/doc/fiasco_renderer_new.3
new file mode 100644
index 00000000..b24d8462
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_renderer_new.3
@@ -0,0 +1,125 @@
+.\" $Id: fiasco_renderer_new.3,v 1.2 2000/06/14 18:58:35 hafner Exp $
+.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec"
+
+.SH NAME
+.B  fiasco_renderer_new, fiasco_renderer_delete
+\- convert a FIASCO image object to an X11 XImage
+
+.SH SYNOPSIS
+.B #include <fiasco.h>
+.sp
+.BI "fiasco_renderer_t *"
+.fi
+.BI "fiasco_renderer_new (unsigned long "red_mask ,
+.fi
+.BI "                     unsigned long "green_mask ,
+.fi
+.BI "                     unsigned long "blue_mask ,
+.fi
+.BI "                     unsigned "bpp ,
+.fi
+.BI "                     int "double_resolution );
+.sp
+.BI "void"
+.fi
+.BI "fiasco_renderer_delete (fiasco_renderer_t * "renderer );
+.sp
+.BI "int"
+.fi
+.BI "fiasco_renderer_render (const fiasco_renderer_t * "renderer ,
+.fi
+.BI "                        unsigned char * "data );
+.fi
+.BI "                        const fiasco_image_t * "fiasco_image );
+.fi
+
+.SH DESCRIPTION
+The \fBfiasco_renderer_new()\fP function allocates and initializes a
+renderer object which has to be used to convert an internal FIASCO
+image object to one of the supported X11 formats. Currently, the FIASCO
+image can be rendered to an X11 XImage of either 16, 24, or 32 bits
+per pixel. Additional formats will be supported upon request.  
+
+Function \fBfiasco_renderer_render()\fP is used to convert the given
+FIASCO image object to the specified format. 
+
+After all frames are rendered, the function
+\fBfiasco_renderer_delete()\fP should be called to free temporarily
+allocated memory and to discard the renderer object.
+
+Note that the FIASCO renderer class is not restricted to X11 images: a
+FIASCO image object can be converted to an image data array of the
+form RGBRGB... by setting \fIred_mask\fP=0xff0000,
+\fIgreen_mask\fP=0xff00, \fIblue_mask\fP=0xff, and \fIbpp\fP=24.
+
+.SH ARGUMENTS
+
+.TP
+bpp
+Determines the number of bits of a single pixel of the X11 XImage
+structure (see XCreateImage(3)). If the XImage is already allocated
+then the value XImage->bits_per_pixel should be used. Currently, 16,
+24, and 32 bits per pixel are supported.
+
+.TP
+red_mask
+Determines which bits of a pixel should be used for the red
+component. If the XImage is already allocated then the value
+XImage->red_mask should be used. E.g., if \fIbpp=16\fP and
+\fIred_mask=0xf800\fP then each pixel is stored with two bytes. The
+red component uses bits 11-15, the remaining green and blue components
+use bits 0-10.
+
+.TP
+green_mask
+Determines which bits of a pixel should be used for the green
+component. If the XImage is already allocated then the value
+XImage->green_mask should be used.
+
+.TP
+blue_mask
+Determines which bits of a pixel should be used for the blue
+component. If the XImage is already allocated then the value
+XImage->blue_mask should be used.
+
+.TP
+data
+A pointer to the image data. If the XImage is already allocated then
+the value XImage->data should be used. This array has to be large
+enough to hold the decoded image at the given size (geometry and bits
+per pixel).
+
+.TP
+fiasco_image
+This object represents the decoded image which has been
+created by the FIASCO functions fiasco_decoder_get_frame(3) or
+fiasco_image_new(3).
+
+.SH RETURN VALUE
+The function \fBfiasco_renderer_new()\fP returns a pointer to the newly
+allocated renderer object. If an error has been catched, a NULL pointer
+is returned.
+
+The function \fBfiasco_renderer_render()\fP returns 1 if the image
+has been successfully converted. Otherwise, the function returns 0.
+
+In case of an error in one of the above functions, use the function
+fiasco_get_error_message(3) to get a string with the last error
+message of FIASCO.
+
+.SH "SEE ALSO"
+.br
+.BR fiasco_decoder_get_frame "(3), " fiasco_get_error_message (3)
+.BR fiasco_image_new (3)
+.br
+
+Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger.
+\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on
+Selected Areas In Communications, January 1998
+.br
+Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted
+Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN
+3-89820-002-7, October 1999.
+
+.SH AUTHOR
+Ullrich Hafner <hafner@bigfoot.de>
diff --git a/converter/other/fiasco/doc/fiasco_renderer_render.3 b/converter/other/fiasco/doc/fiasco_renderer_render.3
new file mode 100644
index 00000000..0aec996e
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_renderer_render.3
@@ -0,0 +1 @@
+.so man3/fiasco_renderer_new.3
diff --git a/converter/other/fiasco/doc/fiasco_set_verbosity.3 b/converter/other/fiasco/doc/fiasco_set_verbosity.3
new file mode 100644
index 00000000..746854b1
--- /dev/null
+++ b/converter/other/fiasco/doc/fiasco_set_verbosity.3
@@ -0,0 +1,46 @@
+.\" $Id: fiasco_set_verbosity.3,v 1.1 2000/06/06 20:55:05 hafner Exp $
+.TH fiasco 3 "April, 2000" "FIASCO" "Fractal Image And Sequence COdec"
+
+.SH NAME
+.B  fiasco_get_verbosity, fiasco_set_verbosity
+\- get or set verbosity of FIASCO library
+
+.SH SYNOPSIS
+.B #include <fiasco.h>
+.sp
+.BI "fiasco_verbosity_e"
+.fi
+.BI "fiasco_get_verbosity (void);"
+.sp
+.BI "void"
+.fi
+.BI "fiasco_set_verbosity (fiasco_verbosity_e "level );
+.fi
+
+.SH DESCRIPTION
+The \fBfiasco_get_verbosity()\fP function returns the current
+verbosity level of the FIASCO library. Conversely, the function
+\fBfiasco_set_verbosity()\fP sets the verbosity of the FIASCO library
+to the given \fIlevel\fP.
+
+.SH RETURN VALUE
+The function \fBfiasco_get_verbosity()\fP returns the current
+verbosity level. Level either is \fBFIASCO_NO_VERBOSITY\fP (no output at
+all), \fBFIASCO_SOME_VERBOSITY\fP (show progress meter) or
+\fBFIASCO_ULTIMATE_VERBOSITY\fP (show debugging output).
+
+.SH "SEE ALSO"
+.br
+.BR fiasco_coder (3), fiasco_decoder (3)
+.br
+
+Ullrich Hafner, Juergen Albert, Stefan Frank, and Michael Unger.
+\fBWeighted Finite Automata for Video Compression\fP, IEEE Journal on
+Selected Areas In Communications, January 1998
+.br
+Ullrich Hafner. \fBLow Bit-Rate Image and Video Coding with Weighted
+Finite Automata\fP, Ph.D. thesis, Mensch & Buch Verlag, ISBN
+3-89820-002-7, October 1999.
+
+.SH AUTHOR
+Ullrich Hafner <hafner@bigfoot.de>
diff --git a/converter/other/fiasco/fiasco.h b/converter/other/fiasco/fiasco.h
new file mode 100644
index 00000000..235b1279
--- /dev/null
+++ b/converter/other/fiasco/fiasco.h
@@ -0,0 +1,425 @@
+/*
+ *  fiasco.h		
+ *
+ *  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 <hafner@bigfoot.de>
+ *
+ *  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, USA.
+ */
+
+/*
+ *  $Date: 2000/10/28 17:39:28 $
+ *  $Author: hafner $
+ *  $Revision: 5.6 $
+ *  $State: Exp $
+ */
+
+#undef __BEGIN_DECLS
+#undef __END_DECLS
+#ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+#else
+# define __BEGIN_DECLS /* empty */
+# define __END_DECLS /* empty */
+#endif
+
+#ifndef _FIASCO_H
+#define _FIASCO_H 1
+
+__BEGIN_DECLS
+
+/****************************************************************************
+			  FIASCO data types
+****************************************************************************/
+
+/*
+ *  Verbosity level:
+ *  FIASCO_NO_VERBOSITY:       No output at all.
+ *  FIASCO_SOME_VERBOSITY:     Show progress meter during coding
+ *  FIASCO_ULTIMATE_VERBOSITY: Show debugging output
+ */
+typedef enum {FIASCO_NO_VERBOSITY,
+	      FIASCO_SOME_VERBOSITY,
+	      FIASCO_ULTIMATE_VERBOSITY} fiasco_verbosity_e;
+  
+/*
+ *  Image tiling methods:
+ *  VARIANCE_ASC:  Tiles are sorted by variance.
+ *                 The first tile has the lowest variance.
+ *  VARIANCE_DSC:  Tiles are sorted by variance.
+ *                 The first tile has the largest variance.
+ *  SPIRAL_ASC:    Tiles are sorted like a spiral starting
+ *                 in the middle of the image.
+ *  SPIRAL_DSC:    Tiles are sorted like a spiral starting
+ *                 in the upper left corner.
+ */
+typedef enum {FIASCO_TILING_SPIRAL_ASC,
+	      FIASCO_TILING_SPIRAL_DSC,
+	      FIASCO_TILING_VARIANCE_ASC,
+	      FIASCO_TILING_VARIANCE_DSC} fiasco_tiling_e;
+
+/*
+ *  Range of reduced precision format:
+ *  FIASCO_RPF_RANGE_0_75: use interval [-0.75,0.75]
+ *  FIASCO_RPF_RANGE_1_00: use interval [-1.00,1.00]
+ *  FIASCO_RPF_RANGE_1_50: use interval [-1.50,0.75]
+ *  FIASCO_RPF_RANGE_2_00: use interval [-2.00,2.00]
+ */
+typedef enum {FIASCO_RPF_RANGE_0_75,
+	      FIASCO_RPF_RANGE_1_00,
+	      FIASCO_RPF_RANGE_1_50,
+	      FIASCO_RPF_RANGE_2_00} fiasco_rpf_range_e;
+
+/*
+ *  Type of progress meter to be used during coding
+ *  FIASCO_PROGRESS_NONE:    no output at all
+ *  FIASCO_PROGRESS_BAR:     RPM style progress bar using 50 hash marks ###### 
+ *  FIASCO_PROGRESS_PERCENT: percentage meter 50% 
+ */
+typedef enum {FIASCO_PROGRESS_NONE,
+	      FIASCO_PROGRESS_BAR,
+	      FIASCO_PROGRESS_PERCENT} fiasco_progress_e;
+
+/*
+ * Class to encapsulate FIASCO images.
+ */
+typedef struct fiasco_image
+{
+   void		(*delete)	(struct fiasco_image *image);
+   unsigned	(*get_width)	(struct fiasco_image *image);
+   unsigned	(*get_height)	(struct fiasco_image *image);
+   int		(*is_color)	(struct fiasco_image *image);
+   void *private;
+} fiasco_image_t;
+
+/*
+ * Class to store internal state of decoder.
+ */
+typedef struct fiasco_decoder
+{
+   int			(*delete)	 (struct fiasco_decoder *decoder);
+   int			(*write_frame)   (struct fiasco_decoder *decoder,
+					  const char *filename);
+   fiasco_image_t *	(*get_frame)     (struct fiasco_decoder *decoder);
+   unsigned		(*get_length)    (struct fiasco_decoder *decoder);
+   unsigned		(*get_rate)	 (struct fiasco_decoder *decoder);
+   unsigned		(*get_width)	 (struct fiasco_decoder *decoder);
+   unsigned		(*get_height)	 (struct fiasco_decoder *decoder);
+   const char *		(*get_title)	 (struct fiasco_decoder *decoder);
+   const char *		(*get_comment)	 (struct fiasco_decoder *decoder);
+   int			(*is_color)	 (struct fiasco_decoder *decoder);
+   void *private;
+} fiasco_decoder_t;
+
+/*
+ * Class to encapsulate advanced coder options.
+ */
+typedef struct fiasco_c_options
+{
+   void (*delete)            (struct fiasco_c_options *options);
+   int (*set_tiling)         (struct fiasco_c_options *options,
+			      fiasco_tiling_e method,
+			      unsigned exponent);
+   int (*set_frame_pattern)  (struct fiasco_c_options *options,
+			      const char *pattern);
+   int (*set_basisfile)      (struct fiasco_c_options *options,
+			      const char *filename);
+   int (*set_chroma_quality) (struct fiasco_c_options *options,
+			      float quality_factor,
+			      unsigned dictionary_size);
+   int (*set_optimizations)  (struct fiasco_c_options *options,
+			      unsigned min_block_level,
+			      unsigned max_block_level,
+			      unsigned max_elements,
+			      unsigned dictionary_size,
+			      unsigned optimization_level);
+   int (*set_prediction)     (struct fiasco_c_options *options,
+			      int intra_prediction,
+			      unsigned min_block_level,
+			      unsigned max_block_level);
+   int (*set_video_param)    (struct fiasco_c_options *options,
+			      unsigned frames_per_second,
+			      int half_pixel_prediction,
+			      int cross_B_search,
+			      int B_as_past_ref);
+   int (*set_quantization)   (struct fiasco_c_options *options,
+			      unsigned mantissa,
+			      fiasco_rpf_range_e range,
+			      unsigned dc_mantissa,
+			      fiasco_rpf_range_e dc_range);
+   int (*set_progress_meter) (struct fiasco_c_options *options,
+			      fiasco_progress_e type);
+   int (*set_smoothing)      (struct fiasco_c_options *options,
+			      int smoothing);
+   int (*set_comment)        (struct fiasco_c_options *options,
+			      const char *comment);
+   int (*set_title)          (struct fiasco_c_options *options,
+			      const char *title);
+   void *private;
+} fiasco_c_options_t;
+
+/*
+ * Class to encapsulate advanced decoder options.
+ */
+typedef struct fiasco_d_options
+{
+   void (*delete)            (struct fiasco_d_options *options);
+   int (*set_smoothing)      (struct fiasco_d_options *options,
+			      int smoothing);
+   int (*set_magnification)  (struct fiasco_d_options *options,
+			      int level);
+   int (*set_4_2_0_format)   (struct fiasco_d_options *options,
+			      int format);
+   void *private;
+} fiasco_d_options_t;
+
+/*
+ * Class to convert internal FIASCO image structure to a XImage structure.
+ * Method `renderer()' is used to convert internal image to XImage. 
+ * Method `delete()' is used to delete and free internal image. 
+ */
+typedef struct fiasco_renderer
+{
+   int  (*render) (const struct fiasco_renderer *this,
+		   unsigned char *data,
+		   const fiasco_image_t *fiasco_image);
+   void (*delete) (struct fiasco_renderer *this);
+   void *private;
+} fiasco_renderer_t;
+
+/****************************************************************************
+		       miscellaneous functions
+****************************************************************************/
+  
+/* Get last error message of FIASCO library */
+const char *fiasco_get_error_message (void);
+
+/* Set verbosity of FIASCO library */
+void fiasco_set_verbosity (fiasco_verbosity_e level);
+
+/* Get verbosity of FIASCO library */
+fiasco_verbosity_e fiasco_get_verbosity (void);
+
+/****************************************************************************
+			  decoder functions
+****************************************************************************/
+
+/* Decode FIASCO image or sequence */
+fiasco_decoder_t *fiasco_decoder_new (const char *filename,
+				      const fiasco_d_options_t *options);
+
+/* Flush and discard FIASCO decoder */
+int fiasco_decoder_delete (fiasco_decoder_t *decoder);
+
+/* Decode next FIASCO frame and write to PNM image 'filename' */
+int fiasco_decoder_write_frame (fiasco_decoder_t *decoder,
+				const char *filename);
+
+/* Decode next FIASCO frame to FIASCO image structure */
+fiasco_image_t *fiasco_decoder_get_frame (fiasco_decoder_t *decoder);
+
+/* Get width of FIASCO image or sequence */
+unsigned fiasco_decoder_get_width (fiasco_decoder_t *decoder);
+
+/* Get height of FIASCO image or sequence */
+unsigned fiasco_decoder_get_height (fiasco_decoder_t *decoder);
+
+/* Get width of FIASCO image or sequence */
+int fiasco_decoder_is_color (fiasco_decoder_t *decoder);
+
+/* Get frame rate of FIASCO sequence */
+unsigned fiasco_decoder_get_rate (fiasco_decoder_t *decoder);
+
+/* Get number of frames of FIASCO file */
+unsigned fiasco_decoder_get_length (fiasco_decoder_t *decoder);
+
+/* Get title of FIASCO file */
+const char *
+fiasco_decoder_get_title (fiasco_decoder_t *decoder);
+
+/* Get comment of FIASCO file */
+const char *
+fiasco_decoder_get_comment (fiasco_decoder_t *decoder);
+
+/****************************************************************************
+			  image functions
+****************************************************************************/
+
+/* Read FIASCO image (raw ppm or pgm format) */
+fiasco_image_t * fiasco_image_new (const char *filename);
+
+/* Discard FIASCO image */
+void fiasco_image_delete (fiasco_image_t *image); 
+
+/* Get width of FIASCO image or sequence */
+unsigned fiasco_image_get_width (fiasco_image_t *image);
+
+/* Get height of FIASCO image or sequence */
+unsigned fiasco_image_get_height (fiasco_image_t *image);
+
+/* Get width of FIASCO image or sequence */
+int fiasco_image_is_color (fiasco_image_t *image);
+
+/****************************************************************************
+			  renderer functions
+****************************************************************************/
+
+/* Constructor of FIASCO image structure to a XImage renderer */
+fiasco_renderer_t *
+fiasco_renderer_new (unsigned long red_mask, unsigned long green_mask,
+		     unsigned long blue_mask, unsigned bpp,
+		     int double_resolution);
+
+/* Destructor of FIASCO image structure to a XImage renderer */
+void
+fiasco_renderer_delete (fiasco_renderer_t *renderer);
+
+/* FIASCO image structure to a XImage renderer */
+int
+fiasco_renderer_render (const fiasco_renderer_t *renderer,
+			unsigned char *ximage,
+			const fiasco_image_t *fiasco_image);
+
+/****************************************************************************
+			   coder functions
+****************************************************************************/
+
+/* Encode image or sequence by FIASCO */
+int fiasco_coder (char const * const *inputname,
+		  const char *outputname,
+		  float quality,
+		  const fiasco_c_options_t *options);
+
+/****************************************************************************
+		 coder options functions
+****************************************************************************/
+
+/* FIASCO additional options constructor */
+fiasco_c_options_t *fiasco_c_options_new (void);
+
+/* FIASCO additional options destructor */
+void fiasco_c_options_delete (fiasco_c_options_t *options);
+
+/* Define `smoothing'-percentage along partitioning borders.*/
+int fiasco_c_options_set_smoothing (fiasco_c_options_t *options,
+				    int smoothing);
+
+/* Set type of frame prediction for sequence of frames */
+int fiasco_c_options_set_frame_pattern (fiasco_c_options_t *options,
+					const char *pattern);
+
+/* Set method and number of tiles for image tiling */
+int fiasco_c_options_set_tiling (fiasco_c_options_t *options,
+				 fiasco_tiling_e method,
+				 unsigned exponent);
+
+/* Set FIASCO initial basis file */
+int fiasco_c_options_set_basisfile (fiasco_c_options_t *options,
+				    const char *filename);
+
+/* Set quality and dictionary size of chroma compression */
+int fiasco_c_options_set_chroma_quality (fiasco_c_options_t *options,
+					 float quality_factor,
+					 unsigned dictionary_size);
+
+/*
+ *  Since FIASCO internally works with binary trees, all functions
+ *  (which are handling image geometry) rather expect the `level' of
+ *  the corresponding binary tree than the traditional `width' and
+ *  `height' arguments.  Refer to following table to convert these
+ *  values:
+ *  
+ *  level | width | height
+ *  ------+-------+--------
+ *    0   |    1  |    1  
+ *    1   |    1  |    2  
+ *    2   |    2  |    2  
+ *    3   |    2  |    4  
+ *    4   |    4  |    4  
+ *    5   |    4  |    8  
+ *    6   |    8  |    8  
+ *    7   |    8  |   16
+ *
+ */
+   
+/* Set various optimization parameters. */
+int fiasco_c_options_set_optimizations (fiasco_c_options_t *options,
+					unsigned min_block_level,
+					unsigned max_block_level,
+					unsigned max_elements,
+					unsigned dictionary_size,
+					unsigned optimization_level);
+
+/* Set minimum and maximum size of image block prediction */
+int fiasco_c_options_set_prediction (fiasco_c_options_t *options,
+				     int intra_prediction,
+				     unsigned min_block_level,
+				     unsigned max_block_level);
+
+/*  Set various parameters used for video compensation */
+int fiasco_c_options_set_video_param (fiasco_c_options_t *options,
+				      unsigned frames_per_second,
+				      int half_pixel_prediction,
+				      int cross_B_search,
+				      int B_as_past_ref);
+
+/* Set accuracy of coefficients quantization */
+int fiasco_c_options_set_quantization (fiasco_c_options_t *options,
+				       unsigned mantissa,
+				       fiasco_rpf_range_e range,
+				       unsigned dc_mantissa,
+				       fiasco_rpf_range_e dc_range);
+
+/* Set type of progress meter */
+int fiasco_c_options_set_progress_meter (fiasco_c_options_t *options,
+					 fiasco_progress_e type);
+
+/*  Set comment of FIASCO stream */
+int fiasco_c_options_set_comment (fiasco_c_options_t *options,
+				  const char *comment);
+
+/*  Set title of FIASCO stream */
+int fiasco_c_options_set_title (fiasco_c_options_t *options,
+				const char *title);
+
+/****************************************************************************
+		 decoder options functions
+****************************************************************************/
+
+/* FIASCO additional options constructor */
+fiasco_d_options_t *fiasco_d_options_new (void);
+
+/* FIASCO additional options destructor */
+void fiasco_d_options_delete (fiasco_d_options_t *options);
+
+
+/* Define `smoothing'-percentage along partitioning borders.*/
+int fiasco_d_options_set_smoothing (fiasco_d_options_t *options,
+				  int smoothing);
+
+/* Set magnification-'level' of decoded image */
+int fiasco_d_options_set_magnification (fiasco_d_options_t *options,
+				      int level);
+
+/* Set image format to 4:2:0 or 4:4:4 */
+int fiasco_d_options_set_4_2_0_format (fiasco_d_options_t *options,
+				     int format);
+
+__END_DECLS
+
+#endif /* not _FIASCO_H */
diff --git a/converter/other/fiasco/fiascotopnm.c b/converter/other/fiasco/fiascotopnm.c
new file mode 100644
index 00000000..6d8b6f7f
--- /dev/null
+++ b/converter/other/fiasco/fiascotopnm.c
@@ -0,0 +1,477 @@
+/*
+ *  dwfa.c:     Decoding of WFA-files
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+ 
+/*
+ *  $Date: 2000/10/28 17:39:29 $
+ *  $Author: hafner $
+ *  $Revision: 5.7 $
+ *  $State: Exp $
+ */
+
+#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include "config.h"
+#include "pnm.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "types.h"
+#include "macros.h"
+
+#include <getopt.h>
+
+#include "binerror.h"
+#include "misc.h"
+#include "params.h"
+#include "fiasco.h"
+
+#ifndef X_DISPLAY_MISSING
+
+#   include "display.h"
+#   include "buttons.h"
+
+static x11_info_t *xinfo = NULL;
+
+#endif /* not X_DISPLAY_MISSING */
+
+/*****************************************************************************
+
+                prototypes
+  
+*****************************************************************************/
+
+static int 
+checkargs (int argc, char **argv, bool_t *double_resolution, bool_t *panel,
+           int *fps, char **image_name, fiasco_d_options_t **options);
+static void
+video_decoder (const char *wfa_name, const char *image_name, bool_t panel,
+               bool_t double_resolution, int fps, fiasco_d_options_t *options);
+static void
+get_output_template (const char *image_name, const char *wfa_name,
+                     bool_t color, char **basename, char **suffix);
+
+#ifndef X_DISPLAY_MISSING
+
+static void
+show_stored_frames (unsigned char * const *frame_buffer, int last_frame,
+                    x11_info_t *xinfo, binfo_t *binfo, size_t size,
+                    unsigned frame_time);
+
+#endif /* not X_DISPLAY_MISSING */
+
+/*****************************************************************************
+
+                public code
+  
+*****************************************************************************/
+
+int 
+main (int argc, char **argv)
+{
+    char               *image_name        = NULL; /* output filename */
+    bool_t              double_resolution = NO; /* double resolution of image */
+    bool_t              panel             = NO; /* control panel */
+    int             fps               = -1; /* frame display rate */
+    fiasco_d_options_t *options           = NULL; /* additional coder options */
+    int                 last_arg;    /* last processed cmdline parameter */
+
+    init_error_handling (argv[0]);
+
+    last_arg = checkargs (argc, argv, &double_resolution, &panel, &fps,
+                          &image_name, &options);
+   
+    if (last_arg >= argc)
+        video_decoder ("-", image_name, panel, double_resolution, fps, options);
+    else
+        while (last_arg++ < argc)
+            video_decoder (argv [last_arg - 1], image_name, panel,
+                           double_resolution, fps, options);
+
+    return 0;
+}
+
+/*****************************************************************************
+
+                private code
+  
+*****************************************************************************/
+
+static param_t params [] =
+{
+#ifdef X_DISPLAY_MISSING
+    {"output", "FILE", 'o', PSTR, {0}, "-",
+     "Write raw PNM frame(s) to `%s'."},
+#else  /* not X_DISPLAY_MISSING */
+    {"output", "FILE", 'o', POSTR, {0}, NULL,
+     "Write raw PNM frame(s) to INPUT.ppm/pgm [or `%s']."},
+#endif /* not X_DISPLAY_MISSING */
+    {"double", NULL, 'd', PFLAG, {0}, "FALSE",
+     "Interpolate images to double size before display."},
+    {"fast", NULL, 'r', PFLAG, {0}, "FALSE",
+     "Use 4:2:0 format for fast, low quality output."},
+    {"panel", NULL, 'p', PFLAG, {0}, "FALSE",
+     "Display control panel."},
+    {"magnify", "NUM", 'm', PINT, {0}, "0",
+     "Magnify/reduce image size by a factor of 4^`%s'."},
+    {"framerate", "NUM", 'F', PINT, {0}, "-1",
+     "Set display rate to `%s' frames per second."},
+    {"smoothing", "NUM", 's', PINT, {0}, "-1",
+     "Smooth image(s) by factor `%s' (0-100)"},
+    {NULL, NULL, 0, 0, {0}, NULL, NULL }
+};
+
+static int 
+checkargs (int argc, char **argv, bool_t *double_resolution, bool_t *panel,
+           int *fps, char **image_name, fiasco_d_options_t **options)
+/*
+ *  Check validness of command line parameters and of the parameter files.
+ *
+ *  Return value.
+ *  index in argv of the first argv-element that is not an option.
+ *
+ *  Side effects:
+ *  'double_resolution', 'panel', 'fps', 'image_name' and 'options'
+ *      are modified.
+ */
+{
+    int optind;              /* last processed commandline param */
+
+    optind = parseargs (params, argc, argv,
+#ifdef X_DISPLAY_MISSING
+                        "Decode FIASCO-FILEs and write frame(s) to disk.",
+#else  /* not X_DISPLAY_MISSING */
+                        "Decode and display FIASCO-FILEs using X11.",
+#endif /* not X_DISPLAY_MISSING */
+                        "With no FIASCO-FILE, or if FIASCO-FILE is -, "
+                        "read standard input.\n"
+#ifndef X_DISPLAY_MISSING
+                        "With --output=[FILE] specified, "
+                        "write frames without displaying them.\n\n"
+#endif  /* not X_DISPLAY_MISSING */
+                        "Environment:\n"
+                        "FIASCO_DATA   Search path for automata files. "
+                        "Default: ./\n"
+                        "FIASCO_IMAGES Save path for image files. "
+                        "Default: ./", " [FIASCO-FILE]...",
+                        FIASCO_SHARE, "system.fiascorc", ".fiascorc");
+
+    *image_name        =   (char *)   parameter_value (params, "output");
+    *double_resolution = *((bool_t *) parameter_value (params, "double"));
+    *panel             = *((bool_t *) parameter_value (params, "panel"));
+    *fps           = *((int *)    parameter_value (params, "framerate"));
+
+    /*
+     *  Additional options ... (have to be set with the fiasco_set_... methods)
+     */
+    *options = fiasco_d_options_new ();
+
+    {
+        int n = *((int *) parameter_value (params, "smoothing"));
+      
+        if (!fiasco_d_options_set_smoothing (*options, max (-1, n)))
+            error (fiasco_get_error_message ());
+    }
+
+    {
+        int 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"));
+      
+        if (!fiasco_d_options_set_4_2_0_format (*options, n > 0 ? YES : NO))
+            error (fiasco_get_error_message ());
+    }
+
+    return optind;
+}
+
+static void
+video_decoder (const char *wfa_name, const char *image_name, bool_t panel,
+               bool_t double_resolution, int fps, fiasco_d_options_t *options)
+{
+#ifndef X_DISPLAY_MISSING
+    fiasco_renderer_t  *renderer     = NULL;
+    unsigned char     **frame_buffer = NULL;
+    binfo_t            *binfo        = NULL; /* buttons info */
+#endif /* not X_DISPLAY_MISSING */
+   
+    do
+    {
+        unsigned      width, height, frames, n;
+        fiasco_decoder_t *decoder_state;
+        char             *filename;
+        char             *basename;   /* basename of decoded frame */
+        char             *suffix;     /* suffix of decoded frame */
+        unsigned      frame_time;
+      
+        if (!(decoder_state = fiasco_decoder_new (wfa_name, options)))
+            error (fiasco_get_error_message ());
+   
+        if (fps <= 0)         /* then use value of FIASCO file */ 
+            fps = fiasco_decoder_get_rate (decoder_state);
+        frame_time = fps ? (1000 / fps) : (1000 / 25);
+
+        if (!(width = fiasco_decoder_get_width (decoder_state)))
+            error (fiasco_get_error_message ());
+      
+        if (!(height = fiasco_decoder_get_height (decoder_state)))
+            error (fiasco_get_error_message ());
+
+        if (!(frames = fiasco_decoder_get_length (decoder_state)))
+            error (fiasco_get_error_message ());
+      
+        get_output_template (image_name, wfa_name,
+                             fiasco_decoder_is_color (decoder_state),
+                             &basename, &suffix);
+
+        filename = calloc (strlen (basename) + strlen (suffix) + 2
+                           + 10 + (int) (log10 (frames) + 1), sizeof (char));
+        if (!filename)
+            error ("Out of memory.");
+
+        for (n = 0; n < frames; n++)
+        {
+            clock_t fps_timer;     /* frames per second timer struct */
+     
+            prg_timer (&fps_timer, START);
+     
+            if (image_name)        /* just write frame to disk */
+            {
+                if (frames == 1)        /* just one image */
+                {
+                    if (streq (image_name, "-"))
+                        strcpy (filename, "-");
+                    else
+                        sprintf (filename, "%s.%s", basename, suffix);
+                }
+                else
+                {
+                    fprintf (stderr, "Decoding frame %d to file `%s.%0*d.%s\n",
+                             n, basename, (int) (log10 (frames - 1) + 1),
+                             n, suffix);
+                    sprintf (filename, "%s.%0*d.%s", basename,
+                             (int) (log10 (frames - 1) + 1), n, suffix);
+                }
+
+                if (!fiasco_decoder_write_frame (decoder_state, filename))
+                    error (fiasco_get_error_message ());
+            }
+#ifndef X_DISPLAY_MISSING
+            else
+            {
+                fiasco_image_t *frame;
+        
+                if (!(frame = fiasco_decoder_get_frame (decoder_state)))
+                    error (fiasco_get_error_message ());
+        
+                if (frames == 1)
+                    panel = NO;
+
+                if (xinfo == NULL)      /* initialize X11 window */
+                {
+                    const char * const title = 
+                        fiasco_decoder_get_title (decoder_state);
+                    char        titlename [MAXSTRLEN];
+
+           
+                    sprintf (titlename, "dfiasco " VERSION ": %s",
+                             strlen (title) > 0 ? title : wfa_name);
+                    xinfo = 
+                        open_window (titlename, "dfiasco",
+                                     (width  << (double_resolution ? 1 : 0)),
+                                     (height << (double_resolution ? 1 : 0))
+                                     + (panel ? 30 : 0));
+                    alloc_ximage (xinfo, width  << (double_resolution ? 1 : 0),
+                                  height << (double_resolution ? 1 : 0));
+                    if (panel)       /* initialize button panel */
+                        binfo = init_buttons (xinfo, n, frames, 30, 10);
+                    renderer = 
+                        fiasco_renderer_new (xinfo->ximage->red_mask,
+                                             xinfo->ximage->green_mask,
+                                             xinfo->ximage->blue_mask,
+                                             xinfo->ximage->bits_per_pixel,
+                                             double_resolution);
+                    if (!renderer)
+                        error (fiasco_get_error_message ());
+                }
+                renderer->render (renderer, xinfo->pixels, frame);
+                frame->delete (frame);
+        
+                if (frame_buffer != NULL) /* store next frame */
+                {
+                    size_t size = (width  << (double_resolution ? 1 : 0))
+                        * (height << (double_resolution ? 1 : 0))
+                        * (xinfo->ximage->depth <= 8
+                           ? sizeof (byte_t)
+                           : (xinfo->ximage->depth <= 16
+                              ? sizeof (u_word_t)
+                              : sizeof (unsigned int)));
+
+                    frame_buffer [n] = malloc (size);
+                    if (!frame_buffer [n])
+                        error ("Out of memory.");
+                    memcpy (frame_buffer [n], xinfo->pixels, size);
+
+                    if (n == frames - 1)
+                    {
+                        show_stored_frames (frame_buffer, frames - 1,
+                                            xinfo, binfo, size, frame_time);
+                        break;
+                    }
+                }
+
+                display_image (0, 0, xinfo);
+                if (frames == 1)
+                    wait_for_input (xinfo);
+                else if (panel)
+                {
+                    check_events (xinfo, binfo, n, frames);
+                    if (binfo->pressed [QUIT_BUTTON]) 
+                        /* start from beginning */
+                        break;
+                    if (binfo->pressed [STOP_BUTTON]) 
+                        /* start from beginning */
+                        n = frames;
+           
+                    if (binfo->pressed [RECORD_BUTTON] && frame_buffer == NULL)
+                    {
+                        n = frames;
+                        frame_buffer = 
+                            calloc (frames, sizeof (unsigned char *));
+                        if (!frame_buffer)
+                            error ("Out of memory.");
+                    }
+                }
+                while (prg_timer (&fps_timer, STOP) < frame_time) /* wait */
+                    ;
+            }
+#endif /* not X_DISPLAY_MISSING */   
+        }
+        free (filename);
+   
+        fiasco_decoder_delete (decoder_state);
+    } while (panel
+
+#ifndef X_DISPLAY_MISSING
+             && !binfo->pressed [QUIT_BUTTON]
+#endif /* not X_DISPLAY_MISSING */
+        
+        );
+
+#ifndef X_DISPLAY_MISSING
+    if (renderer)
+        renderer->delete (renderer);
+
+    if (!image_name)
+    {
+        close_window (xinfo);
+        free (xinfo);
+        xinfo = NULL;
+        if (binfo)
+            free (binfo);
+    }
+#endif /* not X_DISPLAY_MISSING */
+}
+
+static void
+get_output_template (const char *image_name, const char *wfa_name,
+                     bool_t color, char **basename, char **suffix)
+/*
+ *  Generate image filename template for output of image sequences.
+ *  'wfa_name' is the filename of the WFA stream.
+ *  Images are either saved with filename 'basename'.'suffix' (still images)
+ *  or 'basename'.%03d.'suffix' (videos).
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *  '*basename' and '*suffix' is set.
+ */
+{
+    if (!wfa_name || streq (wfa_name, "-"))
+        wfa_name = "stdin";       
+    /*
+     *  Generate filename template
+     */
+    if (!image_name || streq (image_name, "") || streq (image_name, "-"))
+    {
+        *basename = strdup (wfa_name);
+        *suffix   = NULL;
+    }
+    else
+    {
+        *basename = strdup (image_name);
+        *suffix   = strrchr (*basename, '.');
+    }
+    
+    if (*suffix)         /* found name 'basename.suffix' */
+    {
+        **suffix = 0;         /* remove dot */
+        (*suffix)++;
+        if (**suffix == 0)
+            *suffix = strdup (color ? "ppm" : "pgm");
+    }
+    else             /* no suffix found, generate one */
+        *suffix = strdup (color ? "ppm" : "pgm");
+}
+
+#ifndef X_DISPLAY_MISSING
+
+static void
+show_stored_frames (unsigned char * const *frame_buffer, int last_frame,
+                    x11_info_t *xinfo, binfo_t *binfo, size_t size,
+                    unsigned frame_time)
+/*
+ *  After a WFA video stream has been saved, all frames have been
+ *  decoded and stored in memory. These frames are then displayed
+ *  in an endless loop.
+ *
+ *  This function never returns, the program is terminated if the
+ *  STOP button is pressed.
+ */
+{
+    int n = last_frame;          /* frame number */
+   
+    while (1)
+    {
+        clock_t fps_timer;        /* frames per second timer struct */
+      
+        prg_timer (&fps_timer, START);
+      
+        display_image (0, 0, xinfo);
+        check_events (xinfo, binfo, n, last_frame + 1);
+
+        if (binfo->pressed [STOP_BUTTON])
+            n = 0;
+        else if (binfo->pressed [QUIT_BUTTON])
+            break;
+        else if (binfo->pressed [PLAY_BUTTON])
+            n++;
+        else if (binfo->pressed [RECORD_BUTTON]) /* REWIND is mapped RECORD */
+            n--;
+        if (n < 0)
+            n = last_frame;
+        if (n > last_frame)
+            n = 0;
+
+        memcpy (xinfo->pixels, frame_buffer [n], size);
+        while (prg_timer (&fps_timer, STOP) < frame_time) /* wait */
+            ;
+    };
+}
+
+#endif /* not X_DISPLAY_MISSING */
diff --git a/converter/other/fiasco/getopt.c b/converter/other/fiasco/getopt.c
new file mode 100644
index 00000000..0b2d1b75
--- /dev/null
+++ b/converter/other/fiasco/getopt.c
@@ -0,0 +1,1002 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
+   Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#include <unistd.h>
+#endif	/* GNU C library.  */
+
+#ifdef VMS
+#include <unixlib.h>
+#if HAVE_STRING_H - 0
+#include <string.h>
+#endif
+#endif
+
+#if defined (WIN32) && !defined (__CYGWIN32__)
+/* It's not Unix, really.  See?  Capital letters.  */
+#include <windows.h>
+#define getpid() GetCurrentProcessId()
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+   When compiling libc, the _ macro is predefined.  */
+#ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid)	gettext (msgid)
+#else
+# define _(msgid)	(msgid)
+#endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+static const char *nonoption_flags;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void store_args (int argc, char *const *argv) __attribute__ ((unused));
+static void
+store_args (int argc, char *const *argv)
+{
+  /* XXX This is no good solution.  We should rather copy the args so
+     that we can compare them later.  But we must not use malloc(3).  */
+  original_argc = argc;
+  original_argv = argv;
+}
+text_set_element (__libc_subinit, store_args);
+#endif
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined (__STDC__) && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined (__STDC__) && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind = 1;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#ifdef _LIBC
+  if (posixly_correct == NULL
+      && argc == original_argc && argv == original_argv)
+    {
+      /* Bash 2.0 puts a special variable in the environment for each
+	 command it runs, specifying which ARGV elements are the results of
+	 file name wildcard expansion and therefore should not be
+	 considered as options.  */
+      char var[100];
+      sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ());
+      nonoption_flags = getenv (var);
+      if (nonoption_flags == NULL)
+	nonoption_flags_len = 0;
+      else
+	nonoption_flags_len = strlen (nonoption_flags);
+    }
+  else
+    nonoption_flags_len = 0;
+#endif
+
+  return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  optarg = NULL;
+
+  if (!__getopt_initialized || optind == 0)
+    {
+      optstring = _getopt_initialize (argc, argv, optstring);
+      optind = 1;		/* Don't scan ARGV[0], the program name.  */
+      __getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \
+		     || (optind < nonoption_flags_len			      \
+			 && nonoption_flags[optind] == '1'))
+#else
+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+	 moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > optind)
+	last_nonopt = optind;
+      if (first_nonopt > optind)
+	first_nonopt = optind;
+
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc && NONOPTION_P)
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* The special ARGV-element `--' means premature end of options.
+	 Skip it like a null option,
+	 then exchange with previous non-options as if it were an option,
+	 then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+	 and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return -1;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+	 either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return -1;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+	 Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+	/* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+	 or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	if (!strncmp (p->name, nextchar, nameend - nextchar))
+	  {
+	    if ((unsigned int) (nameend - nextchar)
+		== (unsigned int) strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second or later nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*nameend)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+		 allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = nameend + 1;
+	      else
+		{
+            if (opterr) {
+		   if (argv[optind - 1][1] == '-')
+		    /* --option */
+		    fprintf (stderr,
+		     _("%s: option `--%s' doesn't allow an argument\n"),
+		     argv[0], pfound->name);
+		   else
+		    /* +option or -option */
+		    fprintf (stderr,
+		     _("%s: option `%c%s' doesn't allow an argument\n"),
+		     argv[0], argv[optind - 1][0], pfound->name);
+            }
+
+		  nextchar += strlen (nextchar);
+
+		  optopt = pfound->val;
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr,
+			   _("%s: option `%s' requires an argument\n"),
+			   argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  optopt = pfound->val;
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+	 or the option starts with '--' or is not a valid short
+	 option, then it's an error.
+	 Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+	    if (posixly_correct)
+	      /* 1003.2 specifies the format of this message.  */
+	      fprintf (stderr, _("%s: illegal option -- %c\n"),
+		       argv[0], c);
+	    else
+	      fprintf (stderr, _("%s: invalid option -- %c\n"),
+		       argv[0], c);
+	  }
+	optopt = c;
+	return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+	char *nameend;
+	const struct option *p;
+	const struct option *pfound = NULL;
+	int exact = 0;
+	int ambig = 0;
+	int indfound = 0;
+	int option_index;
+
+	/* This is an option that requires an argument.  */
+	if (*nextchar != '\0')
+	  {
+	    optarg = nextchar;
+	    /* If we end this ARGV-element by taking the rest as an arg,
+	       we must advance to the next element now.  */
+	    optind++;
+	  }
+	else if (optind == argc)
+	  {
+	    if (opterr)
+	      {
+		/* 1003.2 specifies the format of this message.  */
+		fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+			 argv[0], c);
+	      }
+	    optopt = c;
+	    if (optstring[0] == ':')
+	      c = ':';
+	    else
+	      c = '?';
+	    return c;
+	  }
+	else
+	  /* We already incremented `optind' once;
+	     increment it again when taking next ARGV-elt as argument.  */
+	  optarg = argv[optind++];
+
+	/* optarg is now the argument, see if it's in the
+	   table of longopts.  */
+
+	for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+	  /* Do nothing.  */ ;
+
+	/* Test all long options for either exact match
+	   or abbreviated matches.  */
+	for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	  if (!strncmp (p->name, nextchar, nameend - nextchar))
+	    {
+	      if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+		{
+		  /* Exact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		  exact = 1;
+		  break;
+		}
+	      else if (pfound == NULL)
+		{
+		  /* First nonexact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		}
+	      else
+		/* Second or later nonexact match found.  */
+		ambig = 1;
+	    }
+	if (ambig && !exact)
+	  {
+	    if (opterr)
+	      fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+		       argv[0], argv[optind]);
+	    nextchar += strlen (nextchar);
+	    optind++;
+	    return '?';
+	  }
+	if (pfound != NULL)
+	  {
+	    option_index = indfound;
+	    if (*nameend)
+	      {
+		/* Don't test has_arg with >, because some C compilers don't
+		   allow it to be used on enums.  */
+		if (pfound->has_arg)
+		  optarg = nameend + 1;
+		else
+		  {
+		    if (opterr)
+		      fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+			       argv[0], pfound->name);
+
+		    nextchar += strlen (nextchar);
+		    return '?';
+		  }
+	      }
+	    else if (pfound->has_arg == 1)
+	      {
+		if (optind < argc)
+		  optarg = argv[optind++];
+		else
+		  {
+		    if (opterr)
+		      fprintf (stderr,
+			       _("%s: option `%s' requires an argument\n"),
+			       argv[0], argv[optind - 1]);
+		    nextchar += strlen (nextchar);
+		    return optstring[0] == ':' ? ':' : '?';
+		  }
+	      }
+	    nextchar += strlen (nextchar);
+	    if (longind != NULL)
+	      *longind = option_index;
+	    if (pfound->flag)
+	      {
+		*(pfound->flag) = pfound->val;
+		return 0;
+	      }
+	    return pfound->val;
+	  }
+	  nextchar = NULL;
+	  return 'W';	/* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = NULL;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr,
+			   _("%s: option requires an argument -- %c\n"),
+			   argv[0], c);
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+		 increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif	/* Not ELIDE_CODE.  */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/converter/other/fiasco/getopt.h b/converter/other/fiasco/getopt.h
new file mode 100644
index 00000000..9acca708
--- /dev/null
+++ b/converter/other/fiasco/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+   Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument		(or 0) if the option does not take an argument,
+   required_argument	(or 1) if the option requires an argument,
+   optional_argument 	(or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+  const char *name;
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+		        const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind,
+			     int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/converter/other/fiasco/getopt1.c b/converter/other/fiasco/getopt1.c
new file mode 100644
index 00000000..8347bb13
--- /dev/null
+++ b/converter/other/fiasco/getopt1.c
@@ -0,0 +1,189 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef	NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif	/* Not ELIDE_CODE.  */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+	{"add", 1, 0, 0},
+	{"append", 0, 0, 0},
+	{"delete", 1, 0, 0},
+	{"verbose", 0, 0, 0},
+	{"create", 0, 0, 0},
+	{"file", 1, 0, 0},
+	{0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+		       long_options, &option_index);
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case 0:
+	  printf ("option %s", long_options[option_index].name);
+	  if (optarg)
+	    printf (" with arg %s", optarg);
+	  printf ("\n");
+	  break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case 'd':
+	  printf ("option d with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/converter/other/fiasco/input/Makefile b/converter/other/fiasco/input/Makefile
new file mode 100644
index 00000000..c01af772
--- /dev/null
+++ b/converter/other/fiasco/input/Makefile
@@ -0,0 +1,26 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../../..
+  BUILDDIR = $(SRCDIR)
+endif
+FIASCOSUBDIR = converter/other/fiasco
+SUBDIR = $(FIASCOSUBDIR)/input
+BUILDDIR = ../../../..
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+OBJECTS =  basis.o matrices.o mc.o nd.o read.o tree.o weights.o
+
+MERGE_OBJECTS = $(OBJECTS)
+
+INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \
+	   -I$(SRCDIR)/$(FIASCOSUBDIR)/codec
+
+all: libfiasco_input.a
+
+include $(SRCDIR)/Makefile.common
+
+libfiasco_input.a: $(OBJECTS)
+	$(AR) -rc $@ $(OBJECTS)
+	$(RANLIB) $@
+
diff --git a/converter/other/fiasco/input/basis.c b/converter/other/fiasco/input/basis.c
new file mode 100644
index 00000000..cef075e6
--- /dev/null
+++ b/converter/other/fiasco/input/basis.c
@@ -0,0 +1,141 @@
+/*
+ *  basis.c:		WFA initial basis files	
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/25 16:38:06 $
+ *  $Author: hafner $
+ *  $Revision: 5.3 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "wfalib.h"
+
+#include "basis.h"
+
+typedef struct basis_values
+{
+   unsigned  states;
+   real_t   *final;
+   bool_t   *use_domain;
+   real_t (*transitions)[4];
+} basis_values_t;
+
+typedef struct
+{
+    const char *filename;
+    void (*function)(basis_values_t *bv);
+} basis_file_t;
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+small_init (basis_values_t *bv);
+
+static basis_file_t const basis_files[] = { 
+    {"small.fco", small_init},
+    {"small.wfa", small_init},
+    {NULL, NULL} 
+};
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+bool_t
+get_linked_basis (const char *basis_name, wfa_t *wfa)
+/*
+ *  Check wether given WFA initial basis 'basis_name' is already linked
+ *  with the excecutable. If the basis is available then fill the 'wfa' struct
+ *  according to the stored data, otherwise print a warning message.
+ *
+ *  Return value:
+ *	true on success, false if basis is not available yet.
+ *
+ *  Side effects:
+ *	'wfa' struct is filled on success.
+ */
+{
+   bool_t	  success = NO;		/* indicates if basis is found */
+   unsigned	  n;			/* counter */
+   basis_values_t bv;			/* basis values */
+   
+   for (n = 0; basis_files [n].filename != NULL; n++)
+      if (streq (basis_files [n].filename, basis_name))	/* basis is stored */
+      {
+	 unsigned state, edge;		
+	 
+	 (*basis_files [n].function) (&bv); /* initialize local variables */
+	 /*
+	  *  Generate WFA
+	  */
+	 wfa->basis_states = wfa->states = bv.states + 1;
+	 wfa->domain_type[0]             = USE_DOMAIN_MASK; 
+	 wfa->final_distribution[0]      = 128;
+	 append_edge (0, 0, 1.0, 0, wfa);
+	 append_edge (0, 0, 1.0, 1, wfa);
+	 for (state = 1; state < wfa->basis_states; state++)
+	 {
+	    wfa->final_distribution [state] = bv.final [state - 1];
+	    wfa->domain_type [state]        = bv.use_domain [state - 1]
+					      ? USE_DOMAIN_MASK
+					      : AUXILIARY_MASK;
+	 }
+	 for (edge = 0; isedge (bv.transitions [edge][0]); edge++)
+	    append_edge (bv.transitions [edge][0], bv.transitions [edge][1],
+			 bv.transitions [edge][2], bv.transitions [edge][3],
+			 wfa);
+	 
+	 success = YES;
+	 break;
+      }
+
+   if (!success)
+      warning ("WFA initial basis '%s' isn't linked with the excecutable yet."
+	       "\nLoading basis from disk instead.", basis_name);
+
+   return success;
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+/*****************************************************************************
+				basis "small.wfa"
+*****************************************************************************/
+
+static unsigned	states_small           = 2;
+static bool_t	use_domain_small[]     = {YES, YES};
+static real_t 	final_small[]          = {64, 64};
+static real_t 	transitions_small[][4] = {{1, 2, 0.5, 0}, {1, 2, 0.5, 1},
+				      	 {1, 0, 0.5, 1}, {2, 1, 1.0, 0},
+				      	 {2, 1, 1.0, 1}, {-1, 0, 0, 0}};
+static void
+small_init (basis_values_t *bv)
+{
+   bv->states      = states_small;
+   bv->final       = final_small;
+   bv->use_domain  = use_domain_small;
+   bv->transitions = transitions_small;
+}
diff --git a/converter/other/fiasco/input/basis.h b/converter/other/fiasco/input/basis.h
new file mode 100644
index 00000000..fa26bca2
--- /dev/null
+++ b/converter/other/fiasco/input/basis.h
@@ -0,0 +1,26 @@
+/*
+ *  basis.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _BASIS_H
+#define _BASIS_H
+
+#include "wfa.h"
+
+bool_t
+get_linked_basis (const char *basis_name, wfa_t *wfa);
+
+#endif /* not _BASIS_H */
+
diff --git a/converter/other/fiasco/input/matrices.c b/converter/other/fiasco/input/matrices.c
new file mode 100644
index 00000000..47cde1aa
--- /dev/null
+++ b/converter/other/fiasco/input/matrices.c
@@ -0,0 +1,644 @@
+/*
+ *  matrices.c:		Input of transition matrices
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "bit-io.h"
+#include "arith.h"
+#include "misc.h"
+#include "wfalib.h"
+
+#include "matrices.h"
+
+#if STDC_HEADERS
+#	include <stdlib.h>
+#endif /* not STDC_HEADERS */
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static unsigned
+delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input);
+static unsigned
+column_0_decoding (wfa_t *wfa, unsigned last_row, bitfile_t *input);
+static unsigned
+chroma_decoding (wfa_t *wfa, bitfile_t *input);
+static void
+compute_y_state (int state, int y_state, wfa_t *wfa);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+unsigned
+read_matrices (wfa_t *wfa, bitfile_t *input)
+/* 
+ *  Read transitions of WFA given from the stream 'input'.
+ *
+ *  Return value:
+ *	number of edges
+ *
+ *  Side effects:
+ *	'wfa->into' is filled with decoded values 
+ */
+{
+   unsigned total;			/* total number of edges in the WFA */
+   unsigned root_state = wfa->wfainfo->color
+			 ? wfa->tree [wfa->tree [wfa->root_state][0]][0]
+			 : wfa->root_state;
+
+   total  = column_0_decoding (wfa, root_state, input);
+   total += delta_decoding (wfa, root_state, input);
+   if (wfa->wfainfo->color)
+      total += chroma_decoding (wfa, input);
+       
+   return total;
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static unsigned
+delta_decoding (wfa_t *wfa, unsigned last_domain, bitfile_t *input)
+/*
+ *  Read transition matrices which are encoded with delta coding
+ *  from stream 'input'.
+ *  'last_domain' is the maximum state number used as domain image.
+ *
+ *  Return value:
+ *	number of non-zero matrix elements (WFA edges)
+ *
+ *  Side effects:
+ *	'wfa->into' is filled with decoded values 
+ */
+{
+   range_sort_t	 rs;			/* ranges are sorted as in the coder */
+   unsigned	 max_domain;		/* dummy used for recursion */
+   unsigned	 range;
+   unsigned	 count [MAXEDGES + 1];
+   unsigned 	 state, label;
+   unsigned	*n_edges;		/* number of elements per row */
+   unsigned	 total = 0;		/* total number of decoded edges */
+
+   /*
+    *  Generate a list of range blocks.
+    *  The order is the same as in the coder.
+    */
+   rs.range_state      = Calloc ((last_domain + 1) * MAXLABELS,
+				 sizeof (u_word_t));
+   rs.range_label      = Calloc ((last_domain + 1) * MAXLABELS,
+				 sizeof (byte_t));
+   rs.range_max_domain = Calloc ((last_domain + 1) * MAXLABELS,
+				 sizeof (u_word_t));
+   rs.range_subdivided = Calloc ((last_domain + 1) * MAXLABELS,
+				 sizeof (bool_t));
+   rs.range_no	       = 0;
+   max_domain 	       = wfa->basis_states - 1;
+   sort_ranges (last_domain, &max_domain, &rs, wfa);
+
+   /*
+    *  Get row statistics
+    */
+   {
+      arith_t  *decoder;
+      model_t  *elements;
+      unsigned 	max_edges = read_rice_code (3, input);
+      
+      /*
+       *  Get the probability array of the number of edges distribution
+       *  and allocate the corresponding model.
+       */
+      {
+	 unsigned edge;
+	 
+	 for (edge = 0; edge <= max_edges; edge++)
+	    count [edge] = read_rice_code ((int) log2 (last_domain) - 2,
+					   input);
+	 elements = alloc_model (max_edges + 1, 0, 0, count);
+      }
+      
+      /*
+       *  Get number of elements per matrix row
+       */
+      {
+	 unsigned row;
+      
+	 n_edges = Calloc (wfa->states, sizeof (unsigned));
+	 decoder = alloc_decoder (input);
+	 for (row = range = 0; range < rs.range_no; range++)
+	    if (!rs.range_subdivided [range])
+	    {
+	       state = rs.range_state [range];
+	       label = rs.range_label [range];
+	       
+	       n_edges [row++]
+		  = decode_symbol (decoder, elements)
+		  - (isedge (wfa->into [state][label][0]) ? 1 : 0);
+	    }
+	 
+	 free_decoder (decoder);
+	 free_model (elements);
+      }
+   }
+   
+   /*
+    *  Get matrix elements
+    */
+   {
+      unsigned row;
+      u_word_t *mapping1           = Calloc (wfa->states, sizeof (word_t));
+      u_word_t *mapping_coder1     = Calloc (wfa->states, sizeof (word_t));
+      u_word_t *mapping2           = Calloc (wfa->states, sizeof (word_t));
+      u_word_t *mapping_coder2     = Calloc (wfa->states, sizeof (word_t));
+      bool_t	use_normal_domains = get_bit (input);
+      bool_t	use_delta_domains  = get_bit (input);
+	  
+      /*
+       *  Generate array of states which are admitted domains.
+       *  When coding intra frames 'mapping1' == 'mapping2' otherwise
+       *  'mapping1' is a list of 'normal' domains which are admitted for 
+       *             coding intra blocks
+       *  'mapping2' is a list of 'delta' domains which are admitted for
+       *             coding the motion compensated prediction error 
+       */
+      {
+	 unsigned n1, n2, state;
+	    
+	 for (n1 = n2 = state = 0; state < wfa->states; state++)
+	 {
+	    mapping1 [n1] = state;
+	    mapping_coder1 [state] = n1;
+	    if (usedomain (state, wfa)
+		&& (state < wfa->basis_states
+		    || use_delta_domains || !wfa->delta_state [state]))
+	       n1++;
+	    
+	    mapping2 [n2] = state;
+	    mapping_coder2 [state] = n2;
+	    if (usedomain (state, wfa)
+		&& (state < wfa->basis_states || use_normal_domains
+		    || wfa->delta_state [state]))
+	       n2++;
+	 }
+      }
+	 
+      for (row = 0, range = 0; range < rs.range_no; range++)
+	 if (!rs.range_subdivided [range])
+	 {
+	    u_word_t *mapping;
+	    u_word_t *mapping_coder;
+	    unsigned  max_value;
+	    unsigned  edge;
+	    unsigned  state = rs.range_state [range];
+	    unsigned  label = rs.range_label [range];
+	    unsigned  last  = 1;
+
+	    if (wfa->delta_state [state] ||
+		wfa->mv_tree [state][label].type != NONE)
+	    {
+	       mapping 	     = mapping2;
+	       mapping_coder = mapping_coder2;
+	    }
+	    else
+	    {
+	       mapping 	     = mapping1;
+	       mapping_coder = mapping_coder1;
+	    }
+	    max_value = mapping_coder [rs.range_max_domain [range]];
+	    for (edge = n_edges [row]; edge; edge--)
+	    {
+	       unsigned domain;
+
+	       if (max_value - last)
+		  domain = read_bin_code (max_value - last, input) + last;
+	       else
+		  domain = max_value;
+	       append_edge (state, mapping [domain], -1, label, wfa);
+	       last = domain + 1;
+	       total++;
+	    }
+	    row++;
+	 }
+      Free (mapping1);
+      Free (mapping_coder1);
+      Free (mapping2);
+      Free (mapping_coder2);
+   }
+      
+   Free (n_edges);
+   Free (rs.range_state);
+   Free (rs.range_label);
+   Free (rs.range_max_domain);
+   Free (rs.range_subdivided);
+
+   return total;
+}
+
+static unsigned
+column_0_decoding (wfa_t *wfa, unsigned last_row, bitfile_t *input)
+/*
+ *  Read column 0 of the transition matrices of the 'wfa' which are coded
+ *  with quasi arithmetic coding from stream 'input'.
+ *  All rows from 'wfa->basis_states' up to 'last_row' are decoded.
+ * 
+ *  Return value:
+ *	number of non-zero matrix elements (WFA edges)
+ *
+ *  Side effects:
+ *	'wfa->into' is filled with decoded values 
+ */
+{
+   unsigned  row;			/* current matrix row */
+   unsigned  total = 0;			/* total number of edges in col 0 */
+   unsigned *prob_ptr;			/* pointer to current probability */
+   unsigned *last;			/* pointer to minimum probability */
+   unsigned *first;			/* pointer to maximum probability */
+   unsigned *new_prob_ptr;		/* ptr to probability of last domain */
+   unsigned *prob;			/* probability array */
+   u_word_t  high;			/* Start of the current code range */
+   u_word_t  low;			/* End of the current code range */
+   u_word_t  code;			/* The present input code value */
+   word_t   *is_leaf;			/* pointer to the tree structure */
+
+   /*
+    *  Compute the asymmetric probability array
+    *  prob[] = { 1/2, 1/2, 1/4, 1/4, 1/4, 1/4,
+    *             1/8, ... , 1/16, ..., 1/(MAXPROB+1)}
+    */
+   {
+      unsigned n;
+      unsigned index;			/* probability index */
+      unsigned exp;			/* current exponent */
+      
+      prob = Calloc (1 << (MAX_PROB + 1), sizeof (unsigned));
+   
+      for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++)
+	 for (exp = 0; exp < 1U << n; exp++, index++)
+	    prob [index] = n;
+   }
+
+   first = prob_ptr = new_prob_ptr = prob;
+   last  = first + 1020;
+   
+   is_leaf = wfa->tree [wfa->basis_states]; /* use pointer arithmetics ... */
+
+   high = HIGH;				/* 1.0 */
+   low  = LOW;				/* 0.0 */
+   code = get_bits (input, 16);		
+
+   /*
+    *  Decode column 0 with a quasi arithmetic coder (QAC).
+    *  Advantage of this QAC with respect to a binary AC:
+    *  Instead of using time consuming multiplications and divisions
+    *  to compute the probability of the most probable symbol (MPS) and
+    *  the range of the interval, a table look up procedure linked
+    *  with a shift operation is used for both computations.
+    *
+    *  Loops and array accesses have been removed
+    *  to make real time decoding possible.
+    */
+   for (row = wfa->basis_states; row <= last_row; row++)
+   {
+      unsigned count;			/* value in the current interval */
+      
+      /*
+       *  Read label 0 element
+       */
+      if (isrange (*is_leaf++))		/* valid matrix index */
+      {
+	 count = high - ((high - low) >> *prob_ptr);
+	 if (code < count)
+	 {
+	    if (prob_ptr < last)	/* model update */
+	       prob_ptr++;
+	    /*
+	     *  Decode the MPS '0'
+	     */
+	    high = count - 1;
+
+	    RESCALE_INPUT_INTERVAL;
+	 }
+	 else
+	 {
+	    prob_ptr = ((prob_ptr - first) >> 1) + first; /* model update */
+	    /*
+	     *  Decode the LPS '1'
+	     */
+	    low = count;
+
+	    RESCALE_INPUT_INTERVAL;
+	    /*
+	     *  Restore the transition (weight = -1)
+	     */
+	    append_edge (row, 0, -1, 0, wfa);
+	    total++;
+	 }
+      }
+      /*
+       *  Read label 1 element
+       */
+      if (isrange (*is_leaf++)) /* valid matrix index */
+      {
+	 count = high - ((high - low) >> *prob_ptr);
+	 if (code < count)
+	 {
+	    if (prob_ptr < last)
+	       prob_ptr++;		/* model update */
+	    /*
+	     *  Decode the MPS '0'
+	     */
+	    high = count - 1;
+
+	    RESCALE_INPUT_INTERVAL;
+	 }
+	 else
+	 {
+	    prob_ptr = ((prob_ptr - first) >> 1) + first; /* model update */
+	    /*
+	     *  Decode the LPS '1'
+	     */
+	    low = count;
+
+	    RESCALE_INPUT_INTERVAL;
+	    /*
+	     *  Restore the transition (weight = -1)
+	     */
+	    append_edge (row, 0, -1, 1, wfa);
+	    total++;
+	 }
+      }
+   }
+
+   INPUT_BYTE_ALIGN (input);
+
+   Free (prob);
+   
+   return total;
+}
+
+static unsigned
+chroma_decoding (wfa_t *wfa, bitfile_t *input)
+/*
+ *  Read transition matrices of 'wfa' states which are part of the
+ *  chroma channels Cb and Cr from stream 'input'.
+ *
+ *  Return value:
+ *	number of non-zero matrix elements (WFA edges)
+ *
+ *  Side effects:
+ *	'wfa->into' is filled with decoded values 
+ */
+{
+   unsigned  domain;			/* current domain, counter */
+   unsigned  total = 0;			/* total number of chroma edges */
+   unsigned *prob_ptr;			/* pointer to current probability */
+   unsigned *last;			/* pointer to minimum probability */
+   unsigned *first;			/* pointer to maximum probability */
+   unsigned *new_prob_ptr;		/* ptr to probability of last domain */
+   unsigned *prob;			/* probability array */
+   u_word_t  high;			/* Start of the current code range */
+   u_word_t  low;			/* End of the current code range */
+   u_word_t  code;			/* The present input code value */
+   word_t   *y_domains;			/* domain images corresponding to Y */
+   int	     save_index;		/* YES: store current probabilty */
+
+   /*
+    *  Compute the asymmetric probability array
+    *  prob[] = { 1/2, 1/2, 1/4, 1/4, 1/4, 1/4,
+    *                     1/8, ... , 1/16, ..., 1/(MAXPROB+1)}
+    */
+   {
+      unsigned n;
+      unsigned index;			/* probability index */
+      unsigned exp;			/* current exponent */
+      
+      prob = Calloc (1 << (MAX_PROB + 1), sizeof (unsigned));
+   
+      for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++)
+	 for (exp = 0; exp < 1U << n; exp++, index++)
+	    prob [index] = n;
+   }
+
+   high = HIGH;				/* 1.0 */
+   low  = LOW;				/* 0.0 */
+   code = get_bits (input, 16);
+
+   /*
+    *  Compute list of admitted domains
+    */
+   y_domains = compute_hits (wfa->basis_states,
+			     wfa->tree [wfa->tree [wfa->root_state][0]][0],
+			     wfa->wfainfo->chroma_max_states, wfa);
+   
+   first = prob_ptr = new_prob_ptr = prob;
+   last  = first + 1020;
+
+   /*
+    *  First of all, read all matrix columns given in the list 'y_domains'
+    *  which note all admitted domains.
+    *  These matrix elements are stored with QAC (see column_0_decoding ()).
+    */
+   for (domain = 0; y_domains [domain] != -1; domain++)
+   {
+      unsigned 	row	= wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1;
+      word_t   *is_leaf = wfa->tree [row];
+
+      prob_ptr   = new_prob_ptr;
+      save_index = YES;
+
+      for (; row < wfa->states; row++)
+      {
+	 unsigned count;		/* value in the current interval */
+	 /*
+	  *  Read label 0 element
+	  */
+	 if (isrange (*is_leaf++)) 	/* valid matrix index */
+	 {
+	    count = high - ((high - low) >> *prob_ptr);
+	    if (code < count)
+	    {
+	       if (prob_ptr < last)
+		  prob_ptr++;
+	       /*
+		*  Decode the MPS '0'
+		*/
+	       high = count - 1;
+
+	       RESCALE_INPUT_INTERVAL;
+	    }
+	    else
+	    {
+	       prob_ptr = ((prob_ptr - first) >> 1) + first;
+	       /*
+		*  Decode the LPS '1'
+		*/
+	       low = count;
+
+	       RESCALE_INPUT_INTERVAL;
+	       /*
+		*  Restore the transition (weight = -1)
+		*/
+	       append_edge (row, y_domains [domain], -1, 0, wfa);
+	       total++;
+	    }
+	 }
+	 /*
+	  *  Read label 1 element
+	  */
+	 if (isrange (*is_leaf++)) /* valid matrix index */
+	 {
+	    count = high - ((high - low) >> *prob_ptr);
+	    if (code < count)
+	    {
+	       if (prob_ptr < last)
+		  prob_ptr++;
+	       /*
+		*  Decode the MPS '0'
+		*/
+	       high = count - 1;
+
+	       RESCALE_INPUT_INTERVAL;
+	    }
+	    else
+	    {
+	       prob_ptr = ((prob_ptr - first) >> 1) + first;
+	       /*
+		*  Decode the LPS '1'
+		*/
+	       low = count;
+
+	       RESCALE_INPUT_INTERVAL;
+	       /*
+		*  Restore the transition (weight = -1)
+		*/
+	       append_edge (row, y_domains [domain], -1, 1, wfa);
+	       total++;
+	    }
+	 }
+	 if (save_index)
+	 {
+	    save_index 	 = NO;
+	    new_prob_ptr = prob_ptr;
+	 }
+      }
+   }
+
+   Free (y_domains);
+
+   compute_y_state (wfa->tree [wfa->tree [wfa->root_state][0]][1],
+		    wfa->tree [wfa->tree [wfa->root_state][0]][0], wfa);
+   compute_y_state (wfa->tree [wfa->tree [wfa->root_state][1]][0],
+		    wfa->tree [wfa->tree [wfa->root_state][0]][0], wfa);
+   
+   first = prob_ptr = new_prob_ptr = prob;
+
+   /*
+    *  Decode the additional column which indicates whether there
+    *  are transitions to a state with same spatial coordinates
+    *  in the Y component.
+    *
+    *  Again, quasi arithmetic decoding is used for this task.
+    */
+   {
+      unsigned 	row;
+      
+      for (row = wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1;
+	   row < wfa->states; row++)
+      {
+	 int label;			/* current label */
+
+	 for (label = 0; label < MAXLABELS; label++)
+	 {
+	    u_word_t count = high - ((high - low) >> *prob_ptr);
+
+	    if (code < count)
+	    {
+	       if (prob_ptr < last)
+		  prob_ptr++;
+	       /*
+		*  Decode the MPS '0'
+		*/
+	       high = count - 1;
+
+	       RESCALE_INPUT_INTERVAL;
+	    }
+	    else
+	    {
+	       prob_ptr = ((prob_ptr - first) >> 1) + first;
+	       /*
+		*  Decode the LPS '1'
+		*/
+	       low = count;
+
+	       RESCALE_INPUT_INTERVAL;
+	       /*
+		*  Restore the transition (weight = -1)
+		*/
+	       append_edge (row, wfa->y_state [row][label], -1, label, wfa);
+	       total++;
+	    }
+	 }
+      }
+   }
+
+   INPUT_BYTE_ALIGN (input);
+
+   Free (prob);
+
+   return total;
+}
+
+static void
+compute_y_state (int state, int y_state, wfa_t *wfa)
+/*
+ *  Compute the 'wfa->y_state' array which denotes those states of
+ *  the Y band that have the same spatial coordinates as the corresponding
+ *  states of the Cb and Cr bands.
+ *  The current root of the Y tree is given by 'y_state'.
+ *  The current root of the tree of the chroma channel is given by 'state'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'wfa->y_state' is filled with the generated tree structure.
+ */
+{
+   unsigned label;
+   
+   for (label = 0; label < MAXLABELS; label++)
+      if (isrange (y_state))
+	 wfa->y_state [state][label] = RANGE;
+      else
+      {
+	 wfa->y_state [state][label] = wfa->tree [y_state][label];
+	 if (!isrange (wfa->tree [state][label]))
+	    compute_y_state (wfa->tree [state][label],
+			     wfa->y_state [state][label], wfa);
+      }
+      
+}
diff --git a/converter/other/fiasco/input/matrices.h b/converter/other/fiasco/input/matrices.h
new file mode 100644
index 00000000..ba8fd9bf
--- /dev/null
+++ b/converter/other/fiasco/input/matrices.h
@@ -0,0 +1,27 @@
+/*
+ *  matrices.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _MATRICES_H
+#define _MATRICES_H
+
+#include "wfa.h"
+#include "bit-io.h"
+
+unsigned
+read_matrices (wfa_t *wfa, bitfile_t *input);
+
+#endif /* not _MATRICES_H */
+
diff --git a/converter/other/fiasco/input/mc.c b/converter/other/fiasco/input/mc.c
new file mode 100644
index 00000000..070d839e
--- /dev/null
+++ b/converter/other/fiasco/input/mc.c
@@ -0,0 +1,334 @@
+/*
+ *  mc.c:	Input of motion compensation	
+ *
+ *  written by: Michael Unger
+ *		Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include <stdlib.h>
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "bit-io.h"
+#include "misc.h"
+#include "mvcode.h"
+
+#include "mc.h"
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+typedef struct huff_node 
+{
+   int		     code_index;	/* leaf if index >= 0 */
+   struct huff_node *left;		/* follow if '0' bit read */
+   struct huff_node *right;		/* follow if '1' bit read */
+   int		     index_set [34];
+} huff_node_t;
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+decode_mc_tree (frame_type_e frame_type, unsigned max_state,
+		wfa_t *wfa, bitfile_t *input);
+static void
+decode_mc_coords (unsigned max_state, wfa_t *wfa, bitfile_t *input);
+static int
+get_mv (int f_code, huff_node_t *hn, bitfile_t *input);
+static huff_node_t *
+create_huff_tree (void);
+static void
+create_huff_node (huff_node_t *hn, int bits_processed);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+read_mc (frame_type_e frame_type, wfa_t *wfa, bitfile_t *input)
+/*
+ *  Read motion compensation information of the 'input' stream.
+ *  Depending on 'frame_type' different decoding methods are used.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'wfa->mv_tree' is filled with the decoded values.
+ */
+{
+   unsigned max_state = wfa->wfainfo->color
+			? wfa->tree [wfa->tree [wfa->root_state][0]][0]
+			: wfa->states;
+
+   decode_mc_tree (frame_type, max_state, wfa, input);
+   decode_mc_coords (max_state, wfa, input);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+decode_mc_tree (frame_type_e frame_type, unsigned max_state,
+		wfa_t *wfa, bitfile_t *input)
+/*
+ *  Read tree of motion compensation decisions of the 'input' stream.
+ *  Depending on 'frame_type' different decoding methods are used.
+ *  'max_state' is the last state with motion compensation infos.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'wfa->mv_tree' is filled with decoded values.
+ */
+{
+   unsigned  state;			/* current state */
+   unsigned *queue;			/* states in breadth first order */
+   unsigned  last;			/* last node
+					   (update for each new node) */
+
+   /*
+    *  Traverse tree in breadth first order (starting at level
+    *  'wfa->wfainfo->p_max_level'). Use a queue to store the childs
+    *  of each node ('last' is the next free queue element).  
+    */
+   queue = Calloc (MAXSTATES, sizeof (unsigned));
+   for (last = 0, state = wfa->basis_states; state < max_state; state++)
+      if (wfa->level_of_state [state] - 1 == (int) wfa->wfainfo->p_max_level)
+	 queue [last++] = state;	/* init level 'p_max_level' */
+
+   if (frame_type == P_FRAME)
+   {
+      unsigned label;			/* current label */
+      unsigned current;			/* current node to process */
+      
+      for (current = 0; current < last; current++)
+	 for (label = 0; label < MAXLABELS; label++)
+	 {
+	    state = queue[current];
+	    if (wfa->x [state][label]	/* process visible states only */
+		+  width_of_level (wfa->level_of_state [state] - 1)
+		<= wfa->wfainfo->width
+		&&
+		wfa->y [state][label]
+		+  height_of_level (wfa->level_of_state [state] - 1)
+		<= wfa->wfainfo->height)
+	    {
+	       wfa->mv_tree [state][label].type
+		  = get_bit (input) ? NONE : FORWARD;
+	    }
+	    else
+	       wfa->mv_tree [state][label].type = NONE;
+	    if (wfa->mv_tree [state][label].type == NONE &&
+		!isrange (wfa->tree [state][label]) &&
+		wfa->level_of_state [state] - 1 >=
+		(int) wfa->wfainfo->p_min_level) 
+	       queue [last++] = wfa->tree [state][label]; /* append child  */
+	 }
+   }
+   else
+   {
+      unsigned label;			/* current label */
+      unsigned current;			/* current node to process */
+      
+      for (current = 0; current < last; current++)
+	 for (label = 0; label < MAXLABELS; label++)
+	 {
+	    state = queue[current];
+	    if (wfa->x [state][label]	/* process visible states only */
+		+ width_of_level (wfa->level_of_state [state] - 1)
+		> wfa->wfainfo->width
+		||
+		wfa->y [state][label]
+		+ height_of_level (wfa->level_of_state [state] - 1)
+		> wfa->wfainfo->height)
+	       wfa->mv_tree[state][label].type = NONE;
+	    else if (get_bit (input))	/* 1   */
+	       wfa->mv_tree[state][label].type = NONE;
+	    else if (get_bit (input))	/* 01  */
+	       wfa->mv_tree[state][label].type = INTERPOLATED;
+	    else if (get_bit (input))	/* 001 */ 
+	       wfa->mv_tree[state][label].type = BACKWARD;
+	    else			/* 000 */ 
+	       wfa->mv_tree[state][label].type = FORWARD;
+	    if (wfa->mv_tree[state][label].type == NONE &&
+		!isrange (wfa->tree[state][label]) &&
+		wfa->level_of_state[state] - 1
+		>= (int) wfa->wfainfo->p_min_level) 
+	       queue[last++] = wfa->tree[state][label]; /* append child  */
+	 }
+   }
+   
+   INPUT_BYTE_ALIGN (input);
+   Free (queue);
+}
+
+static void
+decode_mc_coords (unsigned max_state, wfa_t *wfa, bitfile_t *input)
+/*
+ *  Read motion vector coordinates of the 'input' stream. They are stored
+ *  with the static Huffman code of the MPEG and H.263 standards.
+ *  'max_state' is the last state with motion compensation infos.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'wfa->mv_tree' is filled with decoded values.
+ */
+{
+   unsigned	       label;		/* current label */
+   unsigned	       state;		/* current state */
+   mv_t		      *mv;		/* current motion vector */
+   static huff_node_t *huff_mv_root = NULL; /* root of huffman tree */
+ 
+   if (huff_mv_root == NULL)
+      huff_mv_root = create_huff_tree ();
+   
+   for (state = wfa->basis_states; state < max_state; state++)
+      for (label = 0; label < MAXLABELS; label++)
+      {
+	 mv = &wfa->mv_tree[state][label];
+	 switch (mv->type)
+	 {
+	    case NONE:
+	       break;
+	    case FORWARD:
+	       mv->fx = get_mv (1, huff_mv_root, input);
+	       mv->fy = get_mv (1, huff_mv_root, input);
+	       break;	    
+	    case BACKWARD:	    
+	       mv->bx = get_mv (1, huff_mv_root, input);
+	       mv->by = get_mv (1, huff_mv_root, input);
+	       break;	    
+	    case INTERPOLATED:   
+	       mv->fx = get_mv (1, huff_mv_root, input);
+	       mv->fy = get_mv (1, huff_mv_root, input);
+	       mv->bx = get_mv (1, huff_mv_root, input);
+	       mv->by = get_mv (1, huff_mv_root, input);
+	       break;
+	 }
+      }
+
+   INPUT_BYTE_ALIGN (input);
+}
+ 
+static int
+get_mv (int f_code, huff_node_t *hn, bitfile_t *input)
+/* 
+ *  Decode next motion vector component in bitstream 
+ *  by traversing the huffman tree.
+ */
+{
+   int vlc_code, vlc_code_magnitude, residual, diffvec;
+
+   while (hn->code_index < 0)
+   {
+      if (hn->code_index == -2)
+	 error ("wrong huffman code !");
+      if (get_bit (input))
+	 hn = hn->right;
+      else
+	 hn = hn->left;
+   }
+   vlc_code = hn->code_index - 16;
+   if (vlc_code == 0 || f_code == 1) 
+      return vlc_code;
+
+   vlc_code_magnitude = abs (vlc_code) - 1;
+   if (f_code <= 1)
+      residual = 0;
+   else
+      residual = get_bits (input, f_code - 1);
+   diffvec = (vlc_code_magnitude << (f_code - 1)) + residual + 1;
+   
+   return vlc_code > 0 ? diffvec : - diffvec;
+}
+
+static huff_node_t *
+create_huff_tree (void)
+/*
+ *  Construct huffman tree from code table
+ */
+{
+   unsigned	i;
+   huff_node_t *huff_root = Calloc (1, sizeof (huff_node_t));
+   
+   /*
+    *  The nodes' index set contains indices of all codewords that are
+    *  still decodable by traversing further down from the node.
+    *  (The root node has the full index set.)
+    */
+
+   for (i = 0; i < 33; i++)
+      huff_root->index_set [i] = i;
+   huff_root->index_set [i] = -1;	/* end marker */
+
+   create_huff_node (huff_root, 0);
+
+   return huff_root;
+}
+
+static void
+create_huff_node (huff_node_t *hn, int bits_processed)
+/*
+ *  Create one node in the huffman tree
+ */
+{
+   int lind = 0;			/* next index of left huff_node */
+   int rind = 0;			/* next index of right huff_node */
+   int code_len, i, ind;
+
+   hn->code_index = -1;
+   if (hn->index_set [0] < 0)		/* empty index set ? */
+   {
+      hn->code_index = -2;		/* error */
+      return;
+   }
+   hn->left  = Calloc (1, sizeof (huff_node_t));
+   hn->right = Calloc (1, sizeof (huff_node_t));
+
+   for (i = 0; (ind = hn->index_set[i]) >= 0; i++)
+   {
+      code_len = mv_code_table[ind][1];
+      if (code_len == bits_processed)	/* generate leaf */
+      {
+	 hn->code_index = ind;
+	 Free (hn->left); 
+	 Free (hn->right);
+	 return;
+      }
+      if (mv_code_table[ind][0] & (1 << (code_len - 1 - bits_processed)))
+	 hn->right->index_set[rind++] = ind;
+      else
+	 hn->left->index_set[lind++] = ind;
+   }
+   hn->right->index_set[rind] = -1;	/* set end markers */
+   hn->left->index_set[lind]  = -1;
+   create_huff_node (hn->left, bits_processed + 1);
+   create_huff_node (hn->right, bits_processed + 1);
+}
diff --git a/converter/other/fiasco/input/mc.h b/converter/other/fiasco/input/mc.h
new file mode 100644
index 00000000..1e14d287
--- /dev/null
+++ b/converter/other/fiasco/input/mc.h
@@ -0,0 +1,28 @@
+/*
+ *  mc.h
+ *
+ *  written by: Michael Unger
+ *		Ullrich Hafner
+ 
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _MC_H
+#define _MC_H
+
+#include "wfa.h"
+#include "bit-io.h"
+
+void
+read_mc (frame_type_e frame_type, wfa_t *wfa, bitfile_t *input);
+
+#endif /* not _MC_H */
+
diff --git a/converter/other/fiasco/input/nd.c b/converter/other/fiasco/input/nd.c
new file mode 100644
index 00000000..1a68bfbf
--- /dev/null
+++ b/converter/other/fiasco/input/nd.c
@@ -0,0 +1,237 @@
+/*
+ *  nd.c:		Input of prediction tree	
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "bit-io.h"
+#include "arith.h"
+#include "misc.h"
+#include "list.h"
+#include "wfalib.h"
+
+#include "nd.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+decode_nd_coefficients (unsigned total, wfa_t *wfa, bitfile_t *input);
+static unsigned
+decode_nd_tree (wfa_t *wfa, bitfile_t *input);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+read_nd (wfa_t *wfa, bitfile_t *input)
+/*
+ *  Read transitions of the nondetermistic 'wfa' part from 'input' stream.
+ *  ND is used only at levels {'wfa->p_min_level', ... , 'wfa->p_max_level'}.
+ *
+ *  Side effects:
+ *	'wfa->into' and 'wfa->weights' are filled with the decoded values
+ */
+{
+   unsigned total = decode_nd_tree (wfa, input);
+   
+   if (total > 0)
+      decode_nd_coefficients (total, wfa, input);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static unsigned
+decode_nd_tree (wfa_t *wfa, bitfile_t *input)
+/*
+ *  Read 'wfa' prediction tree of given 'input' stream.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'wfa->into' is filled with the decoded values
+ */
+{
+   lqueue_t *queue;			/* queue of states */
+   int       next, state;		/* state and its current child */
+   unsigned  total = 0;			/* total number of predicted states */
+   u_word_t  sum0, sum1;		/* Probability model */
+   u_word_t  code;			/* The present input code value */
+   u_word_t  low;			/* Start of the current code range */
+   u_word_t  high;			/* End of the current code range */
+
+   /*
+    *  Initialize arithmetic decoder
+    */
+   code = get_bits (input, 16);
+   low  = 0;
+   high = 0xffff;
+   sum0 = 1;
+   sum1 = 11;
+
+   queue = alloc_queue (sizeof (int));
+   state = wfa->root_state;
+   queue_append (queue, &state);
+
+   /*
+    *  Traverse the WFA tree in breadth first order (using a queue).
+    */
+   while (queue_remove (queue, &next))
+   {
+      unsigned label;
+
+      if (wfa->level_of_state [next] > wfa->wfainfo->p_max_level + 1) 
+      {
+	 /*
+	  *  Nondetermismn is not allowed at levels larger than
+	  *  'wfa->wfainfo->p_max_level'.
+	  */
+	 for (label = 0; label < MAXLABELS; label++)
+	    if (ischild (state = wfa->tree [next][label]))
+	       queue_append (queue, &state); /* continue with childs */
+      }
+      else if (wfa->level_of_state [next] > wfa->wfainfo->p_min_level)
+      {
+	 for (label = 0; label < MAXLABELS; label++)
+	    if (ischild (state = wfa->tree [next][label]))
+	    {
+	       unsigned count;		/* Current interval count */
+	       unsigned range;		/* Current interval range */
+	       
+	       count = (((code - low) + 1) * sum1 - 1) / ((high - low) + 1);
+	       if (count < sum0)
+	       {
+		  /*
+		   *  Decode a '0' symbol
+		   *  First, the range is expanded to account for the
+		   *  symbol removal.
+		   */
+		  range = (high - low) + 1;
+		  high = low + (u_word_t) ((range * sum0) / sum1 - 1 );
+		  RESCALE_INPUT_INTERVAL;
+		  /*
+		   *  Update the frequency counts
+		   */
+		  sum0++;
+		  sum1++;
+		  if (sum1 > 50) /* scale the symbol frequencies */
+		  {
+		     sum0 >>= 1;
+		     sum1 >>= 1;
+		     if (!sum0)
+			sum0 = 1;
+		     if (sum0 >= sum1)
+			sum1 = sum0 + 1;
+		  }
+		  if (wfa->level_of_state [state] > wfa->wfainfo->p_min_level)
+		     queue_append (queue, &state);
+	       }
+	       else
+	       {
+		  /*
+		   *  Decode a '1' symbol
+		   *  First, the range is expanded to account for the
+		   *  symbol removal.
+		   */
+		  range = (high - low) + 1;
+		  high = low + (u_word_t) ((range * sum1) / sum1 - 1);
+		  low  = low + (u_word_t) ((range * sum0) / sum1);
+		  RESCALE_INPUT_INTERVAL;
+		  /*
+		   *  Update the frequency counts
+		   */
+		  sum1++;
+		  if (sum1 > 50) /* scale the symbol frequencies */
+		  {
+		     sum0 >>= 1;
+		     sum1 >>= 1;
+		     if (!sum0)
+			sum0 = 1;
+		     if (sum0 >= sum1)
+			sum1 = sum0 + 1;
+		  }
+		  append_edge (next, 0, -1, label, wfa);
+		  total++;
+	       }
+	    }
+      }
+   }
+   free_queue (queue);
+
+   INPUT_BYTE_ALIGN (input);
+
+   return total;
+}
+
+static void
+decode_nd_coefficients (unsigned total, wfa_t *wfa, bitfile_t *input)
+/*
+ *  Read #'total' weights of nondeterministic part of 'wfa'  
+ *  of given 'input' stream.
+ *  'frame' gives the current frame number.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'wfa->weights' is filled with the decoded values.
+ */
+{
+   unsigned *coefficients;		/* array of factors to encode */
+   unsigned *ptr;			/* pointer to current factor */
+   
+   /*
+    *  Decode array of coefficients stored with arithmetic coding
+    */
+   {
+      const int	scaling  = 50;		/* scaling factor of prob. model */
+      unsigned  c_symbols = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1);
+      
+      ptr = coefficients = decode_array (input, NULL, &c_symbols, 1,
+					 total, scaling);
+   }
+   
+   /*
+    *  Fill 'wfa->weights' with decoded coefficients
+    */
+   {
+      unsigned state, label;
+      
+      for (state = wfa->basis_states; state < wfa->states; state++)
+	 for (label = 0; label < MAXLABELS; label++)
+	    if (ischild (wfa->tree [state][label])
+		&& isedge (wfa->into [state][label][0]))
+	    {
+	       wfa->weight [state][label][0] = btor (*ptr++,
+						     wfa->wfainfo->dc_rpf);
+	       wfa->int_weight [state][label][0]
+		  = wfa->weight [state][label][0] * 512 + 0.5;
+	    }
+   }
+   Free (coefficients);
+}
diff --git a/converter/other/fiasco/input/nd.h b/converter/other/fiasco/input/nd.h
new file mode 100644
index 00000000..2c2fff4b
--- /dev/null
+++ b/converter/other/fiasco/input/nd.h
@@ -0,0 +1,28 @@
+/*
+ *  nd.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _ND_H
+#define _ND_H
+
+#include "wfa.h"
+#include "rpf.h"
+#include "bit-io.h"
+
+void
+read_nd (wfa_t *wfa, bitfile_t *input);
+
+#endif /* not _ND_H */
+
diff --git a/converter/other/fiasco/input/read.c b/converter/other/fiasco/input/read.c
new file mode 100644
index 00000000..26bae7e4
--- /dev/null
+++ b/converter/other/fiasco/input/read.c
@@ -0,0 +1,499 @@
+/*
+ *  read.c:		Input of WFA files
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/07/18 15:44:58 $
+ *  $Author: hafner $
+ *  $Revision: 5.4 $
+ *  $State: Exp $
+ */
+
+#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <string.h>
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "misc.h"
+#include "rpf.h"
+#include "bit-io.h"
+#include "wfalib.h"
+
+#include "tree.h"
+#include "matrices.h"
+#include "weights.h"
+#include "nd.h"
+#include "mc.h"
+#include "basis.h"
+#include "read.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+read_tiling (tiling_t *tiling, unsigned image_width, unsigned image_height,
+	     unsigned image_level, bitfile_t *input);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+bitfile_t *
+open_wfa (const char *filename, wfa_info_t *wi)
+/*
+ *  Open WFA file 'filename' and read header information.
+ *
+ *  Return value:
+ *	Pointer to input stream (fileposition: first WFA frame)
+ *
+ *  Side effects:
+ *	The values of the header of 'filename' are copied to 'wfainfo'. 
+ *
+ */
+{
+   bitfile_t *input;			/* pointer to WFA bitfile */
+   
+   assert (filename && wi);
+   
+   wi->wfa_name = strdup (filename);
+
+   /*
+    *  Check whether 'filename' is a regular WFA file
+    */
+   {
+      unsigned 	n;
+      const char     *str;
+      
+      if (!(input = open_bitfile (filename, "FIASCO_DATA", READ_ACCESS)))
+          file_error (filename);
+   
+      for (str = FIASCO_MAGIC, n = strlen (FIASCO_MAGIC); n; n--)
+          if (get_bits (input, 8) != (unsigned) *str++)
+              error ("Input file %s is not a valid FIASCO file!", filename);
+      get_bits (input, 8);		/* fetch newline */
+   }
+   
+   /*
+    *  Read WFA header information
+    */
+   {
+      char	      basis_name [MAXSTRLEN]; /* temp. buffer */
+      const unsigned  rice_k = 8; 	/* parameter of Rice Code */
+      char     	     *str    = basis_name;
+      
+      while ((*str++ = get_bits (input, 8)) != 0
+	     && str < basis_name + MAXSTRLEN)
+	 ;
+      if (str == basis_name + MAXSTRLEN)
+	 error ("Input file %s is not a valid FIASCO file!", filename);
+      
+      {
+	 wi->release = read_rice_code (rice_k, input);
+
+	 if (wi->release > FIASCO_BINFILE_RELEASE)
+	    error ("Can't decode FIASCO files of file format release `%d'."
+		   "\nCurrent file format release is `%d'.", wi->release,
+		   FIASCO_BINFILE_RELEASE);
+      }
+
+      if (wi->release > 1)
+      {
+	 header_type_e type;
+	 
+	 while ((type = read_rice_code (rice_k, input)) != HEADER_END)
+	 {
+	    char     buffer [MAXSTRLEN];
+	    unsigned n = 0;
+	    
+	    switch (type)
+	    {
+	       case HEADER_TITLE:
+		  while ((buffer [n++] = get_bits (input, 8)))
+		     ;
+		  wi->title = strdup (buffer);
+		  break;
+	       case HEADER_COMMENT:
+		  while ((buffer [n++] = get_bits (input, 8)))
+		     ;
+		  wi->comment = strdup (buffer);
+		  break;
+	       default:			/* should not happen */
+		  break;
+	    }
+	 }
+      }
+
+      wi->basis_name = strdup (basis_name);
+      wi->max_states = read_rice_code (rice_k, input);
+      wi->color      = get_bit (input) ? YES : NO;
+      wi->width      = read_rice_code (rice_k, input);
+      wi->height     = read_rice_code (rice_k, input);
+
+      /*
+       *  Compute bintree level
+       */
+      {
+	 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->chroma_max_states = wi->color ? read_rice_code (rice_k, input) : -1;
+      wi->p_min_level       = read_rice_code (rice_k, input);
+      wi->p_max_level       = read_rice_code (rice_k, input);
+      wi->frames            = read_rice_code (rice_k, input);
+      wi->smoothing	    = read_rice_code (rice_k, input);
+
+      /*
+       *  Read RPF models from disk
+       */
+      {
+	 unsigned 	    mantissa;
+	 fiasco_rpf_range_e range;
+
+	 mantissa = get_bits (input, 3) + 2;
+	 range    = get_bits (input, 2);
+	 wi->rpf  = alloc_rpf (mantissa, range);
+	 
+	 if (get_bit (input))		/* different DC model */
+	 {
+	    mantissa   = get_bits (input, 3) + 2;
+	    range      = get_bits (input, 2);
+	    wi->dc_rpf = alloc_rpf (mantissa, range);
+	 }
+	 else				/* use same model for DC coefficents */
+	    wi->dc_rpf = alloc_rpf (wi->rpf->mantissa_bits,
+				    wi->rpf->range_e);
+
+	 if (get_bit (input))		/* different delta model */
+	 {
+	    mantissa  = get_bits (input, 3) + 2;
+	    range     = get_bits (input, 2);
+	    wi->d_rpf = alloc_rpf (mantissa, range);
+	 }
+	 else
+	    wi->d_rpf = alloc_rpf (wi->rpf->mantissa_bits,
+				   wi->rpf->range_e);
+	 
+	 if (get_bit (input))		/* different DC delta model */
+	 {
+	    mantissa  	 = get_bits (input, 3) + 2;
+	    range     	 = get_bits (input, 2);
+	    wi->d_dc_rpf = alloc_rpf (mantissa, range);
+	 }
+	 else
+	    wi->d_dc_rpf = alloc_rpf (wi->dc_rpf->mantissa_bits,
+				      wi->dc_rpf->range_e);
+      }
+
+      if (wi->frames > 1)		/* motion compensation stuff */
+      {
+	 wi->fps           = read_rice_code (rice_k, input);
+	 wi->search_range  = read_rice_code (rice_k, input);
+	 wi->half_pixel    = get_bit (input) ? YES : NO;
+	 wi->B_as_past_ref = get_bit (input) ? YES : NO;
+      }
+   }
+   
+   INPUT_BYTE_ALIGN (input);
+
+   return input;
+}
+
+void
+read_basis (const char *filename, wfa_t *wfa)
+/*
+ *  Read WFA initial basis 'filename' and fill 'wfa' struct.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	wfa->into, wfa->weights, wfa->final_distribution, wfa->basis_states
+ *	wfa->domain_type wfa->wfainfo->basis_name, are filled with the
+ *	values of the WFA basis.
+ */
+{
+   FILE	*input;				/* ASCII WFA initial basis file */
+
+   assert (filename && wfa);
+
+   if (!wfa->wfainfo->basis_name ||
+       !streq (wfa->wfainfo->basis_name, filename))
+   {
+      if (wfa->wfainfo->basis_name)
+	 Free (wfa->wfainfo->basis_name);
+      wfa->wfainfo->basis_name = strdup (filename);
+   }
+   
+   if (get_linked_basis (filename, wfa))
+      return;				/* basis is linked with excecutable */
+   
+   /*
+    *  Check whether 'wfa_name' is a regular ASCII WFA initial basis file
+    */
+   {
+      char magic [MAXSTRLEN];		/* WFA magic number */
+
+      if (!(input = open_file (filename, "FIASCO_DATA", READ_ACCESS)))
+	 file_error(filename);
+      
+      if (fscanf (input, MAXSTRLEN_SCANF, magic) != 1)
+	 error ("Format error: ASCII FIASCO initial basis file %s", filename);
+      else if (strneq (FIASCO_BASIS_MAGIC, magic))
+	 error ("Input file %s is not an ASCII FIASCO initial basis!",
+		filename);
+   }
+   
+   /*
+    *  WFA ASCII format:
+    *
+    *  Note: State 0 is assumed to be the constant function f(x, y) = 128.
+    *        Don't define any transitions of state 0 in an initial basis. 
+    *
+    *  Header:
+    *   type		|description
+    *	----------------+-----------
+    *   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)
+    *			|1: use vector in linear combinations
+    *	float-array[N]	|final distribution of every state
+    *
+    *  Transitions:
+    *
+    *      <state 1>			current state
+    *      <label> <into> <weight>	transition 1 of current state
+    *      <label> <into> <weight>	transition 2 of current state
+    *      ...
+    *      <-1>				last transition marker
+    *      <state 2>
+    *      ...
+    *      <-1>				last transition marker
+    *      <state N>
+    *      ...
+    *
+    *      <-1>				last transition marker
+    *      <-1>				last state marker
+    */
+   {
+      unsigned state;
+
+      if (fscanf (input ,"%u", &wfa->basis_states) != 1)
+	 error ("Format error: ASCII FIASCO initial basis file %s", filename);
+
+      /*
+       *  State 0 is assumed to be the constant function f(x, y) = 128.
+       */
+      wfa->domain_type [0]        = USE_DOMAIN_MASK; 
+      wfa->final_distribution [0] = 128;
+      wfa->states 		  = wfa->basis_states;
+      wfa->basis_states++;
+
+      append_edge (0, 0, 1.0, 0, wfa);
+      append_edge (0, 0, 1.0, 1, wfa);
+   
+      for (state = 1; state < wfa->basis_states; state++)
+	 wfa->domain_type [state]
+	    = read_int (input) ? USE_DOMAIN_MASK : AUXILIARY_MASK;
+
+      for (state = 1; state < wfa->basis_states; state++)
+	 wfa->final_distribution[state] = read_real (input);
+
+      /*
+       *  Read transitions
+       */
+      for (state = 1; state < wfa->basis_states; state++)
+      {
+	 unsigned domain;
+	 int      label;
+	 real_t   weight;
+
+	 if (read_int (input) != (int) state)
+	    error ("Format error: ASCII FIASCO initial basis file %s",
+		   filename);
+
+	 while((label = read_int (input)) != -1)
+	 {
+	    domain = read_int (input);
+	    weight = read_real (input);
+	    append_edge (state, domain, weight, label, wfa);
+	 }
+      }
+   }
+   
+   fclose (input);
+}
+
+unsigned
+read_next_wfa (wfa_t *wfa, bitfile_t *input)
+/*
+ *  Read next WFA frame of the WFA stream 'input'.
+ *  WFA header information has to be already present in the 'wfainfo' struct.
+ *  (i.e. open_wfa must be called first!)
+ *  
+ *  No return value.
+ *
+ *  Side effects:
+ *	wfa->into, wfa->weights, wfa->final_distribution, wfa->states
+ *	wfa->x, wfa->y, wfa->level_of_state, wfa->domain_type
+ *      mt->type, mt->number are filled with the values of the WFA file.
+ */
+{
+   tiling_t tiling;			/* tiling information */
+   unsigned frame_number;		/* current frame number */
+   
+   assert (wfa && input);
+   
+   /*
+    *  Frame header information
+    */
+   {
+      const unsigned rice_k = 8;	/* parameter of Rice Code */
+
+      wfa->states     = read_rice_code (rice_k, input);
+      wfa->frame_type = read_rice_code (rice_k, input);
+      frame_number    = read_rice_code (rice_k, input);
+   }
+
+   if (wfa->wfainfo->release > 1)	/* no alignment in version 1 */
+   {
+      INPUT_BYTE_ALIGN (input);
+   }
+   
+   /*
+    *  Read image tiling info 
+    */
+   if (get_bit (input))			/* tiling performed ? */
+      read_tiling (&tiling, wfa->wfainfo->width, wfa->wfainfo->height,
+		   wfa->wfainfo->level, input);
+   else
+      tiling.exponent = 0;
+   
+   INPUT_BYTE_ALIGN (input);
+
+   read_tree (wfa, &tiling, input);
+
+   /*
+    *  Compute domain pool.
+    *  Large images have not been used due to image tiling.
+    */
+   {
+      unsigned state;
+   
+      for (state = wfa->basis_states; state < wfa->states; state++)
+	 if ((!wfa->wfainfo->color
+	      || (int) state <= wfa->tree [wfa->tree [wfa->root_state][0]][0])
+	     &&
+	     (!tiling.exponent ||
+	      wfa->level_of_state [state] <= (wfa->wfainfo->level
+					      - tiling.exponent))
+	     && ((wfa->x [state][0]
+		 + width_of_level (wfa->level_of_state [state]))
+		 <= wfa->wfainfo->width)
+	     && ((wfa->y [state][0]
+		 + height_of_level (wfa->level_of_state [state]))
+		 <= wfa->wfainfo->height))
+	    wfa->domain_type [state] = USE_DOMAIN_MASK;
+	 else
+	    wfa->domain_type [state] = 0;
+   }
+   
+   if (tiling.exponent)
+      Free (tiling.vorder);
+
+   if (get_bit (input))			/* nondeterministic prediction used */
+      read_nd (wfa, input);
+
+   if (wfa->frame_type != I_FRAME)	/* motion compensation used */
+      read_mc (wfa->frame_type, wfa, input);
+
+   locate_delta_images (wfa);
+   
+   /*
+    *  Read linear combinations (coefficients and indices)
+    */
+   {
+      unsigned edges = read_matrices (wfa, input); 
+
+      if (edges)
+	 read_weights (edges, wfa, input);
+   }
+
+   /*
+    *  Compute final distribution of all states
+    */
+   {
+      unsigned state;
+   
+      for (state = wfa->basis_states; state <= wfa->states; state++)
+	 wfa->final_distribution[state]
+	    = compute_final_distribution (state, wfa);
+   }
+
+   return frame_number;
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+read_tiling (tiling_t *tiling, unsigned image_width, unsigned image_height,
+	     unsigned image_level, bitfile_t *input)
+/*
+ *  Read image tiling information from the given file 'input'
+ *  and store parameters in struct 'tiling'.
+ *  
+ *  No return value.
+ */
+{
+   const unsigned rice_k = 8;		/* parameter of Rice Code */
+   
+   tiling->exponent = read_rice_code (rice_k, input);
+   
+   if (get_bit (input))			/* variance order */
+   {
+      unsigned tile;			/* current image tile */
+      unsigned x0, y0;			/* NW corner of image tile */
+      unsigned width, height;		/* size of image tile */
+
+      tiling->vorder = Calloc (1 << tiling->exponent, sizeof (int));
+      for (tile = 0; tile <  1U << tiling->exponent; tile++)
+      {
+	 locate_subimage (image_level, image_level - tiling->exponent, tile,
+			  &x0, &y0, &width, &height);
+	 if (x0 < image_width && y0 < image_height) 
+	    tiling->vorder [tile] = get_bits (input, tiling->exponent);
+	 else
+	    tiling->vorder [tile] = -1;
+      }
+   }
+   else					/* spiral order */
+   {
+      tiling->vorder = Calloc (1 << tiling->exponent, sizeof (int));
+      compute_spiral (tiling->vorder, image_width, image_height,
+		      tiling->exponent, get_bit (input) ? YES : NO);
+   }
+}
diff --git a/converter/other/fiasco/input/read.h b/converter/other/fiasco/input/read.h
new file mode 100644
index 00000000..d0d0ee13
--- /dev/null
+++ b/converter/other/fiasco/input/read.h
@@ -0,0 +1,31 @@
+/*
+ *  read.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _READ_H
+#define _READ_H
+
+#include "wfa.h"
+#include "bit-io.h"
+
+bitfile_t *
+open_wfa (const char *filename, wfa_info_t *wfainfo);
+void
+read_basis (const char *filename, wfa_t *wfa);
+unsigned
+read_next_wfa (wfa_t *wfa, bitfile_t *input);
+
+#endif /* not _READ_H */
+
diff --git a/converter/other/fiasco/input/tree.c b/converter/other/fiasco/input/tree.c
new file mode 100644
index 00000000..e3e7117e
--- /dev/null
+++ b/converter/other/fiasco/input/tree.c
@@ -0,0 +1,303 @@
+/*
+ *  tree.c:		Input of bintree partitioning
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "bit-io.h"
+#include "arith.h"
+#include "misc.h"
+#include "wfalib.h"
+#include "tiling.h"
+
+#include "tree.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static unsigned
+restore_depth_first_order (unsigned src_state, unsigned level, unsigned x,
+			   unsigned y, unsigned *dst_state,
+			   word_t (*bfo_tree)[MAXLABELS],
+			   wfa_t *wfa, tiling_t *tiling);
+static void 
+decode_tree (bitfile_t *input, byte_t *data, unsigned n_data, unsigned scaling,
+	     u_word_t sum0, u_word_t sum1);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+read_tree (wfa_t *wfa, tiling_t *tiling, bitfile_t *input)
+/*
+ *  Read bintree partitioning of WFA from the 'input' stream.
+ *  'tiling' provides the information about image tiling, if applied.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'wfa->tree', 'wfa->x', 'wfa->y', 'wfa->level_of_state'
+ *      are filled with decoded values.
+ */
+{
+   byte_t *bitstring;			/* the encoded data */
+   word_t (*bfo_tree)[MAXLABELS];	/* node numbers in BFO */
+      
+   /*
+    *  Read WFA tree stored in breadth first order
+    */
+   {
+      unsigned total = (wfa->states - wfa->basis_states) * MAXLABELS;
+      unsigned scale = total / 20;
+
+      bitstring = Calloc (total, sizeof (byte_t));
+      decode_tree (input, bitstring, total, scale, 1, 11);
+   }
+   
+   /*
+    *  Generate tree using a breadth first traversal
+    */
+   {
+      unsigned 	next;			/* next free node number of the tree */
+      unsigned 	state;
+      unsigned 	label;
+      byte_t   *buffer = bitstring;	/* pointer to decoded data */
+      
+      bfo_tree = Calloc (wfa->states * MAXLABELS, sizeof (word_t));
+      for (state = 0, next = 1; state < next; state++)
+	 for (label = 0; label < MAXLABELS; label++)
+	    bfo_tree [state][label] = *buffer++ ? next++ : RANGE;
+   }
+
+   /*
+    *  Traverse tree and restore depth first order
+    */
+   {
+      unsigned dst_state = wfa->basis_states;
+
+      wfa->root_state
+	 = restore_depth_first_order (0, (wfa->wfainfo->level
+					  + (wfa->wfainfo->color ? 2 : 0)),
+				      0, 0, &dst_state, bfo_tree, wfa, tiling);
+   }
+
+   Free (bitstring);
+   Free (bfo_tree);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static unsigned
+restore_depth_first_order (unsigned src_state, unsigned level, unsigned x,
+			   unsigned y, unsigned *dst_state,
+			   word_t (*bfo_tree)[MAXLABELS],
+			   wfa_t *wfa, tiling_t *tiling)
+/*
+ *  Map state 'src_state' (breadth first order) 
+ *  to state '*dst_state' (depth first order)
+ *  Add a tree edge 'state' --> 'child' with label and weight 1.0
+ *  if required.
+ *  'x', 'y' give the coordinates of the current state in the 'color' image
+ *  of size 'image_level'. 'tiling' defines the image partitioning. 
+ *  
+ *  Return value:
+ *	new node number in depth first order
+ *
+ *  Side effects:
+ *	'wfa->tree', 'wfa->x', 'wfa->y', 'wfa->level_of_state'
+ *      are filled with decoded values.
+ */
+{
+   unsigned newx [MAXLABELS];		/* x coordinate of childs */
+   unsigned newy [MAXLABELS];		/* y coordinate of childs */
+   unsigned x0, y0;			/* NW corner of image tile */
+   unsigned width, height;		/* size of image tile */
+
+   /*
+    *  If tiling is performed then replace current coordinates
+    */
+   if (tiling->exponent && level == wfa->wfainfo->level - tiling->exponent)
+   {
+      unsigned tile;
+      
+      for (tile = 0; tile < 1U << tiling->exponent; tile++)
+      {
+	 locate_subimage (wfa->wfainfo->level, level, tile,
+			  &x0, &y0, &width, &height);
+	 if (x0 == x && y0 == y) /* matched ! */
+	 {
+	    locate_subimage (wfa->wfainfo->level, level, tiling->vorder[tile],
+			     &x, &y, &width, &height);
+	    break;
+	 }
+      }
+   }
+   /*
+    *  Coordinates of childs 0 and 1
+    */
+   if (wfa->wfainfo->color && level == wfa->wfainfo->level + 1)
+      newx[0] = newy[0] = newx[1] = newy[1] = 0;
+   else
+   {
+      newx[0] = x;
+      newy[0] = y;
+      newx[1] = level & 1 ? x : x + width_of_level (level - 1);
+      newy[1] = level & 1 ? y + height_of_level (level - 1) : y;
+   }
+   
+   /*
+    *  Remap node numbers
+    */
+   {
+      int      child [MAXLABELS];	/* childs of current node (state) */
+      int      domain;			/* current domain */
+      unsigned label;
+
+      for (label = 0; label < MAXLABELS; label++)
+	 if (!isrange (domain = bfo_tree [src_state][label]))
+	    child [label] = restore_depth_first_order (domain, level - 1,
+						       newx [label],
+						       newy [label], dst_state,
+						       bfo_tree, wfa, tiling);
+	 else
+	    child [label] = RANGE;
+
+      for (label = 0; label < MAXLABELS; label++)
+      {
+	 wfa->tree [*dst_state][label] = child [label];
+	 wfa->x [*dst_state][label]    = newx [label];
+	 wfa->y [*dst_state][label]    = newy [label];
+      }
+      wfa->level_of_state [*dst_state] = level;
+   }
+   
+   return (*dst_state)++;
+}	
+
+/****************************************************************************
+
+                 Binary adaptive arithmetic compression
+ 
+****************************************************************************/
+
+static void 
+decode_tree (bitfile_t *input, byte_t *data, unsigned n_data, unsigned scaling,
+	     u_word_t sum0, u_word_t sum1)
+/*
+ *  Decode bintree partitioning using adaptive binary arithmetic decoding.
+ *  'input'	input stream,
+ *  'data'	buffer for decoded szmbols,
+ *  'n_data'	number of symbols to decode,
+ *  'scaling'	rescale probability models if range > 'scaling'
+ *  'sum0'	initial totals of symbol '0'
+ *  'sum1'	initial totals of symbol '1'
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'data []' is filled with the decoded bitstring
+ */
+{
+   u_word_t code;			/* The present input code value */
+   u_word_t low;			/* Start of the current code range */
+   u_word_t high;			/* End of the current code range */
+   unsigned n;				/* Data counter */
+
+   assert (data);
+
+   code = get_bits (input, 16);
+   low  = 0;
+   high = 0xffff;
+
+   for (n = n_data; n; n--) 
+   {
+      unsigned count;			/* Current interval count */
+      unsigned range;			/* Current interval range */
+      
+      count = (((code - low) + 1) * sum1 - 1) / ((high - low) + 1);
+      if (count < sum0)
+      {
+	 /*
+	  *  Decode a '0' symbol
+	  *  First, the range is expanded to account for the symbol removal.
+	  */
+	 range = (high - low) + 1;
+	 high = low + (u_word_t) ((range * sum0) / sum1 - 1 );
+
+	 RESCALE_INPUT_INTERVAL;
+
+	 *data++ = 0;
+	 /*
+	  *  Update the frequency counts
+	  */
+	 sum0++;
+	 sum1++;
+	 if (sum1 > scaling) /* scale the symbol frequencies */
+	 {
+	    sum0 >>= 1;
+	    sum1 >>= 1;
+	    if (!sum0)
+	       sum0 = 1;
+	    if (sum0 >= sum1)
+	       sum1 = sum0 + 1;
+	 }
+
+      }
+      else
+      {
+	 /*
+	  *  Decode a '1' symbol
+	  *  First, the range is expanded to account for the symbol removal.
+	  */
+	 range = (high - low) + 1;
+	 high = low + (u_word_t) ((range * sum1) / sum1 - 1);
+	 low  = low + (u_word_t) ((range * sum0) / sum1);
+
+	 RESCALE_INPUT_INTERVAL;
+
+	 *data++ = 1;
+	 /*
+	  *  Update the frequency counts
+	  */
+	 sum1++;
+	 if (sum1 > scaling) /* scale the symbol frequencies */
+	 {
+	    sum0 >>= 1;
+	    sum1 >>= 1;
+	    if (!sum0)
+	       sum0 = 1;
+	    if (sum0 >= sum1)
+	       sum1 = sum0 + 1;
+	 }
+      }
+   }
+   INPUT_BYTE_ALIGN (input);
+}
+
+
diff --git a/converter/other/fiasco/input/tree.h b/converter/other/fiasco/input/tree.h
new file mode 100644
index 00000000..e4b5f2d8
--- /dev/null
+++ b/converter/other/fiasco/input/tree.h
@@ -0,0 +1,28 @@
+/*
+ *  tree.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _TREE_H
+#define _TREE_H
+
+#include "wfa.h"
+#include "bit-io.h"
+#include "tiling.h"
+
+void
+read_tree (wfa_t *wfa, tiling_t *tiling, bitfile_t *input);
+
+#endif /* not _TREE_H */
+
diff --git a/converter/other/fiasco/input/weights.c b/converter/other/fiasco/input/weights.c
new file mode 100644
index 00000000..55339980
--- /dev/null
+++ b/converter/other/fiasco/input/weights.c
@@ -0,0 +1,200 @@
+/*
+ *  weights.c:		Input of weights
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "bit-io.h"
+#include "arith.h"
+#include "rpf.h"
+#include "misc.h"
+
+#include "weights.h"
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+read_weights (unsigned total, wfa_t *wfa, bitfile_t *input)
+/*
+ *  Read #'total' weights from input stream 'input' and
+ *  update transitions of the WFA states with corresponding weights.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'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 */
+   
+   /*
+    *  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)
+    */
+   {
+      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;
+   
+      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;
+      if (d_min_level > d_max_level)
+	 d_max_level = d_min_level - 1;
+
+      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);
+
+      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;
+	       }
+   }
+
+   /*
+    *  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 */
+
+      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);
+      
+      weights_array = decode_array (input, level_array, c_symbols,
+				    offset4, total, scale);
+      Free (c_symbols);
+   }
+   Free (level_array);
+
+   /*
+    *  Update transitions with decoded weights
+    */
+   {
+      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;
+	       }
+   }
+   
+   Free (weights_array);
+}
+ 
diff --git a/converter/other/fiasco/input/weights.h b/converter/other/fiasco/input/weights.h
new file mode 100644
index 00000000..1e2285a9
--- /dev/null
+++ b/converter/other/fiasco/input/weights.h
@@ -0,0 +1,27 @@
+/*
+ *  weights.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:13 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _WEIGHTS_H
+#define _WEIGHTS_H
+
+#include "wfa.h"
+#include "bit-io.h"
+
+void
+read_weights (unsigned total, wfa_t *wfa, bitfile_t *input);
+
+#endif /* not _WEIGHTS_H */
+
diff --git a/converter/other/fiasco/lib/Makefile b/converter/other/fiasco/lib/Makefile
new file mode 100644
index 00000000..99d7c1d7
--- /dev/null
+++ b/converter/other/fiasco/lib/Makefile
@@ -0,0 +1,33 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../../..
+  BUILDDIR = $(SRCDIR)
+endif
+FIASCOSUBDIR = converter/other/fiasco
+SUBDIR = $(FIASCOSUBDIR)/lib
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+OBJECTS = \
+  arith.o \
+  bit-io.o \
+  dither.o \
+  error.o \
+  image.o \
+  list.o \
+  misc.o \
+  rpf.o \
+  mvcode.o \
+
+MERGE_OBJECTS = $(OBJECTS)
+
+INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR)
+
+all: libfiasco_lib.a
+
+include $(SRCDIR)/Makefile.common
+
+libfiasco_lib.a: $(OBJECTS)
+	$(AR) -rc $@ $(OBJECTS)
+	$(RANLIB) $@
+
diff --git a/converter/other/fiasco/lib/arith.c b/converter/other/fiasco/lib/arith.c
new file mode 100644
index 00000000..e3745bf7
--- /dev/null
+++ b/converter/other/fiasco/lib/arith.c
@@ -0,0 +1,708 @@
+/*
+ *  arith.c:		Adaptive arithmetic coding and decoding
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "bit-io.h"
+#include "misc.h"
+#include "arith.h"
+
+/******************************************************************************
+
+				public code
+  
+******************************************************************************/
+
+arith_t *
+alloc_encoder (bitfile_t *output)
+/*
+ *  Arithmetic coder constructor:
+ *  Initialize the arithmetic coder.
+ *  
+ *  Return value:
+ *	A pointer to the new coder structure
+ */
+{
+   arith_t *arith = Calloc (1, sizeof (arith_t));
+
+   assert (output);
+   
+   arith->low       = LOW;
+   arith->high      = HIGH;
+   arith->underflow = 0;
+   arith->file 	    = output;
+
+   return arith;
+}
+
+void
+free_encoder (arith_t *arith)
+/*
+ *  Arithmetic encoder destructor.
+ *  Flush the arithmetic coder. Append all remaining bits to the
+ *  output stream. Append zero bits to get the output file byte aligned.
+ *  
+ *  No return value.
+ */
+{
+   u_word_t   low;			/* start of the current code range  */
+   u_word_t   high;			/* end of the current code range    */
+   u_word_t   underflow;		/* number of underflow bits pending */
+   bitfile_t *output;
+   
+   assert (arith);
+
+   low       = arith->low;
+   high      = arith->high;
+   underflow = arith->underflow;
+   output    = arith->file;
+   
+   low = high;
+
+   RESCALE_OUTPUT_INTERVAL;
+
+   OUTPUT_BYTE_ALIGN (output);
+
+   Free (arith);
+}
+
+real_t
+encode_symbol (unsigned symbol, arith_t *arith, model_t *model)
+/*
+ *  Encode the given 'symbol' using the given probability '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
+ *  symbol counts are rescaled).
+ *  
+ *  Return value:
+ *	information content of the encoded symbol.
+ *
+ *  Side effects:
+ *	'model' is updated (probability distribution)
+ *	'arith' is updated (coder state)
+ */
+{
+   u_word_t   low_count;		/* lower bound of 'symbol' interval */
+   u_word_t   high_count;		/* upper bound of 'symbol' interval */
+   u_word_t   scale;			/* range of all 'm' symbol intervals */
+   unsigned   range;			/* range of current interval */
+   unsigned   index;			/* index of probability model */
+   u_word_t   low;			/* start of the current code range  */
+   u_word_t   high;			/* end of the current code range    */
+   u_word_t   underflow;		/* number of underflow bits pending */
+   bitfile_t *output;			/* output file */
+   
+   assert (model && arith);
+
+   /*
+    * Get interval values
+    */
+   low       = arith->low;
+   high      = arith->high;
+   underflow = arith->underflow;
+   output    = arith->file;
+
+   assert (high > low);
+   
+   if (model->order > 0)		/* order-'n' model*/
+   {
+      unsigned power;			/* multiplicator */
+      unsigned i;
+
+      /*
+       *  Compute index of the probability model to use.
+       *  See init_model() for more details.
+       */
+      power = 1;			/* multiplicator */
+      index = 0;			/* address of prob. model */
+	 
+      for (i = 0; i < model->order; i++) /* genarate a M-nary number */
+      {
+	 index += model->context [i] * power;	
+	 power *= model->symbols;
+      }
+
+      index *= model->symbols + 1;	/* we need space for M + 1 elements */
+
+      for (i = 0; i < model->order - 1; i++)
+	 model->context [i] = model->context [i + 1];
+      model->context [i] = symbol;
+   }
+   else
+      index = 0;
+
+   scale      = model->totals [index + model->symbols];
+   low_count  = model->totals [index + symbol];
+   high_count = model->totals [index + symbol + 1];
+
+   /*
+    *  Compute the new interval depending on the input 'symbol'.
+    */
+   range = (high - low) + 1;
+   high  = low + (u_word_t) ((range * high_count) / scale - 1);
+   low   = low + (u_word_t) ((range * low_count) / scale);
+   
+   RESCALE_OUTPUT_INTERVAL;
+   
+   if (model->scale > 0)		/* adaptive model */
+   {
+      unsigned i;
+
+      /*
+       *  Update probability model
+       */
+      for (i = symbol + 1; i <= model->symbols; i++)
+	 model->totals [index + i]++;
+      if (model->totals [index + model->symbols] > model->scale) /* scaling */
+      {
+	 for (i = 1; i <= model->symbols; i++)
+	 {
+	    model->totals [index + i] >>= 1;
+	    if (model->totals [index + i] <= model->totals [index + i - 1])
+	       model->totals [index + i] = model->totals [index + i - 1] + 1;
+	 }
+      }
+   }
+
+   /*
+    *  Store interval values
+    */
+   arith->low  	    = low;
+   arith->high 	    = high;
+   arith->underflow = underflow;
+   
+   return - log2 ((high_count - low_count) / (real_t) scale);
+}
+
+void
+encode_array (bitfile_t *output, const unsigned *data, const unsigned *context,
+	      const unsigned *c_symbols, unsigned n_context, unsigned n_data,
+	      unsigned scaling)
+/*
+ *  Arithmetic coding of #'n_data' symbols given in the array 'data'.
+ *  If 'n_context' > 1 then a number (context [n]) is assigned to every
+ *  data element n, specifying which context (i.e. number of symbols given by
+ *  c_symbols [context [n]] and adaptive probability model) must be used.
+ *  Rescale probability models if range > 'scaling'.
+ *
+ *  No return value.
+ */
+{
+   u_word_t **totals;			/* probability model */
+
+   if (!n_context)
+      n_context = 1;			/* always use one context */
+
+   assert (output && c_symbols && data);
+   assert (n_context == 1 || context);
+   
+   /*
+    *  Allocate probability models, start with uniform distribution
+    */
+   totals = Calloc (n_context, sizeof (u_word_t *));
+   {
+      unsigned c;
+      
+      for (c = 0; c < n_context; c++)
+      {
+	 unsigned i;
+      
+	 totals [c]    = Calloc (c_symbols [c] + 1, sizeof (u_word_t));
+	 totals [c][0] = 0;
+      
+	 for (i = 0; i < c_symbols [c]; i++)
+	    totals [c][i + 1] = totals [c][i] + 1;
+      }
+   }
+
+   /*
+    *  Encode array elements
+    */
+   {
+      u_word_t low  	 = 0;		/* Start of the current code range */
+      u_word_t high 	 = 0xffff;	/* End of the current code range */
+      u_word_t underflow = 0;		/* Number of underflow bits pending */
+      unsigned n;
+      
+      for (n = 0; n < n_data; n++)
+      {
+	 u_word_t low_count;		/* lower bound of 'symbol' interval */
+	 u_word_t high_count;		/* upper bound of 'symbol' interval */
+	 u_word_t scale;		/* range of all 'm' symbol intervals */
+	 unsigned range;		/* current range */
+	 int	  d;			/* current data symbol */
+	 int	  c;			/* context of current data symbol */
+
+	 d = data [n];
+	 c = n_context > 1 ? context [n] : 0; 
+      
+	 scale	    = totals [c][c_symbols [c]];
+	 low_count  = totals [c][d];
+	 high_count = totals [c][d + 1];
+
+	 /*
+	  * Rescale high and low for the new symbol.
+	  */
+	 range = (high - low) + 1;
+	 high  = low + (u_word_t) ((range * high_count) / scale - 1);
+	 low   = low + (u_word_t) ((range * low_count) / scale);
+	 RESCALE_OUTPUT_INTERVAL;
+      
+	 /*
+	  *  Update probability models
+	  */
+	 {
+	    unsigned i;
+
+	    for (i = d + 1; i < c_symbols [c] + 1; i++)
+	       totals [c][i]++;
+	 
+	    if (totals [c][c_symbols [c]] > scaling) /* scaling */
+	       for (i = 1; i < c_symbols [c] + 1; i++)
+	       {
+		  totals [c][i] >>= 1;
+		  if (totals [c][i] <= totals [c][i - 1])
+		     totals [c][i] = totals [c][i - 1] + 1;
+	       }
+	 }
+      }
+      /*
+       *  Flush arithmetic encoder
+       */
+      low = high;
+      RESCALE_OUTPUT_INTERVAL;
+      OUTPUT_BYTE_ALIGN (output);
+   }
+   
+   /*
+    *  Cleanup ...
+    */
+   {
+      unsigned c;
+      for (c = 0; c < n_context; c++)
+	 Free (totals [c]);
+      Free (totals);
+   }
+}
+
+arith_t *
+alloc_decoder (bitfile_t *input)
+/*
+ *  Arithmetic decoder constructor:
+ *  Initialize the arithmetic decoder with the first
+ *  16 input bits from the stream 'input'.
+ *  
+ *  Return value:
+ *	A pointer to the new decoder structure
+ */
+
+{
+   arith_t *arith = Calloc (1, sizeof (arith_t));
+   
+   assert (input);
+   
+   arith->low  = LOW;
+   arith->high = HIGH;
+   arith->code = get_bits (input, 16);
+   arith->file = input;
+
+   return arith;
+}
+
+void
+free_decoder (arith_t *arith)
+/*
+ *  Arithmetic decoder destructor:
+ *  Flush the arithmetic decoder, i.e., read bits to get the input
+ *  file byte aligned. 
+ *  
+ *  No return value.
+ *
+ *  Side effects:
+ *	structure 'arith' is discarded.
+ */
+{
+   assert (arith);
+
+   INPUT_BYTE_ALIGN (arith->file);
+
+   Free (arith);
+}
+
+unsigned
+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).
+ *  
+ *  Return value:
+ *	decoded symbol
+ *
+ *  Side effects:
+ *	'model' is updated (probability distribution)
+ *	'arith' is updated (decoder state)
+ */
+{
+   unsigned   range;			/* range of current interval */
+   unsigned   count;			/* value in the current interval */
+   unsigned   index;			/* index of probability model */
+   unsigned   symbol;			/* decoded symbol */
+   u_word_t   scale;			/* range of all 'm' symbol intervals */
+   u_word_t   low;			/* start of the current code range  */
+   u_word_t   high;			/* end of the current code range    */
+   u_word_t   code;			/* the present input code value */
+   bitfile_t *input;			/* input file */
+
+   assert (arith && model);
+   
+   /*
+    * Get interval values
+    */
+   low   = arith->low;
+   high  = arith->high;
+   code  = arith->code;
+   input = arith->file;
+
+   assert (high > low);
+   
+   if (model->order > 0)		/* order-'n' model */
+   {
+      unsigned power;			/* multiplicator */
+      unsigned i;
+      
+      /*
+       *  Compute index of the probability model to use.
+       *  See init_model() for more details.
+       */
+      power = 1;			/* multiplicator */
+      index = 0;			/* address of prob. model */
+	 
+      for (i = 0; i < model->order; i++) /* genarate a m-nary number */
+      {
+	 index += model->context[i] * power;	
+	 power *= model->symbols;
+      }
+
+      index *= model->symbols + 1;	/* we need space for m + 1 elements */
+   }
+   else
+      index = 0;
+
+   scale = model->totals [index + model->symbols];
+   range = (high - low) + 1;
+   count = ((code - low + 1) * scale - 1) / range;
+
+   for (symbol = model->symbols; count < model->totals [index + symbol];
+	symbol--)
+      ;
+
+   if (model->order > 0)		/* order-'n' model */
+   {
+      unsigned i;
+      
+      for (i = 0; i < model->order - 1; i++)
+	 model->context [i] = model->context [i + 1];
+      model->context [i] = symbol;
+   }
+
+   /*
+    *  Compute interval boundaries
+    */
+   {
+      u_word_t low_count;		/* lower bound of 'symbol' interval */
+      u_word_t high_count;		/* upper bound of 'symbol' interval */
+      
+      low_count  = model->totals [index + symbol];
+      high_count = model->totals [index + symbol + 1];
+      high       = low + (u_word_t) ((range * high_count) / scale - 1 );
+      low        = low + (u_word_t) ((range * low_count) / scale );
+   }
+   
+   RESCALE_INPUT_INTERVAL;
+   
+   if (model->scale > 0)		/* adaptive model */
+   {
+      unsigned i;
+
+      /*
+       *  Update probability model
+       */
+      for (i = symbol + 1; i <= model->symbols; i++)
+	 model->totals [index + i]++;
+      if (model->totals [index + model->symbols] > model->scale) /* scaling */
+      {
+	 for (i = 1; i <= model->symbols; i++)
+	 {
+	    model->totals [index + i] >>= 1;
+	    if (model->totals [index + i] <= model->totals [index + i - 1])
+	       model->totals [index + i] = model->totals [index + i - 1] + 1;
+	 }
+      }
+   }
+   
+   /*
+    *  Store interval values
+    */
+   arith->low  = low;
+   arith->high = high;
+   arith->code = code;
+
+   return symbol;
+}
+
+unsigned *
+decode_array (bitfile_t *input, const unsigned *context,
+	      const unsigned *c_symbols, unsigned n_context,
+	      unsigned n_data, unsigned scaling)
+/*
+ *  Arithmetic decoding of #'n_data' symbols.
+ *  If 'n_context' > 1 then a number (context [n]) is assigned to every
+ *  data element n, specifying which context (i.e. number of symbols given by
+ *  c_symbols [context [n]] and adaptive probability model) must be used.
+ *  Rescale probability models if range > 'scaling'.
+ *
+ *  Return value:
+ *	pointer to array containing the decoded symbols
+ */
+{
+   unsigned  *data;			/* array to store decoded symbols */
+   u_word_t **totals;			/* probability model */
+   
+   if (n_context < 1)
+      n_context = 1;			/* always use one context */
+   assert (input && c_symbols);
+   assert (n_context == 1 || context);
+
+   data = Calloc (n_data, sizeof (unsigned));
+   
+   /*
+    *  Allocate probability models, start with uniform distribution
+    */
+   totals = Calloc (n_context, sizeof (u_word_t *));
+   {
+      unsigned c;
+      
+      for (c = 0; c < n_context; c++)
+      {
+	 unsigned i;
+      
+	 totals [c]    = Calloc (c_symbols [c] + 1, sizeof (u_word_t));
+	 totals [c][0] = 0;
+      
+	 for (i = 0; i < c_symbols [c]; i++)
+	    totals [c][i + 1] = totals [c][i] + 1;
+      }
+   }
+
+   /*
+    *  Fill array 'data' with decoded values
+    */
+   {
+      u_word_t code = get_bits (input, 16); /* The present input code value */
+      u_word_t low  = 0;		/* Start of the current code range */
+      u_word_t high = 0xffff;		/* End of the current code range */
+      unsigned n;
+      
+      for (n = 0; n < n_data; n++) 
+      {
+	 u_word_t scale;		/* range of all 'm' symbol intervals */
+	 u_word_t low_count;		/* lower bound of 'symbol' interval */
+	 u_word_t high_count;		/* upper bound of 'symbol' interval */
+	 unsigned count;		/* value in the current interval */
+	 unsigned range;		/* current interval range */
+	 unsigned d;			/* current data symbol */
+	 unsigned c;			/* context of current data symbol */
+
+	 c = n_context > 1 ? context [n] : 0; 
+
+	 assert (high > low);
+	 scale = totals [c][c_symbols [c]];
+	 range = (high - low) + 1;
+	 count = (((code - low) + 1 ) * scale - 1) / range;
+      
+	 for (d = c_symbols [c]; count < totals [c][d]; d--) /* next symbol */
+	    ;
+	 low_count  = totals [c][d];
+	 high_count = totals [c][d + 1];
+
+	 high = low + (u_word_t) ((range * high_count) / scale - 1 );
+	 low  = low + (u_word_t) ((range * low_count) / scale );
+	 RESCALE_INPUT_INTERVAL;
+
+	 /*
+	  *  Updata probability models
+	  */
+	 {
+	    unsigned i;
+
+	    for (i = d + 1; i < c_symbols [c] + 1; i++)
+	       totals [c][i]++;
+	 
+	    if (totals [c][c_symbols [c]] > scaling) /* scaling */
+	       for (i = 1; i < c_symbols [c] + 1; i++)
+	       {
+		  totals [c][i] >>= 1;
+		  if (totals [c][i] <= totals [c][i - 1])
+		     totals [c][i] = totals [c][i - 1] + 1;
+	       }
+	 }
+	 data [n] = d;
+      }
+      INPUT_BYTE_ALIGN (input);
+   }
+
+   /*
+    *  Cleanup ...
+    */
+   {
+      unsigned c;
+      
+      for (c = 0; c < n_context; c++)
+	 Free (totals [c]);
+      Free (totals);
+   }
+   
+   return data;
+}
+
+model_t *
+alloc_model (unsigned m, unsigned scale, unsigned n, unsigned *totals)
+/*
+ *  Model constructor:
+ *  allocate and initialize an order-'n' probability model.
+ *  The size of the source alphabet is 'm'. Rescale the symbol counts after
+ *  'scale' symbols are encoded/decoded. The initial probability of every
+ *  symbol is 1/m.
+ *  If 'scale' = 0 then use static modeling (p = 1/n).
+ *  If 'totals' is not NULL then use this array of 'm' values to set
+ *  the initial counts.
+ *
+ *  Return value:
+ *	a pointer to the new probability model structure.
+ *  
+ *  Note: We recommend a small size of the alphabet because no escape codes
+ *  are used to encode/decode previously unseen symbols.
+ *  
+ */
+{
+   model_t  *model;			/* new probability model */
+   unsigned  num;			/* number of contexts to allocate */
+   bool_t    cont;			/* continue flag */
+   bool_t    dec;			/* next order flag */
+   unsigned  i;
+
+   /*
+    *  Allocate memory for the structure
+    */
+   model          = Calloc (1, sizeof (model_t));
+   model->symbols = m;
+   model->scale   = scale;
+   model->order   = n;
+   model->context = n > 0 ? Calloc (n, sizeof (unsigned)) : NULL;
+   /*
+    *  Allocate memory for the probabilty model.
+    *  Each of the m^n different contexts requires its own probability model.
+    */
+   for (num = 1, i = 0; i < model->order; i++)
+      num *= model->symbols;
+
+   model->totals = Calloc (num * (model->symbols + 1), sizeof (unsigned));
+
+   for (i = 0; i < model->order; i++)
+      model->context[i] = 0;		/* start with context 0,0, .. ,0 */
+   cont = YES;
+   while (cont)				/* repeat while context != M ... M */
+   {
+      int	power;			/* multiplicator */
+      int	index;			/* index of probability model */
+      /*
+       *  There are m^n different contexts:
+       *  Let "context_1 context_2 ... context_n symbol" be the current input
+       *  stream then the index of the probability model is given by:
+       *  index = context_1 * M^0 + context_2 * M^1 + ... + context_n * M^(n-1)
+       */
+      power = 1;			/* multiplicator */
+      index = 0;			/* address of prob. model */
+	 
+      for (i = 0; i < model->order; i++)	/* genarate a m-nary number */
+      {
+	 index += model->context[i] * power;	
+	 power *= model->symbols;
+      }
+
+      index *= model->symbols + 1;	/* size of each model is m + 1 */
+
+      model->totals [index + 0] = 0;	/* always zero */
+	 
+      for (i = 1; i <= model->symbols; i++) /* prob of each symbol is 1/m or
+					       as given in totals */
+	 model->totals[index + i] = model->totals [index + i - 1]
+				    + (totals ? totals [i - 1] : 1);
+
+      if (model->order == 0)		/* order-0 model */
+	 cont = NO;
+      else				/* try next context */
+	 for (i = model->order - 1, dec = YES; dec; i--)
+	 {
+	    dec = NO;
+	    model->context[i]++;
+	    if (model->context[i] >= model->symbols) 
+	    {
+	       /* change previous context */
+	       model->context[i] = 0;
+	       if (i > 0)		/* there's still a context remaining */
+		  dec = YES;
+	       else
+		  cont = NO;		/* all context models initilized */
+	    }
+	 }
+   }
+   for (i = 0; i < model->order; i++)
+      model->context[i] = 0;		/* start with context 0,0, .. ,0 */
+
+   return model;
+}
+
+void
+free_model (model_t *model)
+/*
+ *  Model destructor:
+ *  Free memory allocated by the arithmetic 'model'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	struct 'model' is discarded
+ */
+{
+   if (model != NULL)
+   {
+      if (model->context != NULL)
+	 Free (model->context);
+      Free (model->totals);
+      Free (model);
+   }
+   else
+      warning ("Can't free model <NULL>.");
+}
diff --git a/converter/other/fiasco/lib/arith.h b/converter/other/fiasco/lib/arith.h
new file mode 100644
index 00000000..744eb9d7
--- /dev/null
+++ b/converter/other/fiasco/lib/arith.h
@@ -0,0 +1,122 @@
+/*
+ *  arith.h
+ *
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _ARITH_H
+#define _ARITH_H
+
+#include "types.h"
+#include "bit-io.h"
+
+typedef struct model
+{
+   unsigned  symbols;			/* number of symbols in the alphabet */
+   unsigned  scale;			/* if totals > scale rescale totals */
+   unsigned  order;			/* order of the probability model */
+   unsigned *context;			/* context of the model */
+   unsigned *totals;			/* the totals */
+} model_t;
+
+typedef struct arith
+{
+   u_word_t   low;			/* start of the current code range */
+   u_word_t   high;			/* end of the current code range */
+   u_word_t   underflow;		/* number of underflow bits pending */
+   u_word_t   code;			/* the present input code value */
+   bitfile_t *file;			/* I/O stream */
+} arith_t;
+
+enum interval {LOW = 0x0000, FIRST_QUARTER = 0x4000, HALF = 0x8000,
+	       THIRD_QUARTER = 0xc000, HIGH = 0xffff};
+
+arith_t *
+alloc_encoder (bitfile_t *file);
+void
+free_encoder (arith_t *arith);
+real_t
+encode_symbol (unsigned symbol, arith_t *arith, model_t *model);
+void
+encode_array (bitfile_t *output, const unsigned *data, const unsigned *context,
+	      const unsigned *c_symbols, unsigned n_context, unsigned n_data,
+	      unsigned scaling);
+arith_t *
+alloc_decoder (bitfile_t *input);
+void
+free_decoder (arith_t *arith);
+unsigned
+decode_symbol (arith_t *arith, model_t *model);
+unsigned *
+decode_array (bitfile_t *input, const unsigned *context,
+	      const unsigned *c_symbols, unsigned n_context,
+	      unsigned n_data, unsigned scaling);
+model_t *
+alloc_model (unsigned m, unsigned scale, unsigned n, unsigned *totals);
+void
+free_model (model_t *model);
+
+#define RESCALE_INPUT_INTERVAL  for (;;)                                      \
+                                   if ((high >= HALF) && (low < HALF) &&      \
+                                      ((low & FIRST_QUARTER) != FIRST_QUARTER \
+				       || (high & FIRST_QUARTER) != 0))       \
+                                   {                                          \
+                                      break;                                  \
+                                   }                                          \
+                                   else if ((high < HALF) || (low >= HALF))   \
+                                   {                                          \
+                                      low  <<= 1;                             \
+                                      high <<= 1;                             \
+                                      high  |= 1;                             \
+                                      code <<= 1;                             \
+                                      code  += get_bit (input);               \
+                                   }                                          \
+                                   else                                       \
+                                   {                                          \
+                                      code  ^= FIRST_QUARTER;                 \
+                                      low   &= FIRST_QUARTER - 1;             \
+                                      low  <<= 1;                             \
+                                      high <<= 1;                             \
+                                      high  |= HALF + 1;                      \
+                                      code <<= 1;                             \
+                                      code  += get_bit (input);               \
+                                   }                                          
+        								   
+#define RESCALE_OUTPUT_INTERVAL  for (;;)                                     \
+                                 {                                            \
+                                    if (high < HALF)                          \
+                                    {                                         \
+                                       put_bit (output, 0);                   \
+                                       for (; underflow; underflow--)         \
+                                          put_bit (output, 1);                \
+                                    }                                         \
+                                    else if (low >= HALF)                     \
+                                    {                                         \
+                                       put_bit (output, 1);                   \
+                                       for (; underflow; underflow--)         \
+                                          put_bit (output, 0);                \
+                                    }                                         \
+                                    else if (high < THIRD_QUARTER &&          \
+                                             low >= FIRST_QUARTER)            \
+                                    {                                         \
+                                       underflow++;                           \
+                                       high |= FIRST_QUARTER;                 \
+                                       low  &= FIRST_QUARTER - 1;             \
+                                    }                                         \
+                                    else                                      \
+                                       break;                                 \
+                                    high <<= 1;                               \
+                                    high  |= 1;                               \
+                                    low  <<= 1;                               \
+                                 }                                             
+					 
+#endif /* not _ARITH_H */
+
diff --git a/converter/other/fiasco/lib/bit-io.c b/converter/other/fiasco/lib/bit-io.c
new file mode 100644
index 00000000..364a1c05
--- /dev/null
+++ b/converter/other/fiasco/lib/bit-io.c
@@ -0,0 +1,327 @@
+/*
+ *  bit-io.c:       Buffered and bit oriented file I/O 
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+ 
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include "config.h"
+
+#include <string.h>
+#if STDC_HEADERS
+#   include <stdlib.h>
+#endif /* not STDC_HEADERS */
+
+#include "macros.h"
+#include "types.h"
+#include "error.h"
+
+#include "misc.h"
+#include "bit-io.h"
+
+/*****************************************************************************
+
+                 local constants
+  
+*****************************************************************************/
+
+static const unsigned BUFFER_SIZE = 16350;
+
+static const unsigned mask[] = {0x0001, 0x0002, 0x0004, 0x0008,
+                                0x0010, 0x0020, 0x0040, 0x0080,
+                                0x0100, 0x0200, 0x0400, 0x0800,
+                                0x1000, 0x2000, 0x4000, 0x8000};
+
+/*****************************************************************************
+
+                public code
+  
+*****************************************************************************/
+
+FILE *
+open_file (const char *filename, const char *env_var, openmode_e mode)
+/*
+ *  Try to open file 'filename' with mode 'mode' (READ_ACCESS, WRITE_ACCESS).
+ *  Scan the current directory first and then cycle through the
+ *  path given in the environment variable 'env_var', if set.
+ * 
+ *  Return value:
+ *  Pointer to open file on success, else NULL.
+ */
+{
+    char       *path;        /* current path */
+    FILE       *fp;      /* file pointer of I/O stream */
+    char       *ext_filename = NULL; /* full path of file */
+    char       *env_path     = NULL; /* path given by 'env_var' */
+    char const * const PATH_SEP     = " ;:,"; /* path separation characters */
+    char const * const DEFAULT_PATH = "."; /* default for output files */
+    const char * const read_mode  = "rb";
+    const char * const write_mode = "wb";
+
+
+    assert (mode == READ_ACCESS || mode == WRITE_ACCESS);
+
+    /*
+     *  First check for stdin or stdout
+     */
+    if (filename == NULL || streq (filename, "-"))
+    {
+        if (mode == READ_ACCESS)
+            return stdin;
+        else 
+            return stdout;
+    }
+   
+    /*
+     *  Try to open 'readonly' file in the current directory
+     */
+    if (mode == READ_ACCESS && (fp = fopen (filename, read_mode)))
+        return fp; 
+
+    if (mode == WRITE_ACCESS && strchr (filename, '/')) /* contains path */
+        return fopen (filename, write_mode);
+   
+    /*
+     *  Get value of environment variable 'env_var', if set
+     *  else use DEFAULT_PATH ("./")
+     */
+    if (env_var != NULL)
+        env_path = getenv (env_var);
+    if (env_path == NULL) 
+        env_path = strdup (DEFAULT_PATH);
+    else
+        env_path = strdup (env_path);
+   
+    /*
+     *  Try to open file in the directory given by the environment
+     *  variable env_var - individual path components are separated by PATH_SEP 
+     */
+    path = strtok (env_path, PATH_SEP);
+    do 
+    {
+        if (ext_filename) 
+            Free (ext_filename);
+        ext_filename =  Calloc (strlen (path) + strlen (filename) + 2,
+                                sizeof (char));
+        strcpy (ext_filename, path); 
+        if (*(ext_filename + strlen (ext_filename) - 1) != '/')
+            strcat (ext_filename, "/");
+        strcat (ext_filename, filename);
+        fp = fopen (ext_filename, mode == READ_ACCESS ? read_mode : write_mode);
+    }
+    while (fp == NULL && (path = strtok (NULL, PATH_SEP)) != NULL);
+
+    Free (env_path);
+   
+    return fp;
+}
+
+bitfile_t *
+open_bitfile (const char *filename, const char *env_var, openmode_e mode)
+/*
+ *  Bitfile constructor:
+ *  Try to open file 'filename' for buffered bit oriented access with mode
+ *  'mode'. Scan the current directory first and then cycle through the path
+ *  given in the environment variable 'env_var', if set.
+ *
+ *  Return value:
+ *  Pointer to open bitfile on success,
+ *      otherwise the program is terminated.
+ */
+{
+    bitfile_t *bitfile = Calloc (1, sizeof (bitfile_t));
+   
+    bitfile->file = open_file (filename, env_var, mode);
+
+    if (bitfile->file == NULL)
+        file_error (filename);
+
+    if (mode == READ_ACCESS)
+    {
+        bitfile->bytepos  = 0;
+        bitfile->bitpos   = 0;
+        bitfile->mode     = mode;
+        bitfile->filename = filename ? strdup (filename) : strdup ("(stdin)");
+    }
+    else if (mode == WRITE_ACCESS)
+    {
+        bitfile->bytepos  = BUFFER_SIZE - 1;
+        bitfile->bitpos   = 8;
+        bitfile->mode     = mode;
+        bitfile->filename = filename ? strdup (filename) : strdup ("(stdout)");
+    }
+    else
+        error ("Unknow file access mode '%d'.", mode);
+   
+    bitfile->bits_processed = 0;
+    bitfile->buffer         = Calloc (BUFFER_SIZE, sizeof (byte_t));
+    bitfile->ptr            = bitfile->buffer;
+
+    return bitfile;
+}
+
+bool_t
+get_bit (bitfile_t *bitfile)
+/*
+ *  Get one bit from the given stream 'bitfile'.
+ *
+ *  Return value:
+ *   1  H bit
+ *   0  L bit
+ *
+ *  Side effects:
+ *  Buffer of 'bitfile' is modified accordingly.
+ */
+{
+    assert (bitfile);
+   
+    if (!bitfile->bitpos--)      /* use next byte ? */
+    {
+        bitfile->ptr++;
+        if (!bitfile->bytepos--)      /* no more bytes left in the buffer? */
+        {
+            /*
+             *  Fill buffer with new data
+             */
+            int bytes = fread (bitfile->buffer, sizeof (byte_t),
+                               BUFFER_SIZE, bitfile->file) - 1;
+            if (bytes < 0)         /* Error or EOF */
+                error ("Can't read next bit from bitfile %s.", bitfile->filename);
+            else
+                bitfile->bytepos = bytes;
+
+            bitfile->ptr = bitfile->buffer;
+        }
+        bitfile->bitpos = 7;
+    }
+
+    bitfile->bits_processed++;
+
+    return *bitfile->ptr & mask [bitfile->bitpos] ? 1 : 0;
+}
+
+unsigned int
+get_bits (bitfile_t *bitfile, unsigned bits)
+/*
+ *  Get #'bits' bits from the given stream 'bitfile'.
+ *
+ *  Return value:
+ *  composed integer value
+ *
+ *  Side effects:
+ *  Buffer of 'bitfile' is modified.
+ */
+{
+    unsigned value = 0;          /* input value */
+   
+    while (bits--)
+        value = (unsigned) (value << 1) | get_bit (bitfile);
+
+    return value;
+}
+
+void
+put_bit (bitfile_t *bitfile, unsigned value)
+/*     
+ *  Put the bit 'value' to the bitfile buffer.
+ *  The buffer is written to the file 'bitfile->file' if the number of
+ *  buffer bytes exceeds 'BUFFER_SIZE'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *  Buffer of 'bitfile' is modified.
+ */
+{
+    assert (bitfile);
+   
+    if (!bitfile->bitpos--)      /* use next byte ? */
+    {
+        bitfile->ptr++;
+        if (!bitfile->bytepos--)      /* no more bytes left ? */
+        {
+            /*
+             *  Write buffer to disk and fill buffer with zeros
+             */
+            if (fwrite (bitfile->buffer, sizeof (byte_t),
+                        BUFFER_SIZE, bitfile->file) != BUFFER_SIZE)
+                error ("Can't write next bit of bitfile %s!", bitfile->filename);
+            memset (bitfile->buffer, 0, BUFFER_SIZE);
+            bitfile->bytepos = BUFFER_SIZE - 1;
+            bitfile->ptr     = bitfile->buffer;
+        }
+        bitfile->bitpos = 7;
+    }
+   
+    if (value)
+        *bitfile->ptr |= mask [bitfile->bitpos];
+
+    bitfile->bits_processed++;
+}
+
+void
+put_bits (bitfile_t *bitfile, unsigned value, unsigned bits)
+/*     
+ *  Put #'bits' bits of integer 'value' to the bitfile buffer 'bitfile'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *  Buffer of 'bitfile' is modified.
+ */
+{
+    while (bits--)
+        put_bit (bitfile, value & mask [bits]);
+}
+
+void
+close_bitfile (bitfile_t *bitfile)
+/*
+ *  Bitfile destructor:
+ *  Close 'bitfile', if 'bitfile->mode' == WRITE_ACCESS write bit buffer
+ *  to disk. 
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *  Structure 'bitfile' is discarded.
+ */
+{
+    assert (bitfile);
+   
+    if (bitfile->mode == WRITE_ACCESS)
+    {
+        unsigned bytes = fwrite (bitfile->buffer, sizeof (byte_t),
+                                 BUFFER_SIZE - bitfile->bytepos, bitfile->file);
+        if (bytes != BUFFER_SIZE - bitfile->bytepos)
+            error ("Can't write remaining %d bytes of bitfile "
+                   "(only %d bytes written)!",
+                   BUFFER_SIZE - bitfile->bytepos, bytes);
+    }
+    fclose (bitfile->file);
+    Free (bitfile->buffer);
+    Free (bitfile->filename);
+    Free (bitfile);
+}
+
+unsigned
+bits_processed (const bitfile_t *bitfile)
+/*
+ *  Return value:
+ *  Number of bits processed up to now
+ */
+{
+    return bitfile->bits_processed;
+}
diff --git a/converter/other/fiasco/lib/bit-io.h b/converter/other/fiasco/lib/bit-io.h
new file mode 100644
index 00000000..d37cc47c
--- /dev/null
+++ b/converter/other/fiasco/lib/bit-io.h
@@ -0,0 +1,58 @@
+/*
+ *  bit-io.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _BIT_IO_H
+#define _BIT_IO_H
+
+#include <stdio.h>
+#include "types.h"
+
+#define OUTPUT_BYTE_ALIGN(bfile) while ((bfile)->bitpos) put_bit (bfile, 0);
+#define INPUT_BYTE_ALIGN(bfile)  while ((bfile)->bitpos) get_bit (bfile);
+
+typedef enum {READ_ACCESS, WRITE_ACCESS} openmode_e;
+
+typedef struct bitfile
+{
+   FILE	      *file;			/* associated filepointer */
+   char	      *filename;		/* corresponding filename */
+   byte_t     *buffer;			/* stream buffer */
+   byte_t     *ptr;			/* pointer to current buffer pos */
+   unsigned    bytepos;			/* current I/O byte */
+   unsigned    bitpos;			/* current I/O bit */
+   unsigned    bits_processed;		/* number of bits already processed */
+   openmode_e  mode;			/* access mode */
+} bitfile_t;
+
+FILE *
+open_file (const char *filename, const char *env_var, openmode_e mode);
+bitfile_t *
+open_bitfile (const char *filename, const char *env_var, openmode_e mode);
+void
+put_bit (bitfile_t *bitfile, unsigned value);
+void
+put_bits (bitfile_t *bitfile, unsigned value, unsigned bits);
+bool_t
+get_bit (bitfile_t *bitfile);
+unsigned 
+get_bits (bitfile_t *bitfile, unsigned bits);
+void
+close_bitfile (bitfile_t *bitfile);
+unsigned
+bits_processed (const bitfile_t *bitfile);
+
+#endif /* not _BIT_IO_H */
+
diff --git a/converter/other/fiasco/lib/dither.c b/converter/other/fiasco/lib/dither.c
new file mode 100644
index 00000000..c7f9ebab
--- /dev/null
+++ b/converter/other/fiasco/lib/dither.c
@@ -0,0 +1,1892 @@
+/*
+ *  dither.c:		Various dithering routines 	
+ *
+ *  Adapted 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 <hafner@bigfoot.de>
+ */
+
+/*
+ * Copyright (c) 1995 Erik Corry
+ * All rights reserved.
+ * 
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL ERIK CORRY BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+ * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ERIK CORRY HAS BEEN ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * ERIK CORRY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+ * BASIS, AND ERIK CORRY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
+ * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*
+ *  $Date: 2000/11/27 20:22:51 $
+ *  $Author: hafner $
+ *  $Revision: 5.3 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#if HAVE_STRING_H
+#	include <string.h>
+#else /* not HAVE_STRING_H */
+#	include <strings.h>
+#endif /* not HAVE_STRING_H */
+#if STDC_HEADERS
+#	include <stdlib.h>
+#endif /* not STDC_HEADERS */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "fiasco.h"
+#include "image.h"
+#include "misc.h"
+#include "dither.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+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);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+fiasco_renderer_t *
+fiasco_renderer_new (unsigned long red_mask, unsigned long green_mask,
+		     unsigned long blue_mask, unsigned bpp,
+		     int double_resolution)
+/*
+ *  FIASCO renderer constructor.
+ *  Allocate memory for the FIASCO renderer structure and
+ *  initialize values.
+ *  `red_mask', `green_mask', and `blue_mask' are the corresponding masks
+ *  of the X11R6 XImage structure. 
+ *  `bpp' gives the depth of the image in bits per pixel (16, 24, or 32).
+ *  If `double_resolution' is not 0 the the image width and height is doubled.
+ *  (fast pixel doubling, no interpolation!)
+ *
+ *  Return value:
+ *	pointer to the new structure or NULL on error
+ */
+{
+   if (bpp != 16 && bpp != 24 && bpp !=32)
+   {
+      set_error (_("Rendering depth of XImage must be 16, 24, or 32 bpp."));
+      return NULL;
+   }
+   else
+   {
+      fiasco_renderer_t  *render    = calloc (1, sizeof (fiasco_renderer_t));
+      renderer_private_t *private   = calloc (1, sizeof (renderer_private_t));
+      bool_t 	       	  twopixels = (bpp == 16 && double_resolution);
+      int 		  crval, cbval, i; /* counter */
+
+      if (!render || !private)
+      {
+	 set_error (_("Out of memory."));
+	 return NULL;
+      }
+      switch (bpp)
+      {
+	 case 16:
+	    render->render = display_16_bit;
+	    break;
+	 case 24:
+	    if (red_mask > green_mask)
+	       render->render = display_24_bit_rgb;
+	    else
+	       render->render = display_24_bit_bgr;
+	    break;
+	 case 32:
+	    render->render = display_32_bit;
+	    break;
+	 default:
+	    break;			/* does not happen */
+      }
+      render->private = private;
+      render->delete  = fiasco_renderer_delete;
+
+      private->double_resolution = double_resolution;
+      private->Cr_r_tab = calloc (256 + 2 * 1024, sizeof (int));
+      private->Cr_g_tab = calloc (256 + 2 * 1024, sizeof (int));
+      private->Cb_g_tab = calloc (256 + 2 * 1024, sizeof (int));
+      private->Cb_b_tab = calloc (256 + 2 * 1024, sizeof (int));
+
+      if (!private->Cr_r_tab || !private->Cr_g_tab
+	  || !private->Cb_b_tab || !private->Cb_g_tab)
+      {
+	 set_error (_("Out of memory."));
+	 return NULL;
+      }
+      
+      for (i = 1024; i < 1024 + 256; i++)
+      {
+	 cbval = crval  = i - 128 - 1024;
+
+	 private->Cr_r_tab [i] =  1.4022 * crval + 0.5;
+	 private->Cr_g_tab [i] = -0.7145 * crval + 0.5;
+	 private->Cb_g_tab [i] = -0.3456 * cbval + 0.5; 
+	 private->Cb_b_tab [i] =  1.7710 * cbval + 0.5;
+      }
+      for (i = 0; i < 1024; i++)
+      {
+	 private->Cr_r_tab [i] = private->Cr_r_tab [1024];
+	 private->Cr_g_tab [i] = private->Cr_g_tab [1024];
+	 private->Cb_g_tab [i] = private->Cb_g_tab [1024]; 
+	 private->Cb_b_tab [i] = private->Cb_b_tab [1024];
+      }
+      for (i = 1024 + 256; i < 2048 + 256; i++)
+      {
+	 private->Cr_r_tab [i] = private->Cr_r_tab [1024 + 255];
+	 private->Cr_g_tab [i] = private->Cr_g_tab [1024 + 255];
+	 private->Cb_g_tab [i] = private->Cb_g_tab [1024 + 255]; 
+	 private->Cb_b_tab [i] = private->Cb_b_tab [1024 + 255];
+      }
+
+      private->Cr_r_tab += 1024 + 128;
+      private->Cr_g_tab += 1024 + 128;
+      private->Cb_g_tab += 1024 + 128;
+      private->Cb_b_tab += 1024 + 128;
+   
+      /* 
+       *  Set up entries 0-255 in rgb-to-pixel value tables.
+       */
+      private->r_table = calloc (256 + 2 * 1024, sizeof (unsigned int));
+      private->g_table = calloc (256 + 2 * 1024, sizeof (unsigned int));
+      private->b_table = calloc (256 + 2 * 1024, sizeof (unsigned int));
+      private->y_table = calloc (256 + 2 * 1024, sizeof (unsigned int));
+
+      if (!private->r_table || !private->g_table
+	  || !private->b_table || !private->y_table)
+      {
+	 set_error (_("Out of memory."));
+	 return NULL;
+      }
+      
+      for (i = 0; i < 256; i++)
+      {
+	 private->r_table [i + 1024]
+	    = i >> (8 - number_of_bits_set(red_mask));
+	 private->r_table [i + 1024]
+	    <<= free_bits_at_bottom (red_mask);
+	 private->g_table [i + 1024]
+	    = i >> (8 - number_of_bits_set (green_mask));
+	 private->g_table [i + 1024]
+	    <<= free_bits_at_bottom (green_mask);
+	 private->b_table [i + 1024]
+	    <<= free_bits_at_bottom (blue_mask);
+	 private->b_table [i + 1024]
+	    = i >> (8 - number_of_bits_set (blue_mask));
+	 if (twopixels)
+	 {
+	    private->r_table [i + 1024] = ((private->r_table [i + 1024] << 16)
+					   | private->r_table [i + 1024]);
+	    private->g_table [i + 1024] = ((private->g_table [i + 1024] << 16)
+					   | private->g_table [i + 1024]);
+	    private->b_table [i + 1024] = ((private->b_table [i + 1024] << 16)
+					   | private->b_table [i + 1024]);
+	 }
+	 private->y_table [i + 1024] = (private->r_table [i + 1024]
+					| private->g_table [i + 1024]
+					| private->b_table [i + 1024]);
+      }
+
+      /*
+       * Spread out the values we have to the rest of the array so that
+       * we do not need to check for overflow.
+       */
+      for (i = 0; i < 1024; i++)
+      {
+	 private->r_table [i]              = private->r_table [1024];
+	 private->r_table [i + 1024 + 256] = private->r_table [1024 + 255];
+	 private->g_table [i]              = private->g_table [1024];
+	 private->g_table [i + 1024 + 256] = private->g_table [1024 + 255];
+	 private->b_table [i]              = private->b_table [1024];
+	 private->b_table [i + 1024 + 256] = private->b_table [1024 + 255];
+	 private->y_table [i]              = private->y_table [1024];
+	 private->y_table [i + 1024 + 256] = private->y_table [1024 + 255];
+      }
+
+      private->r_table += 1024;
+      private->g_table += 1024;
+      private->b_table += 1024;
+      private->y_table += 1024 + 128;
+
+      return render;
+   }
+   
+}
+
+void
+fiasco_renderer_delete (fiasco_renderer_t *renderer)
+/*
+ *  FIASCO renderer destructor:
+ *  Free memory of 'renderer' structure.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	structure 'renderer' is discarded.
+ */
+{
+   if (!renderer)
+      return;
+   else
+   {
+      renderer_private_t *private = (renderer_private_t *) renderer->private;
+
+      Free (private->Cr_g_tab - (1024 + 128));
+      Free (private->Cr_r_tab - (1024 + 128));
+      Free (private->Cb_g_tab - (1024 + 128));
+      Free (private->Cb_b_tab - (1024 + 128));
+      Free (private->r_table - 1024);
+      Free (private->g_table - 1024);
+      Free (private->b_table - 1024);
+      Free (private->y_table - (1024 + 128));
+
+      Free (private);
+      Free (renderer);
+   }
+}
+
+int
+fiasco_renderer_render (const fiasco_renderer_t *renderer,
+			unsigned char *ximage,
+			const fiasco_image_t *fiasco_image)
+{
+   if (!renderer)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "renderer");
+      return 0;
+   }
+   else
+      return renderer->render (renderer, ximage, fiasco_image);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+/*
+ *  Erik Corry's multi-byte dither routines.
+ *
+ *  The basic idea is that the Init generates all the necessary
+ *  tables.  The tables incorporate the information about the layout
+ *  of pixels in the XImage, so that it should be able to cope with
+ *  16-bit 24-bit (non-packed) and 32-bit (10-11 bits per
+ *  color!) screens.  At present it cannot cope with 24-bit packed
+ *  mode, since this involves getting down to byte level again. It is
+ *  assumed that the bits for each color are contiguous in the
+ *  longword.
+ * 
+ *  Writing to memory is done in shorts or ints. (Unfortunately, short
+ *  is not very fast on Alpha, so there is room for improvement
+ *  here). There is no dither time check for overflow - instead the
+ *  tables have slack at each end. This is likely to be faster than an
+ *  'if' test as many modern architectures are really bad at
+ *  ifs. Potentially, each '&&' causes a pipeline flush!
+ *
+ *  There is no shifting and fixed point arithmetic, as I really doubt
+ *  you can see the difference, and it costs. This may be just my
+ *  bias, since I heard that Intel is really bad at shifting.
+ */
+
+static int
+number_of_bits_set (unsigned long a)
+/*
+ *  How many 1 bits are there in the longword.
+ *  Low performance, do not call often.
+ */
+{
+   if (!a)
+      return 0;
+   if (a & 1)
+      return 1 + number_of_bits_set (a >> 1);
+   else
+      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)
+/*
+ *  How many 0 bits are there at least significant end of longword.
+ *  Low performance, do not call often.
+ */
+{
+   /* assume char is 8 bits */
+   if (!a)
+      return sizeof (unsigned long) * 8;
+   else if(((long) a) & 1l)
+      return 0;
+   else
+      return 1 + free_bits_at_bottom ( a >> 1);
+}
+
+static int 
+display_16_bit (const struct fiasco_renderer *this, unsigned char *ximage,
+		const fiasco_image_t *fiasco_image)
+/*
+ *  Convert 'image' to 16 bit color bitmap.
+ *  If 'double_resolution' is true then double image size in both directions.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'out[]'	is filled with dithered image
+ */
+{
+   const image_t      *image;
+   renderer_private_t *private;
+   byte_t	      *out;
+   
+   if (!this)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "this");
+      return 0;
+   }
+   if (!ximage)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "ximage");
+      return 0;
+   }
+   if (!fiasco_image)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image");
+      return 0;
+   }
+
+   out 	   = (byte_t *) ximage;
+   image   = cast_image ((fiasco_image_t *) fiasco_image);
+   if (!image)
+      return 0;
+   private = (renderer_private_t *) this->private;
+   
+   if (image->color)
+   {
+      word_t 	   *cbptr, *crptr;	/* pointer to chroma bands */
+      word_t 	   *yptr;		/* pointers to lumincance band */
+      int     	    yval, crval, cbval;	/* pixel value in YCbCr color space */
+      int     	    R, G, B;		/* pixel value in RGB color space */
+      int     	    n;			/* pixel counter */
+      int     	    x, y;		/* pixel coordinates */
+      int 	   *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab;
+      unsigned int *r_table, *g_table, *b_table;
+
+      Cr_g_tab = private->Cr_g_tab;
+      Cr_r_tab = private->Cr_r_tab;
+      Cb_b_tab = private->Cb_b_tab;
+      Cb_g_tab = private->Cb_g_tab;
+      r_table  = private->r_table;
+      g_table  = private->g_table;
+      b_table  = private->b_table;
+      yptr     = image->pixels [Y];
+      cbptr    = image->pixels [Cb];
+      crptr    = image->pixels [Cr];
+
+      if (image->format == FORMAT_4_2_0)
+      {
+	 u_word_t *dst, *dst2;		/* pointers to dithered pixels */
+	 word_t	  *yptr2;		/* pointers to lumincance band */
+
+	 if (private->double_resolution)
+	 {
+	    yptr2 = yptr + image->width;
+	    dst   = (u_word_t *) out;
+	    dst2  = dst + 4 * image->width;
+	    for (y = image->height / 2; y; y--)
+	    {
+	       for (x = image->width / 2; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  crval = *crptr++ >> 4;
+		  cbval = *cbptr++ >> 4;
+		  yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  crval = *crptr++ / 16;
+		  cbval = *cbptr++ / 16;
+		  yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+	       
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+	       }
+	       memcpy (dst, dst - 2 * image->width,
+		       2 * image->width * sizeof (u_word_t));
+	       memcpy (dst2, dst2 - 2 * image->width,
+		       2 * image->width * sizeof (u_word_t));
+	       yptr  += image->width;
+	       yptr2 += image->width;
+	       dst   += 3 * image->width * 2;
+	       dst2  += 3 * image->width * 2;
+	    }
+	 }
+	 else
+	 {
+	    yptr2 = yptr + image->width;
+	    dst  = (u_word_t *) out;
+	    dst2 = dst + image->width;
+	    
+	    for (y = image->height / 2; y; y--)
+	    {
+	       for (x = image->width / 2; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  crval = *crptr++ >> 4;
+		  cbval = *cbptr++ >> 4;
+		  yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  crval = *crptr++ / 16;
+		  cbval = *cbptr++ / 16;
+		  yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+	       
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+	       }
+	       yptr  += image->width;
+	       yptr2 += image->width;
+	       dst   += image->width;
+	       dst2  += image->width;
+	    }
+	 }
+      }
+      else				/* 4:4:4 format */
+      {
+	 if (private->double_resolution)
+	 {
+	    unsigned int *dst;		/* pointer to dithered pixels */
+	    
+	    dst  = (unsigned int *) out;
+	    
+	    for (y = image->height; y; y--)
+	    {
+	       for (x = image->width; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  crval = *crptr++ >> 4;
+		  cbval = *cbptr++ >> 4;
+		  yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  crval = *crptr++ / 16;
+		  cbval = *cbptr++ / 16;
+		  yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+	       }
+	       memcpy (dst, dst - image->width,
+		       image->width * sizeof (unsigned int));
+	       dst += image->width;
+	    }
+	 }
+	 else
+	 {
+	    u_word_t *dst;		/* pointer to dithered pixels */
+
+	    dst  = (u_word_t *) out;
+	    
+	    for (n = image->width * image->height; n; n--)
+	    {
+#ifdef HAVE_SIGNED_SHIFT
+	       crval = *crptr++ >> 4;
+	       cbval = *cbptr++ >> 4;
+	       yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+	       crval = *crptr++ / 16;
+	       cbval = *cbptr++ / 16;
+	       yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+	       R = yval + Cr_r_tab [crval];
+	       G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+	       B = yval + Cb_b_tab [cbval];
+
+	       *dst++ = r_table [R] | g_table [G] | b_table [B];
+	    }
+	 }
+      }
+   }
+   else
+   {
+      unsigned int *dst;		/* pointer to dithered pixels */
+      word_t	   *src;		/* current pixel of frame */
+      unsigned int *y_table;
+
+      y_table = private->y_table;
+      dst     = (unsigned int *) out;
+      src     = image->pixels [GRAY];
+      
+      if (private->double_resolution)
+      {
+	 int x, y;			/* pixel coordinates */
+  	    
+	 for (y = image->height; y; y--)
+	 {
+	    for (x = image->width; x; x--)
+	    {
+	       int value;
+	       
+#ifdef HAVE_SIGNED_SHIFT
+	       value = y_table [*src++ >> 4];
+#else /* not HAVE_SIGNED_SHIFT */
+	       value = y_table [*src++ / 16];
+#endif /* not HAVE_SIGNED_SHIFT */
+	       *dst++ = (value << 16) | value;
+	    }
+	    
+	    memcpy (dst, dst - image->width,
+		    image->width * sizeof (unsigned int));
+	    dst += image->width;
+	 }
+      }
+      else
+      {
+	 int n;				/* pixel counter */
+	 
+	 for (n = image->width * image->height / 2; n; n--, src += 2)
+#ifdef HAVE_SIGNED_SHIFT
+#	ifndef WORDS_BIGENDIAN
+	    *dst++ = (y_table [src [1] >> 4] << 16) | y_table [src [0] >> 4];
+#	else /* not WORDS_BIGENDIAN  */
+	    *dst++ = (y_table [src [0] >> 4] << 16) | y_table [src [1] >> 4];
+#	endif
+#else /* not HAVE_SIGNED_SHIFT */
+#	ifndef WORDS_BIGENDIAN
+	    *dst++ = (y_table [src [1] / 16] << 16) | y_table [src [0] / 16];
+#	else /* not WORDS_BIGENDIAN  */
+	    *dst++ = (y_table [src [0] / 16] << 16) | y_table [src [1] / 16];
+#	endif
+#endif /* not HAVE_SIGNED_SHIFT */
+      }
+   }
+
+   return 1;
+}
+
+static int 
+display_24_bit_bgr (const struct fiasco_renderer *this, unsigned char *ximage,
+		    const fiasco_image_t *fiasco_image)
+/*
+ *  Convert 'image' to 16 bit color bitmap.
+ *  If 'double_resolution' is true then double image size in both directions.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'out[]'	is filled with dithered image
+ */
+{
+   unsigned 	      *gray_clip = init_clipping ();
+   const image_t      *image;
+   renderer_private_t *private;
+   byte_t	      *out;
+
+   if (!gray_clip)
+      return 0;
+   if (!this)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "this");
+      return 0;
+   }
+   if (!ximage)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "ximage");
+      return 0;
+   }
+   if (!fiasco_image)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image");
+      return 0;
+   }
+
+   out 	   = (byte_t *) ximage;
+   image   = cast_image ((fiasco_image_t *) fiasco_image);
+   if (!image)
+      return 0;
+   private = (renderer_private_t *) this->private;
+   
+   if (image->color)
+   {
+      word_t 	   *cbptr, *crptr;	/* pointer to chroma bands */
+      word_t 	   *yptr;		/* pointers to lumincance band */
+      int 	   *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab;
+      unsigned int *r_table, *g_table, *b_table;
+
+      Cr_g_tab = private->Cr_g_tab;
+      Cr_r_tab = private->Cr_r_tab;
+      Cb_b_tab = private->Cb_b_tab;
+      Cb_g_tab = private->Cb_g_tab;
+      r_table  = private->r_table;
+      g_table  = private->g_table;
+      b_table  = private->b_table;
+      yptr     = image->pixels [Y];
+      cbptr    = image->pixels [Cb];
+      crptr    = image->pixels [Cr];
+
+      if (image->format == FORMAT_4_2_0)
+      {
+	 if (private->double_resolution)
+	 {
+	    int		  yval1;	/* lumincance pixel */
+	    int 	  crval1, cbval1; /* chroma pixels */
+	    int		  yval2;	/* pixel in YCbCr color space */
+	    unsigned int  R1, G1, B1;	/* pixel in RGB color space */
+	    unsigned int  R2, G2, B2;	/* pixel in RGB color space */
+	    int		  x, y;		/* pixel counter */
+	    unsigned int *dst;		/* pointer to dithered pixels */
+	    unsigned int *dst2;		/* pointers to dithered pixels */
+	    word_t	 *yptr2;	/* pointers to lumincance band */
+	    
+	    dst   = (unsigned int *) out;
+	    dst2  = dst + (image->width >> 1) * 3 * 2;
+	    yptr2 = yptr + image->width;
+	    
+	    for (y = image->height >> 1; y; y--)
+	    {
+	       for (x = image->width >> 1; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr++ >> 4) + 128;
+		  yval2  = (*yptr++ >> 4) + 128;
+		  crval1 = *crptr++ >> 4;
+		  cbval1 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr++  / 16 + 128;
+		  yval2  = *yptr++  / 16 + 128;
+		  crval1 = *crptr++ / 16;
+		  cbval1 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B1 << 24);
+		  *dst++ = G1 | (R1 << 8) | (B2 << 16) | (G2 << 24);
+		  *dst++ = R2 | (B2 << 8) | (G2 << 16) | (R2 << 24);
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr2++ >> 4) + 128;
+		  yval2  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr2++  / 16 + 128;
+		  yval2  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst2++ = B1 | (G1 << 8) | (R1 << 16) | (B1 << 24);
+		  *dst2++ = G1 | (R1 << 8) | (B2 << 16) | (G2 << 24);
+		  *dst2++ = R2 | (B2 << 8) | (G2 << 16) | (R2 << 24);
+	       }
+	       memcpy (dst, dst - (image->width >> 1) * 3,
+		       (image->width >> 1) * 3 * sizeof (unsigned int));
+	       memcpy (dst2, dst2 - (image->width >> 1) * 3, 
+		       (image->width >> 1) * 3 * sizeof (unsigned int));
+	       dst   += (image->width >> 1) * 3 * 3;
+	       dst2  += (image->width >> 1) * 3 * 3;
+	       yptr  += image->width;
+	       yptr2 += image->width;
+	    }
+	 }
+	 else
+	 {
+	    int		  yval1;	/* lumincance pixel */
+	    int 	  crval1, cbval1; /* chroma pixels */
+	    int		  yval2;	/* pixel in YCbCr color space */
+	    unsigned int  R1, G1, B1;	/* pixel in RGB color space */
+	    unsigned int  R2, G2, B2;	/* pixel in RGB color space */
+	    int		  x, y;		/* pixel counter */
+	    unsigned int *dst;		/* pointer to dithered pixels */
+	    unsigned int *dst2;		/* pointers to dithered pixels */
+	    word_t	 *yptr2;	/* pointers to lumincance band */
+	    
+	    dst   = (unsigned int *) out;
+	    dst2  = dst + (image->width >> 2) * 3;
+	    yptr2 = yptr + image->width;
+	    
+	    for (y = image->height >> 1; y; y--)
+	    {
+	       for (x = image->width >> 2; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr++ >> 4) + 128;
+		  yval2  = (*yptr++ >> 4) + 128;
+		  crval1 = *crptr++ >> 4;
+		  cbval1 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr++  / 16 + 128;
+		  yval2  = *yptr++  / 16 + 128;
+		  crval1 = *crptr++ / 16;
+		  cbval1 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B2 << 24);
+		  *dst   = G2 | (R2 << 8);
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr2++ >> 4) + 128;
+		  yval2  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr2++  / 16 + 128;
+		  yval2  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst2++ = B1 | (G1 << 8) | (R1 << 16) | (B2 << 24);
+		  *dst2   = G2 | (R2 << 8);
+	       
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr++ >> 4) + 128;
+		  yval2  = (*yptr++ >> 4) + 128;
+		  crval1 = *crptr++ >> 4;
+		  cbval1 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr++  / 16 + 128;
+		  yval2  = *yptr++  / 16 + 128;
+		  crval1 = *crptr++ / 16;
+		  crval2 = *crptr++ / 16;
+		  cbval1 = *cbptr++ / 16;
+		  cbval2 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst++ |= (B1 << 16) | (G1 << 24);
+		  *dst++ = R1 | (B2 << 8) | (G2 << 16) | (R2 << 24);
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr2++ >> 4) + 128;
+		  yval2  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr2++  / 16 + 128;
+		  yval2  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst2++ |= (B1 << 16) | (G1 << 24);
+		  *dst2++ = R1 | (B2 << 8) | (G2 << 16) | (R2 << 24);
+	       }
+	       dst   += (image->width >> 2) * 3;
+	       dst2  += (image->width >> 2) * 3;
+	       yptr  += image->width;
+	       yptr2 += image->width;
+	    }
+	 }
+      }
+      else				/* 4:4:4 format */
+      {
+	 if (private->double_resolution)
+	 {
+	    unsigned int R1, G1, B1;		/* pixel1 in RGB color space */
+	    unsigned int R2, G2, B2;		/* pixel2 in RGB color space */
+	    int		 yval1, crval1, cbval1;	/* pixel1 in YCbCr space */
+	    int		 yval2, crval2, cbval2;	/* pixel2 in YCbCr space */
+	    int		 x, y;			/* pixel counter */
+	    unsigned int *dst;		        /* dithered pixel pointer */
+	    
+	    dst = (unsigned int *) out;
+	    
+	    for (y = image->height; y; y--)
+	    {
+	       for (x = image->width >> 1; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr++ >> 4) + 128;
+		  yval2  = (*yptr++ >> 4) + 128;
+		  crval1 = *crptr++ >> 4;
+		  crval2 = *crptr++ >> 4;
+		  cbval1 = *cbptr++ >> 4;
+		  cbval2 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr++  / 16 + 128;
+		  yval2  = *yptr++  / 16 + 128;
+		  crval1 = *crptr++ / 16;
+		  crval2 = *crptr++ / 16;
+		  cbval1 = *cbptr++ / 16;
+		  cbval2 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				 + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval2]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval2]
+				 + Cb_g_tab [cbval2]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval2]];
+
+		  *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B1 << 24);
+		  *dst++ = G1 | (R1 << 8) | (B2 << 16) | (G2 << 24);
+		  *dst++ = R2 | (B2 << 8) | (G2 << 16) | (R2 << 24);
+	       }
+	       memcpy (dst, dst - 3 * (image->width >> 1),
+		       3 * (image->width >> 1) * sizeof (unsigned int));
+	       dst += 3 * (image->width >> 1);
+	    }
+	 }
+	 else
+	 {
+	    unsigned int R1, G1, B1;		/* pixel in RGB color space */
+	    unsigned int R2, G2, B2;		/* pixel in RGB color space */
+	    int		 yval1, crval1, cbval1;	/* pixel1 in YCbCr space */
+	    int		 yval2, crval2, cbval2;	/* pixel2 in YCbCr space */
+	    int		 n;			/* pixel counter */
+	    unsigned int *dst;		        /* dithered pixel pointer */
+	    
+	    dst = (unsigned int *) out;
+	    
+	    for (n = (image->width * image->height) >> 2; n; n--)
+	    {
+#ifdef HAVE_SIGNED_SHIFT
+	       yval1  = (*yptr++ >> 4) + 128;
+	       yval2  = (*yptr++ >> 4) + 128;
+	       crval1 = *crptr++ >> 4;
+	       crval2 = *crptr++ >> 4;
+	       cbval1 = *cbptr++ >> 4;
+	       cbval2 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+	       yval1  = *yptr++  / 16 + 128;
+	       yval2  = *yptr++  / 16 + 128;
+	       crval1 = *crptr++ / 16;
+	       crval2 = *crptr++ / 16;
+	       cbval1 = *cbptr++ / 16;
+	       cbval2 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+	       R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+	       G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]];
+	       B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+	       R2 = gray_clip [yval2 + Cr_r_tab [crval2]];
+	       G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]];
+	       B2 = gray_clip [yval2 + Cb_b_tab [cbval2]];
+
+	       *dst++ = B1 | (G1 << 8) | (R1 << 16) | (B2 << 24);
+	       *dst   = G2 | (R2 << 8);
+
+#ifdef HAVE_SIGNED_SHIFT
+	       yval1  = (*yptr++ >> 4) + 128;
+	       yval2  = (*yptr++ >> 4) + 128;
+	       crval1 = *crptr++ >> 4;
+	       crval2 = *crptr++ >> 4;
+	       cbval1 = *cbptr++ >> 4;
+	       cbval2 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+	       yval1  = *yptr++  / 16 + 128;
+	       yval2  = *yptr++  / 16 + 128;
+	       crval1 = *crptr++ / 16;
+	       crval2 = *crptr++ / 16;
+	       cbval1 = *cbptr++ / 16;
+	       cbval2 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+	       R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+	       G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]];
+	       B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+	       R2 = gray_clip [yval2 + Cr_r_tab [crval2]];
+	       G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]];
+	       B2 = gray_clip [yval2 + Cb_b_tab [cbval2]];
+
+	       *dst++ |= (B1 << 16) | (G1 << 24);
+	       *dst++ = R1 | (B2 << 8) | (G2 << 16) | (R2 << 24);
+	    }
+	 }
+      }
+   }
+   else
+   {
+      unsigned int *dst;		/* pointer to dithered pixels */
+      word_t	   *src;		/* current pixel of frame */
+      unsigned int *y_table;
+
+      y_table = private->y_table;
+      dst     = (unsigned int *) out;
+      src     = image->pixels [GRAY];
+
+      if (private->double_resolution)
+      {
+	 int	   x, y;		/* pixel counter */
+	 unsigned *shift_clipping = gray_clip + 128;
+
+	 for (y = image->height; y; y--)
+	 {
+	    for (x = image->width >> 1; x; x--)
+	    {
+	       unsigned int val1, val2;
+#ifdef HAVE_SIGNED_SHIFT
+	       val1 = shift_clipping [*src++ >> 4];
+	       val2 = shift_clipping [*src++ >> 4];
+#else /* not HAVE_SIGNED_SHIFT */
+	       val1 = shift_clipping [*src++ / 16];
+	       val2 = shift_clipping [*src++ / 16];
+#endif /* not HAVE_SIGNED_SHIFT */
+
+	       *dst++ = val1 | (val1 << 8) | (val1 << 16) | (val1 << 24);
+	       *dst++ = val1 | (val1 << 8) | (val2 << 16) | (val2 << 24); 
+	       *dst++ = val2 | (val2 << 8) | (val2 << 16) | (val2 << 24);
+	    }
+
+	    memcpy (dst, dst - 3 * (image->width >> 1),
+		    3 * (image->width >> 1) * sizeof (unsigned int));
+	    dst += 3 * (image->width >> 1);
+	 }
+      }
+      else
+      {
+	 int	   n;			/* pixel counter */
+	 unsigned *shift_clipping = gray_clip + 128;
+
+	 for (n = (image->width * image->height) >> 2; n; n--)
+	 {
+	    unsigned int val1, val2;
+
+#ifdef HAVE_SIGNED_SHIFT
+	    val1 = shift_clipping [*src++ >> 4];
+	    val2 = shift_clipping [*src++ >> 4];
+#else /* not HAVE_SIGNED_SHIFT */
+	    val1 = shift_clipping [*src++ / 16];
+	    val2 = shift_clipping [*src++ / 16];
+#endif /* not HAVE_SIGNED_SHIFT */
+
+	    *dst++ = val1 | (val1 << 8)
+		     | (val1 << 16) | (val2 << 24);  /* RGBR */
+	    *dst   = val2 | (val2 << 8);             /* GB-- */
+
+#ifdef HAVE_SIGNED_SHIFT
+	    val1 = shift_clipping [*src++ >> 4];
+	    val2 = shift_clipping [*src++ >> 4];
+#else /* not HAVE_SIGNED_SHIFT */
+	    val1 = shift_clipping [*src++ / 16];
+	    val2 = shift_clipping [*src++ / 16];
+#endif /* not HAVE_SIGNED_SHIFT */
+	    
+	    *dst++ |= (val1 << 16) | (val1 << 24);   /* --RG */
+	    *dst++  = val1 | (val2 << 8)
+		      | (val2 << 16) | (val2 << 24); /* BRGB */
+	 }
+      }
+   }
+   
+   return 1;
+}
+
+static int 
+display_24_bit_rgb (const struct fiasco_renderer *this, unsigned char *ximage,
+		    const fiasco_image_t *fiasco_image)
+/*
+ *  Convert 'image' to 16 bit color bitmap.
+ *  If 'double_resolution' is true then double image size in both directions.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'out[]'	is filled with dithered image
+ */
+{
+   unsigned 	      *gray_clip = init_clipping ();
+   const image_t      *image;
+   renderer_private_t *private;
+   byte_t	      *out;
+
+   if (!gray_clip)
+      return 0;
+   if (!this)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "this");
+      return 0;
+   }
+   if (!ximage)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "ximage");
+      return 0;
+   }
+   if (!fiasco_image)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image");
+      return 0;
+   }
+
+   out 	   = (byte_t *) ximage;
+   image   = cast_image ((fiasco_image_t *) fiasco_image);
+   if (!image)
+      return 0;
+   private = (renderer_private_t *) this->private;
+   
+   if (image->color)
+   {
+      word_t 	   *cbptr, *crptr;	/* pointer to chroma bands */
+      word_t 	   *yptr;		/* pointers to lumincance band */
+      int 	   *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab;
+      unsigned int *r_table, *g_table, *b_table;
+
+      Cr_g_tab = private->Cr_g_tab;
+      Cr_r_tab = private->Cr_r_tab;
+      Cb_b_tab = private->Cb_b_tab;
+      Cb_g_tab = private->Cb_g_tab;
+      r_table  = private->r_table;
+      g_table  = private->g_table;
+      b_table  = private->b_table;
+      yptr     = image->pixels [Y];
+      cbptr    = image->pixels [Cb];
+      crptr    = image->pixels [Cr];
+
+      if (image->format == FORMAT_4_2_0)
+      {
+	 if (private->double_resolution)
+	 {
+	    int		  yval1;	/* lumincance pixel */
+	    int 	  crval1, cbval1; /* chroma pixels */
+	    int		  yval2;	/* pixel in YCbCr color space */
+	    unsigned int  R1, G1, B1;	/* pixel in RGB color space */
+	    unsigned int  R2, G2, B2;	/* pixel in RGB color space */
+	    int		  x, y;		/* pixel counter */
+	    unsigned int *dst;		/* pointer to dithered pixels */
+	    unsigned int *dst2;		/* pointers to dithered pixels */
+	    word_t	 *yptr2;	/* pointers to lumincance band */
+	    
+	    dst   = (unsigned int *) out;
+	    dst2  = dst + (image->width >> 1) * 3 * 2;
+	    yptr2 = yptr + image->width;
+	    
+	    for (y = image->height >> 1; y; y--)
+	    {
+	       for (x = image->width >> 1; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr++ >> 4) + 128;
+		  yval2  = (*yptr++ >> 4) + 128;
+		  crval1 = *crptr++ >> 4;
+		  cbval1 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr++  / 16 + 128;
+		  yval2  = *yptr++  / 16 + 128;
+		  crval1 = *crptr++ / 16;
+		  cbval1 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R1 << 24);
+		  *dst++ = G1 | (B1 << 8) | (R2 << 16) | (G2 << 24);
+		  *dst++ = B2 | (R2 << 8) | (G2 << 16) | (B2 << 24);
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr2++ >> 4) + 128;
+		  yval2  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr2++  / 16 + 128;
+		  yval2  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst2++ = R1 | (G1 << 8) | (B1 << 16) | (R1 << 24);
+		  *dst2++ = G1 | (B1 << 8) | (R2 << 16) | (G2 << 24);
+		  *dst2++ = B2 | (R2 << 8) | (G2 << 16) | (B2 << 24);
+	       }
+	       memcpy (dst, dst - (image->width >> 1) * 3,
+		       (image->width >> 1) * 3 * sizeof (unsigned int));
+	       memcpy (dst2, dst2 - (image->width >> 1) * 3, 
+		       (image->width >> 1) * 3 * sizeof (unsigned int));
+	       dst   += (image->width >> 1) * 3 * 3;
+	       dst2  += (image->width >> 1) * 3 * 3;
+	       yptr  += image->width;
+	       yptr2 += image->width;
+	    }
+	 }
+	 else
+	 {
+	    int		  yval1;	/* lumincance pixel */
+	    int 	  crval1, cbval1; /* chroma pixels */
+	    int		  yval2;	/* pixel in YCbCr color space */
+	    unsigned int  R1, G1, B1;	/* pixel in RGB color space */
+	    unsigned int  R2, G2, B2;	/* pixel in RGB color space */
+	    int		  x, y;		/* pixel counter */
+	    unsigned int *dst;		/* pointer to dithered pixels */
+	    unsigned int *dst2;		/* pointers to dithered pixels */
+	    word_t	 *yptr2;	/* pointers to lumincance band */
+	    
+	    dst   = (unsigned int *) out;
+	    dst2  = dst + (image->width >> 2) * 3;
+	    yptr2 = yptr + image->width;
+	    
+	    for (y = image->height >> 1; y; y--)
+	    {
+	       for (x = image->width >> 2; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr++ >> 4) + 128;
+		  yval2  = (*yptr++ >> 4) + 128;
+		  crval1 = *crptr++ >> 4;
+		  cbval1 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr++  / 16 + 128;
+		  yval2  = *yptr++  / 16 + 128;
+		  crval1 = *crptr++ / 16;
+		  cbval1 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R2 << 24);
+		  *dst   = G2 | (B2 << 8);
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr2++ >> 4) + 128;
+		  yval2  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr2++  / 16 + 128;
+		  yval2  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst2++ = R1 | (G1 << 8) | (B1 << 16) | (R2 << 24);
+		  *dst2   = G2 | (B2 << 8);
+	       
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr++ >> 4) + 128;
+		  yval2  = (*yptr++ >> 4) + 128;
+		  crval1 = *crptr++ >> 4;
+		  cbval1 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr++  / 16 + 128;
+		  yval2  = *yptr++  / 16 + 128;
+		  crval1 = *crptr++ / 16;
+		  crval2 = *crptr++ / 16;
+		  cbval1 = *cbptr++ / 16;
+		  cbval2 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst++ |= (R1 << 16) | (G1 << 24);
+		  *dst++ = B1 | (R2 << 8) | (G2 << 16) | (B2 << 24);
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr2++ >> 4) + 128;
+		  yval2  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr2++  / 16 + 128;
+		  yval2  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval1]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval1]];
+
+		  *dst2++ |= (R1 << 16) | (G1 << 24);
+		  *dst2++ = B1 | (R2 << 8) | (G2 << 16) | (B2 << 24);
+	       }
+	       dst   += (image->width >> 2) * 3;
+	       dst2  += (image->width >> 2) * 3;
+	       yptr  += image->width;
+	       yptr2 += image->width;
+	    }
+	 }
+      }
+      else				/* 4:4:4 format */
+      {
+	 if (private->double_resolution)
+	 {
+	    unsigned int R1, G1, B1;		/* pixel1 in RGB color space */
+	    unsigned int R2, G2, B2;		/* pixel2 in RGB color space */
+	    int		 yval1, crval1, cbval1;	/* pixel1 in YCbCr space */
+	    int		 yval2, crval2, cbval2;	/* pixel2 in YCbCr space */
+	    int		 x, y;			/* pixel counter */
+	    unsigned int *dst;		        /* dithered pixel pointer */
+	    
+	    dst = (unsigned int *) out;
+	    
+	    for (y = image->height; y; y--)
+	    {
+	       for (x = image->width >> 1; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  yval1  = (*yptr++ >> 4) + 128;
+		  yval2  = (*yptr++ >> 4) + 128;
+		  crval1 = *crptr++ >> 4;
+		  crval2 = *crptr++ >> 4;
+		  cbval1 = *cbptr++ >> 4;
+		  cbval2 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval1  = *yptr++  / 16 + 128;
+		  yval2  = *yptr++  / 16 + 128;
+		  crval1 = *crptr++ / 16;
+		  crval2 = *crptr++ / 16;
+		  cbval1 = *cbptr++ / 16;
+		  cbval2 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  
+		  R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+		  G1 = gray_clip [yval1 + Cr_g_tab [crval1]
+				  + Cb_g_tab [cbval1]];
+		  B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+		  R2 = gray_clip [yval2 + Cr_r_tab [crval2]];
+		  G2 = gray_clip [yval2 + Cr_g_tab [crval2]
+				  + Cb_g_tab [cbval2]];
+		  B2 = gray_clip [yval2 + Cb_b_tab [cbval2]];
+
+		  *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R1 << 24);
+		  *dst++ = G1 | (B1 << 8) | (R2 << 16) | (G2 << 24);
+		  *dst++ = B2 | (R2 << 8) | (G2 << 16) | (B2 << 24);
+	       }
+	       memcpy (dst, dst - 3 * (image->width >> 1),
+		       3 * (image->width >> 1) * sizeof (unsigned int));
+	       dst += 3 * (image->width >> 1);
+	    }
+	 }
+	 else
+	 {
+	    unsigned int R1, G1, B1;		/* pixel in RGB color space */
+	    unsigned int R2, G2, B2;		/* pixel in RGB color space */
+	    int		 yval1, crval1, cbval1;	/* pixel1 in YCbCr space */
+	    int		 yval2, crval2, cbval2;	/* pixel2 in YCbCr space */
+	    int		 n;			/* pixel counter */
+	    unsigned int *dst;		        /* dithered pixel pointer */
+	    
+	    dst = (unsigned int *) out;
+	    
+	    for (n = (image->width * image->height) >> 2; n; n--)
+	    {
+#ifdef HAVE_SIGNED_SHIFT
+	       yval1  = (*yptr++ >> 4) + 128;
+	       yval2  = (*yptr++ >> 4) + 128;
+	       crval1 = *crptr++ >> 4;
+	       crval2 = *crptr++ >> 4;
+	       cbval1 = *cbptr++ >> 4;
+	       cbval2 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+	       yval1  = *yptr++  / 16 + 128;
+	       yval2  = *yptr++  / 16 + 128;
+	       crval1 = *crptr++ / 16;
+	       crval2 = *crptr++ / 16;
+	       cbval1 = *cbptr++ / 16;
+	       cbval2 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+	       R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+	       G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]];
+	       B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+	       R2 = gray_clip [yval2 + Cr_r_tab [crval2]];
+	       G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]];
+	       B2 = gray_clip [yval2 + Cb_b_tab [cbval2]];
+
+	       *dst++ = R1 | (G1 << 8) | (B1 << 16) | (R2 << 24);
+	       *dst   = G2 | (B2 << 8);
+
+#ifdef HAVE_SIGNED_SHIFT
+	       yval1  = (*yptr++ >> 4) + 128;
+	       yval2  = (*yptr++ >> 4) + 128;
+	       crval1 = *crptr++ >> 4;
+	       crval2 = *crptr++ >> 4;
+	       cbval1 = *cbptr++ >> 4;
+	       cbval2 = *cbptr++ >> 4;
+#else /* not HAVE_SIGNED_SHIFT */
+	       yval1  = *yptr++  / 16 + 128;
+	       yval2  = *yptr++  / 16 + 128;
+	       crval1 = *crptr++ / 16;
+	       crval2 = *crptr++ / 16;
+	       cbval1 = *cbptr++ / 16;
+	       cbval2 = *cbptr++ / 16;
+#endif /* not HAVE_SIGNED_SHIFT */
+
+	       R1 = gray_clip [yval1 + Cr_r_tab [crval1]];
+	       G1 = gray_clip [yval1 + Cr_g_tab [crval1] + Cb_g_tab [cbval1]];
+	       B1 = gray_clip [yval1 + Cb_b_tab [cbval1]];
+	       R2 = gray_clip [yval2 + Cr_r_tab [crval2]];
+	       G2 = gray_clip [yval2 + Cr_g_tab [crval2] + Cb_g_tab [cbval2]];
+	       B2 = gray_clip [yval2 + Cb_b_tab [cbval2]];
+
+	       *dst++ |= (R1 << 16) | (G1 << 24);
+	       *dst++ = B1 | (R2 << 8) | (G2 << 16) | (B2 << 24);
+	    }
+	 }
+      }
+   }
+   else
+   {
+      unsigned int *dst;		/* pointer to dithered pixels */
+      word_t	   *src;		/* current pixel of frame */
+      unsigned int *y_table;
+
+      y_table = private->y_table;
+      dst     = (unsigned int *) out;
+      src     = image->pixels [GRAY];
+
+      if (private->double_resolution)
+      {
+	 int	   x, y;		/* pixel counter */
+	 unsigned *shift_clipping = gray_clip + 128;
+
+	 for (y = image->height; y; y--)
+	 {
+	    for (x = image->width >> 1; x; x--)
+	    {
+	       unsigned int val1, val2;
+#ifdef HAVE_SIGNED_SHIFT
+	       val1 = shift_clipping [*src++ >> 4];
+	       val2 = shift_clipping [*src++ >> 4];
+#else /* not HAVE_SIGNED_SHIFT */
+	       val1 = shift_clipping [*src++ / 16];
+	       val2 = shift_clipping [*src++ / 16];
+#endif /* not HAVE_SIGNED_SHIFT */
+
+	       *dst++ = val1 | (val1 << 8) | (val1 << 16) | (val1 << 24);
+	       *dst++ = val1 | (val1 << 8) | (val2 << 16) | (val2 << 24); 
+	       *dst++ = val2 | (val2 << 8) | (val2 << 16) | (val2 << 24);
+	    }
+
+	    memcpy (dst, dst - 3 * (image->width >> 1),
+		    3 * (image->width >> 1) * sizeof (unsigned int));
+	    dst += 3 * (image->width >> 1);
+	 }
+      }
+      else
+      {
+	 int	   n;			/* pixel counter */
+	 unsigned *shift_clipping = gray_clip + 128;
+
+	 for (n = (image->width * image->height) >> 2; n; n--)
+	 {
+	    unsigned int val1, val2;
+
+#ifdef HAVE_SIGNED_SHIFT
+	    val1 = shift_clipping [*src++ >> 4];
+	    val2 = shift_clipping [*src++ >> 4];
+#else /* not HAVE_SIGNED_SHIFT */
+	    val1 = shift_clipping [*src++ / 16];
+	    val2 = shift_clipping [*src++ / 16];
+#endif /* not HAVE_SIGNED_SHIFT */
+
+	    *dst++ = val1 | (val1 << 8)
+		     | (val1 << 16) | (val2 << 24);  /* RGBR */
+	    *dst   = val2 | (val2 << 8);             /* GB-- */
+
+#ifdef HAVE_SIGNED_SHIFT
+	    val1 = shift_clipping [*src++ >> 4];
+	    val2 = shift_clipping [*src++ >> 4];
+#else /* not HAVE_SIGNED_SHIFT */
+	    val1 = shift_clipping [*src++ / 16];
+	    val2 = shift_clipping [*src++ / 16];
+#endif /* not HAVE_SIGNED_SHIFT */
+	    
+	    *dst++ |= (val1 << 16) | (val1 << 24);   /* --RG */
+	    *dst++  = val1 | (val2 << 8)
+		      | (val2 << 16) | (val2 << 24); /* BRGB */
+	 }
+      }
+   }
+   
+   return 1;
+}
+
+static int 
+display_32_bit (const struct fiasco_renderer *this, unsigned char *ximage,
+		const fiasco_image_t *fiasco_image)
+/*
+ *  Convert 'image' to 16 bit color bitmap.
+ *  If 'double_resolution' is true then double image size in both directions.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'out[]'	is filled with dithered image
+ */
+{
+   const image_t      *image;
+   renderer_private_t *private;
+   byte_t	      *out;
+   
+   if (!this)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "this");
+      return 0;
+   }
+   if (!ximage)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "ximage");
+      return 0;
+   }
+   if (!fiasco_image)
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "fiasco_image");
+      return 0;
+   }
+
+   out 	   = (byte_t *) ximage;
+   private = (renderer_private_t *) this->private;
+   image   = cast_image ((fiasco_image_t *) fiasco_image);
+   if (!image)
+      return 0;
+   
+   if (image->color)
+   {
+      word_t 	   *cbptr, *crptr;	/* pointer to chroma bands */
+      word_t 	   *yptr;		/* pointers to lumincance band */
+      int     	    yval, crval, cbval;	/* pixel value in YCbCr color space */
+      int     	    R, G, B;		/* pixel value in RGB color space */
+      int     	    n;			/* pixel counter */
+      int     	    x, y;		/* pixel coordinates */
+      int 	   *Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab;
+      unsigned int *r_table, *g_table, *b_table;
+
+      Cr_g_tab = private->Cr_g_tab;
+      Cr_r_tab = private->Cr_r_tab;
+      Cb_b_tab = private->Cb_b_tab;
+      Cb_g_tab = private->Cb_g_tab;
+      r_table  = private->r_table;
+      g_table  = private->g_table;
+      b_table  = private->b_table;
+      yptr  = image->pixels [Y];
+      cbptr = image->pixels [Cb];
+      crptr = image->pixels [Cr];
+
+      if (image->format == FORMAT_4_2_0)
+      {
+	 unsigned int	*dst, *dst2;	/* pointers to dithered pixels */
+	 word_t		*yptr2;		/* pointers to lumincance band */
+
+	 if (private->double_resolution)
+	 {
+	    yptr2 = yptr + image->width;
+	    dst  = (unsigned int *) out;
+	    dst2 = dst + 4 * image->width;
+	    for (y = image->height / 2; y; y--)
+	    {
+	       for (x = image->width / 2; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  crval = *crptr++ >> 4;
+		  cbval = *cbptr++ >> 4;
+		  yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  crval = *crptr++ / 16;
+		  cbval = *cbptr++ / 16;
+		  yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+	       
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+	       }
+	       memcpy (dst, dst - 2 * image->width,
+		       2 * image->width * sizeof (unsigned int));
+	       memcpy (dst2, dst2 - 2 * image->width,
+		       2 * image->width * sizeof (unsigned int));
+	       yptr  += image->width;
+	       yptr2 += image->width;
+	       dst   += 3 * image->width * 2;
+	       dst2  += 3 * image->width * 2;
+	    }
+	 }
+	 else
+	 {
+	    yptr2 = yptr + image->width;
+	    dst   = (unsigned int *) out;
+	    dst2  = dst + image->width;
+	    
+	    for (y = image->height / 2; y; y--)
+	    {
+	       for (x = image->width / 2; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  crval = *crptr++ >> 4;
+		  cbval = *cbptr++ >> 4;
+		  yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  crval = *crptr++ / 16;
+		  cbval = *cbptr++ / 16;
+		  yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+	       
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+
+#ifdef HAVE_SIGNED_SHIFT
+		  yval  = (*yptr2++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  yval  = *yptr2++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  *dst2++ = r_table [R] | g_table [G] | b_table [B];
+	       }
+	       yptr  += image->width;
+	       yptr2 += image->width;
+	       dst   += image->width;
+	       dst2  += image->width;
+	    }
+	 }
+      }
+      else				/* 4:4:4 format */
+      {
+	 if (private->double_resolution)
+	 {
+	    unsigned int *dst;		/* pointer to dithered pixels */
+	    
+	    dst = (unsigned int *) out;
+	    
+	    for (y = image->height; y; y--)
+	    {
+	       for (x = image->width; x; x--)
+	       {
+#ifdef HAVE_SIGNED_SHIFT
+		  crval = *crptr++ >> 4;
+		  cbval = *cbptr++ >> 4;
+		  yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+		  crval = *crptr++ / 16;
+		  cbval = *cbptr++ / 16;
+		  yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+		  R = yval + Cr_r_tab [crval];
+		  G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+		  B = yval + Cb_b_tab [cbval];
+		  
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+		  *dst++ = r_table [R] | g_table [G] | b_table [B];
+	       }
+	       memcpy (dst, dst - 2 * image->width,
+		       2 * image->width * sizeof (unsigned int));
+	       dst += image->width * 2;
+	    }
+	 }
+	 else
+	 {
+	    unsigned int *dst;		/* pointer to dithered pixels */
+
+	    dst  = (unsigned int *) out;
+	    
+	    for (n = image->width * image->height; n; n--)
+	    {
+#ifdef HAVE_SIGNED_SHIFT
+	       crval = *crptr++ >> 4;
+	       cbval = *cbptr++ >> 4;
+	       yval  = (*yptr++ >> 4) + 128;
+#else /* not HAVE_SIGNED_SHIFT */
+	       crval = *crptr++ / 16;
+	       cbval = *cbptr++ / 16;
+	       yval  = *yptr++  / 16 + 128;
+#endif /* not HAVE_SIGNED_SHIFT */
+	       R = yval + Cr_r_tab [crval];
+	       G = yval + Cr_g_tab [crval] + Cb_g_tab [cbval];
+	       B = yval + Cb_b_tab [cbval];
+
+	       *dst++ = r_table [R] | g_table [G] | b_table [B];
+	    }
+	 }
+      }
+   }
+   else
+   {
+      unsigned int *dst;		/* pointer to dithered pixels */
+      word_t	   *src;		/* current pixel of frame */
+      unsigned int *y_table;
+
+      y_table = private->y_table;
+      dst     = (unsigned int *) out;
+      src     = image->pixels [GRAY];
+      
+      if (private->double_resolution)
+      {
+	 int x, y;			/* pixel coordinates */
+	 
+	 for (y = image->height; y; y--)
+	 {
+	    for (x = image->width; x; x--)
+	    {
+	       int value;
+
+#ifdef HAVE_SIGNED_SHIFT
+	       value = y_table [*src++ >> 4];
+#else /* not HAVE_SIGNED_SHIFT */
+	       value = y_table [*src++ / 16];
+#endif /* not HAVE_SIGNED_SHIFT */
+	       *dst++ = value;
+	       *dst++ = value;
+	    }
+
+	    memcpy (dst, dst - 2 * image->width,
+		    2 * image->width * sizeof (unsigned int));
+	    dst += 2 * image->width;
+	 }
+      }
+      else
+      {
+	 int n;				/* pixel counter */
+	 
+	 for (n = image->width * image->height; n; n--)
+#ifdef HAVE_SIGNED_SHIFT
+	    *dst++ = y_table [*src++ >> 4];
+#else /* not HAVE_SIGNED_SHIFT */
+	    *dst++ = y_table [*src++ / 16];
+#endif /* not HAVE_SIGNED_SHIFT */
+      }
+   }
+   
+   return 1;
+}
+
+
+ 
diff --git a/converter/other/fiasco/lib/dither.h b/converter/other/fiasco/lib/dither.h
new file mode 100644
index 00000000..71f9d3c3
--- /dev/null
+++ b/converter/other/fiasco/lib/dither.h
@@ -0,0 +1,27 @@
+/*
+ *  dither.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _DITHER_H
+#define _DITHER_H
+
+typedef struct renderer_private
+{
+   int 	       	*Cr_r_tab, *Cr_g_tab, *Cb_g_tab, *Cb_b_tab;
+   unsigned int *r_table, *g_table, *b_table, *y_table;
+   bool_t	double_resolution;
+} renderer_private_t;
+
+#endif /* _DITHER_H */
diff --git a/converter/other/fiasco/lib/error.c b/converter/other/fiasco/lib/error.c
new file mode 100644
index 00000000..b858badf
--- /dev/null
+++ b/converter/other/fiasco/lib/error.c
@@ -0,0 +1,326 @@
+/*
+ *  error.c:		Error handling
+ *
+ *  Written by:		Stefan Frank
+ *			Ullrich Hafner
+ *  
+ *  Credits:	Modelled after variable argument routines from Jef
+ *		Poskanzer's pbmplus package. 
+ *
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+
+    "int dummy = " change to int dummy; dummy =" for Netpbm to avoid 
+    unused variable warning.
+
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#define _ERROR_C
+
+#include "config.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#if STDC_HEADERS
+#	include <stdarg.h>
+#	define VA_START(args, lastarg) va_start(args, lastarg)
+#else  /* not STDC_HEADERS */
+#	include <varargs.h>
+#	define VA_START(args, lastarg) va_start(args)
+#endif /* not STDC_HEADERS */
+#if HAVE_STRING_H
+#	include <string.h>
+#else /* not HAVE_STRING_H */
+#	include <strings.h>
+#endif /* not HAVE_STRING_H */
+
+#if HAVE_SETJMP_H
+#	include <setjmp.h>
+#endif /* HAVE_SETJMP_H */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "misc.h"
+#include "fiasco.h"
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+static fiasco_verbosity_e  verboselevel  = FIASCO_SOME_VERBOSITY;
+static char 	      	  *error_message = NULL;
+
+#if HAVE_SETJMP_H
+jmp_buf env;
+#endif /* HAVE_SETJMP_H */
+
+/*****************************************************************************
+
+			       public code
+  
+*****************************************************************************/
+
+void
+set_error (const char *format, ...)
+/*
+ *  Set error text to given string.
+ */
+{
+   va_list     args;
+   unsigned    len = 0;
+   const char *str = format;
+   
+   VA_START (args, format);
+
+   len = strlen (format);
+   while ((str = strchr (str, '%')))
+   {
+      str++;
+      if (*str == 's')
+      {
+	 char *vstring = va_arg (args, char *);
+	 len += strlen (vstring);
+      }
+      else if (*str == 'd')
+      {
+	 int dummy;
+     dummy = va_arg (args, int);
+	 len += 10;
+      }
+      else if (*str == 'c')
+      {
+	 int dummy;
+     dummy = va_arg (args, int);
+	 len += 1;
+      }
+      else
+	 return;
+      str++;
+   }
+   va_end(args);
+
+   VA_START (args, format);
+
+   if (error_message)
+      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);
+}
+
+void
+error (const char *format, ...)
+/*
+ *  Set error text to given string.
+ */
+{
+   va_list     args;
+   unsigned    len = 0;
+   const char *str = format;
+   
+   VA_START (args, format);
+
+   len = strlen (format);
+   while ((str = strchr (str, '%')))
+   {
+      str++;
+      if (*str == 's')
+      {
+	 char *vstring = va_arg (args, char *);
+	 len += strlen (vstring);
+      }
+      else if (*str == 'd')
+      {
+	 int dummy;
+     dummy = va_arg (args, int);
+	 len += 10;
+      }
+      else if (*str == 'c')
+      {
+	 int dummy;
+     dummy = va_arg (args, int);
+	 len += 1;
+      }
+      else
+      {
+#if HAVE_SETJMP_H
+	 longjmp (env, 1);
+#else /* not HAVE_SETJMP_H */
+	 exit (1);
+#endif /* HAVE_SETJMP_H */
+      };
+      
+      str++;
+   }
+   va_end(args);
+
+   VA_START (args, format);
+
+   if (error_message)
+      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);
+   
+#if HAVE_SETJMP_H
+   longjmp (env, 1);
+#else /* not HAVE_SETJMP_H */
+   exit (1);
+#endif /* HAVE_SETJMP_H */
+}
+
+const char *
+fiasco_get_error_message (void)
+/*
+ *  Return value:
+ *	Last error message of FIASCO library.
+ */
+{
+   return error_message ? error_message : "";
+}
+
+const char *
+get_system_error (void)
+{
+   return strerror (errno);
+}
+
+void
+file_error (const char *filename)
+/*
+ *  Print file error message and exit.
+ *
+ *  No return value.
+ */
+{
+   error ("File `%s': I/O Error - %s.", filename, get_system_error ());
+}
+
+void 
+warning (const char *format, ...)
+/*
+ *  Issue a warning and continue execution.
+ *
+ *  No return value.
+ */
+{
+   va_list	args;
+
+   VA_START (args, format);
+
+   if (verboselevel == FIASCO_NO_VERBOSITY)
+      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);
+}
+
+void 
+message (const char *format, ...)
+/*
+ *  Print a message to stderr.
+ */
+{
+   va_list args;
+
+   VA_START (args, 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);
+}
+
+void 
+debug_message (const char *format, ...)
+/*
+ *  Print a message to stderr.
+ */
+{
+   va_list args;
+
+   VA_START (args, format);
+
+   if (verboselevel < FIASCO_ULTIMATE_VERBOSITY)
+      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);
+}
+
+void
+info (const char *format, ...)
+/*
+ *  Print a message to stderr. Do not append a newline.
+ */
+{
+   va_list args;
+
+   VA_START (args, 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);
+}
+
+void
+fiasco_set_verbosity (fiasco_verbosity_e level)
+{
+   verboselevel = level;
+}
+
+fiasco_verbosity_e
+fiasco_get_verbosity (void)
+{
+   return verboselevel;
+}
diff --git a/converter/other/fiasco/lib/error.h b/converter/other/fiasco/lib/error.h
new file mode 100644
index 00000000..288b25f4
--- /dev/null
+++ b/converter/other/fiasco/lib/error.h
@@ -0,0 +1,39 @@
+/*
+ *  error.h
+ *  
+ *  Written by:     Stefan Frank
+ *          Ullrich Hafner
+ *
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+#ifndef ERROR_H_INCLUDED
+#define ERROR_H_INCLUDED
+
+void
+set_error (const char *format, ...);
+void
+error (const char *format, ...);
+void
+file_error (const char *filename);
+void
+message (const char *format, ...);
+void 
+debug_message (const char *format, ...);
+void
+warning (const char *format, ...);
+void 
+info (const char *format, ...);
+const char *
+get_system_error (void);
+
+#include <setjmp.h>
+extern jmp_buf env;
+
+#define try         if (setjmp (env) == 0)
+#define catch           else
+
+#include <assert.h>
+
+#endif
diff --git a/converter/other/fiasco/lib/image.c b/converter/other/fiasco/lib/image.c
new file mode 100644
index 00000000..019ba03c
--- /dev/null
+++ b/converter/other/fiasco/lib/image.c
@@ -0,0 +1,512 @@
+/*
+ *  image.c:		Input and output of PNM images.
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/15 17:21:30 $
+ *  $Author: hafner $
+ *  $Revision: 5.2 $
+ *  $State: Exp $
+ */
+
+#include "pnm.h"
+
+#include <string.h>
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "fiasco.h"
+#include "misc.h"
+#include "image.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+init_chroma_tables (void);
+
+/*****************************************************************************
+
+				local variables
+  
+*****************************************************************************/
+static int *Cr_r_tab = NULL;
+static int *Cr_g_tab = NULL;
+static int *Cb_g_tab = NULL;
+static int *Cb_b_tab = NULL;
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+fiasco_image_t *
+fiasco_image_new (const char *filename)
+/*
+ *  FIASCO image constructor.
+ *  Allocate memory for the FIASCO image structure and
+ *  load the specified image `filename'. The image has to be in
+ *  raw pgm or ppm format.
+ *
+ *  Return value:
+ *	pointer to the new image structure
+ *	or NULL in case of an error
+ */
+{
+   try
+   {
+      fiasco_image_t *image = Calloc (1, sizeof (fiasco_image_t));
+
+      image->private 	= read_image (filename);
+      image->delete  	= fiasco_image_delete;
+      image->get_width  = fiasco_image_get_width;
+      image->get_height = fiasco_image_get_height;
+      image->is_color  	= fiasco_image_is_color;
+
+      return image;
+   }
+   catch
+   {
+      return NULL;
+   }
+}
+
+void
+fiasco_image_delete (fiasco_image_t *image)
+/*
+ *  FIASCO image destructor.
+ *  Free memory of FIASCO image struct.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	structure 'image' is discarded.
+ */
+{
+   image_t *this = cast_image (image);
+
+   if (!this)
+      return;
+
+   try
+   {
+      free_image (this);
+   }
+   catch
+   {
+      return;
+   }
+}
+
+unsigned
+fiasco_image_get_width (fiasco_image_t *image)
+{
+   image_t *this = cast_image (image);
+
+   if (!this)
+      return 0;
+   else
+      return this->width;
+}
+
+unsigned
+fiasco_image_get_height (fiasco_image_t *image)
+{
+   image_t *this = cast_image (image);
+
+   if (!this)
+      return 0;
+   else
+      return this->width;
+}
+
+int
+fiasco_image_is_color (fiasco_image_t *image)
+{
+   image_t *this = cast_image (image);
+
+   if (!this)
+      return 0;
+   else
+      return this->color;
+}
+
+image_t *
+cast_image (fiasco_image_t *image)
+/*
+ *  Cast pointer `image' to type image_t.
+ *  Check whether `image' is a valid object of type image_t.
+ *
+ *  Return value:
+ *	pointer to dfiasco_t struct on success
+ *      NULL otherwise
+ */
+{
+   image_t *this = (image_t *) image->private;
+   if (this)
+   {
+      if (!streq (this->id, "IFIASCO"))
+      {
+	 set_error (_("Parameter `image' doesn't match required type."));
+	 return NULL;
+      }
+   }
+   else
+   {
+      set_error (_("Parameter `%s' not defined (NULL)."), "image");
+   }
+
+   return this;
+}
+
+image_t *
+alloc_image (unsigned width, unsigned height, bool_t color, format_e format)
+/*
+ *  Image constructor:
+ *  Allocate memory for the image_t structure.
+ *  Image size is given by 'width' and 'height'.
+ *  If 'color' == YES then allocate memory for three color bands (Y, Cb, Cr).
+ *  otherwise just allocate memory for a grayscale image.
+ *  'format' specifies whether image pixels of color images
+ *  are stored in 4:4:4 or 4:2:0 format.
+ *
+ *  Return value:
+ *	pointer to the new image structure.
+ */
+{
+   image_t *image;
+   color_e band;
+
+   if ((width & 1) || (height & 1))
+      error ("Width and height of images must be even numbers.");
+   if (!color)
+      format = FORMAT_4_4_4;
+
+   image         	  = Calloc (1, sizeof (image_t));
+   image->width  	  = width;
+   image->height 	  = height;
+   image->color  	  = color;
+   image->format 	  = format;
+   image->reference_count = 1;
+   
+   strcpy (image->id, "IFIASCO");
+
+   for (band = first_band (color); band <= last_band (color); band++)
+      if (format == FORMAT_4_2_0 && band != Y)
+	 image->pixels [band] = Calloc ((width * height) >> 2,
+					sizeof (word_t));
+      else
+	 image->pixels [band] = Calloc (width * height, sizeof (word_t));
+   
+   return image;
+}
+
+image_t *
+clone_image (image_t *image)
+/*
+ *  Copy constructor:
+ *  Construct new image by copying the given `image'.
+ *
+ *  Return value:
+ *	pointer to the new image structure.
+ */
+{
+   image_t *new = alloc_image (image->width, image->height, image->color,
+			       image->format);
+   color_e band;
+   
+   for (band = first_band (new->color); band <= last_band (new->color); band++)
+      if (new->format == FORMAT_4_2_0 && band != Y)
+      {
+	 memcpy (new->pixels [band], image->pixels [band],
+		 ((new->width * new->height) >> 2) * sizeof (word_t));
+      }
+      else
+      {
+	 memcpy (new->pixels [band], image->pixels [band],
+		 new->width * new->height * sizeof (word_t));
+      }
+
+   return new;
+}
+
+void
+free_image (image_t *image)
+/*
+ *  Image destructor:
+ *  Free memory of 'image' struct and pixel data.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	structure 'image' is discarded.
+ */
+{
+   if (image != NULL)
+   {
+      if (--image->reference_count)
+	 return;			/* image is still referenced */
+      else
+      {
+	 color_e band;
+
+	 for (band  = first_band (image->color);
+	      band <= last_band (image->color); band++)
+	    if (image->pixels [band])
+	       Free (image->pixels [band]);
+	 Free (image);
+      }
+   }
+   else
+      warning ("Can't free image <NULL>.");
+}
+
+
+static void 
+read_image_data(image_t * const image, FILE *input, const bool_t color,
+                const int width, const int height, const xelval maxval,
+                const int format) {
+   int row;
+   int i;      /* Cursor into image->pixels arrays */
+   xel * xelrow;
+   /* The following are just the normal rgb -> YCbCr conversion matrix,
+      except normalization to maxval 4095 (12 bit color) is built in
+      */
+   const double coeff_lu_r = +0.2989 / maxval * 4095;
+   const double coeff_lu_g = +0.5866 / maxval * 4095;
+   const double coeff_lu_b = +0.1145 / maxval * 4095;
+   const double coeff_cb_r = -0.1687 / maxval * 4095;
+   const double coeff_cb_g = -0.3312 / maxval * 4095;
+   const double coeff_cb_b = +0.5000 / maxval * 4095;
+   const double coeff_cr_r = +0.5000 / maxval * 4095;
+   const double coeff_cr_g = -0.4183 / maxval * 4095;
+   const double coeff_cr_b = -0.0816 / maxval * 4095;
+
+   xelrow = pnm_allocrow(width);
+
+   i = 0; 
+   for (row = 0; row < height; row++) {
+       int col;
+       pnm_readpnmrow(input, xelrow, width, maxval, format);
+       for (col = 0; col < width; col++) {
+           if (color) {
+               image->pixels[Y][i] = 
+                   coeff_lu_r * PPM_GETR(xelrow[col]) 
+                   + coeff_lu_g * PPM_GETG(xelrow[col])
+                   + coeff_lu_b * PPM_GETB(xelrow[col]) - 2048;
+               image->pixels[Cb][i] = 
+                   coeff_cb_r * PPM_GETR(xelrow[col]) 
+                   + coeff_cb_g * PPM_GETG(xelrow[col])
+                   + coeff_cb_b * PPM_GETB(xelrow[col]);
+               image->pixels[Cr][i] = 
+                   coeff_cr_r * PPM_GETR(xelrow[col]) 
+                   + coeff_cr_g * PPM_GETG(xelrow[col])
+                   + coeff_cr_b * PPM_GETB(xelrow[col]);
+
+               i++;
+           } else 
+               image->pixels[GRAY][i++] =
+                   PNM_GET1(xelrow[col]) * 4095 / maxval - 2048;
+       }
+   }
+
+   free(xelrow);
+}
+
+
+
+image_t *
+read_image (const char *image_name)
+/*
+ *  Read image 'image_name'.
+ *  
+ *  Return value:
+ *	pointer to the image structure.
+ */
+{
+   FILE	    *input;			/* input stream */
+   image_t  *image;			/* pointer to new image structure */
+   int  width, height;		/* image size */
+   xelval   maxval;         /* Maxval of image */
+   int format;              /* Image's format code */
+   bool_t    color;			/* color image ? (YES/NO) */
+
+   if (image_name == NULL)
+       input = stdin;
+   else
+       input = pm_openr((char*)image_name);
+
+   pnm_readpnminit(input, &width, &height, &maxval, &format);
+
+   if (PNM_FORMAT_TYPE(format) == PPM_FORMAT)
+       color = YES;
+   else
+       color = NO;
+
+   if (width < 32)
+       pm_error("Image must have a width of at least 32 pixels.");
+
+   if (height < 32)
+       pm_error("Image must have a height of at least 32 pixels.");
+
+   image = alloc_image (width, height, color, FORMAT_4_4_4);
+
+   read_image_data(image, input, color, width, height, maxval, format);
+
+   pm_close(input);
+   
+   return image;
+}   
+
+void
+write_image (const char *image_name, const image_t *image)
+/*
+ *  Write given 'image' data to the file 'image_name'.
+ *  
+ *  No return value.
+ */
+{
+   FILE	*output;			/* output stream */
+   int format;
+   int row;
+   int i;     /* Cursor into image->pixel arrays */
+   xel * xelrow;
+   unsigned *gray_clip;			/* clipping table */
+
+   assert (image && image_name);
+   
+   if (image->format == FORMAT_4_2_0)
+   {
+      warning ("Writing of images in 4:2:0 format not supported.");
+      return;
+   }
+   
+   if (image_name == NULL)
+       output = stdout;
+   else if (strcmp(image_name, "-") == 0)
+       output = stdout;
+   else
+       output = pm_openw((char*)image_name);
+
+   gray_clip  = init_clipping ();	/* mapping of int -> unsigned */
+   if (!gray_clip)
+      error (fiasco_get_error_message ());
+   init_chroma_tables ();
+
+   format = image->color ? PPM_TYPE : PGM_TYPE;
+   
+   pnm_writepnminit(output, image->width, image->height, 255, format, 0);
+
+   xelrow = pnm_allocrow(image->width);
+   i = 0;
+   for (row = 0; row < image->height; row++) {
+       int col;
+       for (col = 0; col < image->width; col++) {
+           if (image->color) {
+               word_t yval, cbval, crval;
+
+               yval  = image->pixels[Y][i]  / 16 + 128;
+               cbval = image->pixels[Cb][i] / 16;
+               crval = image->pixels[Cr][i] / 16;
+
+               PPM_ASSIGN(xelrow[col], 
+                          gray_clip[yval + Cr_r_tab[crval]],
+                          gray_clip[yval + Cr_g_tab[crval] + Cb_g_tab [cbval]],
+                          gray_clip[yval + Cb_b_tab[cbval]]);
+
+           } else
+               /* The 16 below should be 4095/255 = 16.0588 */
+               PNM_ASSIGN1(xelrow[col], 
+                           gray_clip[image->pixels[GRAY][i]/16+128]);
+           i++;
+       }
+       pnm_writepnmrow(output, xelrow, 
+                       image->width, 255, format, 0);
+   }
+   pnm_freerow(xelrow);
+
+   pm_close(output);
+}
+
+bool_t
+same_image_type (const image_t *img1, const image_t *img2)
+/*
+ *  Check whether the given images 'img1' and `img2' are of the same type.
+ *
+ *  Return value:
+ *	YES	if images 'img1' and `img2' are of the same type
+ *	NO	otherwise.
+ */
+{
+   assert (img1 && img2);
+   
+   return ((img1->width == img2->width)
+	   && (img1->height == img2->height)
+	   && (img1->color == img2->color)
+	   && (img1->format == img2->format));
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+init_chroma_tables (void)
+/*
+ *  Chroma tables are used to perform fast YCbCr->RGB color space conversion.
+ */
+{
+   int crval, cbval, i;
+
+   if (Cr_r_tab != NULL || Cr_g_tab != NULL ||
+       Cb_g_tab != NULL || Cb_b_tab != NULL)
+      return;
+
+   Cr_r_tab = Calloc (768, sizeof (int));
+   Cr_g_tab = Calloc (768, sizeof (int));
+   Cb_g_tab = Calloc (768, sizeof (int));
+   Cb_b_tab = Calloc (768, sizeof (int));
+
+   for (i = 256; i < 512; i++)
+   {
+      cbval = crval  = i - 128 - 256;
+
+      Cr_r_tab[i] =  1.4022 * crval + 0.5;
+      Cr_g_tab[i] = -0.7145 * crval + 0.5;
+      Cb_g_tab[i] = -0.3456 * cbval + 0.5; 
+      Cb_b_tab[i] =  1.7710 * cbval + 0.5;
+   }
+   for (i = 0; i < 256; i++)
+   {
+      Cr_r_tab[i] = Cr_r_tab[256];
+      Cr_g_tab[i] = Cr_g_tab[256];
+      Cb_g_tab[i] = Cb_g_tab[256]; 
+      Cb_b_tab[i] = Cb_b_tab[256];
+   }
+   for (i = 512; i < 768; i++)
+   {
+      Cr_r_tab[i] = Cr_r_tab[511];
+      Cr_g_tab[i] = Cr_g_tab[511];
+      Cb_g_tab[i] = Cb_g_tab[511]; 
+      Cb_b_tab[i] = Cb_b_tab[511];
+   }
+
+   Cr_r_tab += 256 + 128;
+   Cr_g_tab += 256 + 128;
+   Cb_g_tab += 256 + 128;
+   Cb_b_tab += 256 + 128;
+}
+
diff --git a/converter/other/fiasco/lib/image.h b/converter/other/fiasco/lib/image.h
new file mode 100644
index 00000000..958049f6
--- /dev/null
+++ b/converter/other/fiasco/lib/image.h
@@ -0,0 +1,59 @@
+/*
+ *  image.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/10/22 10:43:56 $
+ *  $Author: hafner $
+ *  $Revision: 5.3 $
+ *  $State: Exp $
+ */
+
+#ifndef _IMAGE_H
+#define _IMAGE_H
+
+#include <stdio.h>
+#include "types.h"
+#include "fiasco.h"
+
+typedef enum {FORMAT_4_4_4, FORMAT_4_2_0} format_e;
+
+typedef struct image
+/*
+ *  Image data
+ */
+{
+   char      id [7];
+   unsigned  reference_count;
+   unsigned  width;			/* Width of the image */
+   unsigned  height;			/* Height of the image */
+   bool_t    color;			/* Color or grayscale image */
+   format_e  format;			/* Pixel format 4:4:4 or 4:2:0 */
+   word_t   *pixels [3];		/* Pixels in short format */
+} image_t;
+
+image_t *
+cast_image (fiasco_image_t *image);
+image_t *
+alloc_image (unsigned width, unsigned height, bool_t color, format_e format);
+image_t *
+clone_image (image_t *image);
+void
+free_image (image_t *image);
+FILE *
+read_pnmheader (const char *image_name, unsigned *width, unsigned *height,
+		bool_t *color);
+image_t *
+read_image (const char *image_name);
+void
+write_image (const char *image_name, const image_t *image);
+bool_t
+same_image_type (const image_t *img1, const image_t *img2);
+
+#endif /* not _IMAGE_H */
+
diff --git a/converter/other/fiasco/lib/list.c b/converter/other/fiasco/lib/list.c
new file mode 100644
index 00000000..9f516c2e
--- /dev/null
+++ b/converter/other/fiasco/lib/list.c
@@ -0,0 +1,258 @@
+/*
+ *  list.c:		List operations	
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#if HAVE_STRING_H
+#	include <string.h>
+#else /* not HAVE_STRING_H */
+#	include <strings.h>
+#endif /* not HAVE_STRING_H */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "misc.h"
+#include "list.h"
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+list_t *
+alloc_list (size_t size_of_element)
+/*
+ *  List constructor:
+ *  Allocate a new list.
+ *  Size of list element values is given by 'size_of_element'.
+ *
+ *  Return value:
+ *	pointer to an empty list
+ */
+{
+   list_t *new_list = Calloc (1, sizeof (list_t));
+
+   assert (size_of_element > 0);
+
+   new_list->head 	     = NULL;
+   new_list->tail 	     = NULL;
+   new_list->size_of_element = size_of_element;
+
+   return new_list;
+}
+
+void
+free_list (list_t *list)
+/*
+ *  List destructor:
+ *  Discard list and its elements.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	struct 'list' is discarded
+ */
+{
+   assert (list);
+   
+   while (list_remove (list, HEAD, NULL))
+      ;
+   Free (list);
+}
+
+void
+list_insert (list_t *list, pos_e pos, const void *data)
+/*
+ *  Insert a new 'list' element at head ('pos' = HEAD) or
+ *  tail ('pos' = TAIL) of 'list'. 
+ *  'data' is a pointer to a memory segment of size
+ *  'list'->size_of_element containing the value to store.
+ *  The value is directly copied - no references are stored.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	lists current tail or head is replaced by the new element
+ */
+{
+   node_t *element;
+
+   assert (list && data);
+
+   element 	  = Calloc (1, sizeof (node_t));
+   element->value = Calloc (1, list->size_of_element);
+   memcpy (element->value, data, list->size_of_element);
+
+   if (pos == TAIL)
+   {
+      element->next = NULL;
+      element->prev = list->tail;
+      if (list->tail)
+	 list->tail->next = element;
+      list->tail = element;
+      if (!list->head)
+	 list->head = element;
+   }
+   else					/* pos == HEAD */
+   {
+      element->prev = NULL;
+      element->next = list->head;
+      if (list->head)
+	 list->head->prev = element;
+      list->head = element;
+      if (!list->tail)
+	 list->tail = element;
+   }
+}
+
+bool_t
+list_remove (list_t *list, pos_e pos, void *data)
+/*
+ *  Remove 'list' element from head or tail of 'list'.
+ *
+ *  Return value:
+ *	TRUE on success,
+ *	FALSE if list is empty or
+ *	      if list value data is NULL
+ *
+ *  Side effects:
+ *	lists current head or tail is removed
+ *	value of the removed list element (if not NULL) is copied to
+ *      'data' (if 'data' is not NULL)
+ */
+{
+   node_t *element;
+   void	  *valueptr;
+
+   assert (list);
+   
+   if (pos == TAIL)
+   {
+      element = list->tail;
+      if (element)
+      {
+	 list->tail = element->prev;
+	 valueptr   = element->value;
+	 Free (element);
+      }
+      else
+	 valueptr = NULL;
+      if (!list->tail)			/* 'element' was last node */
+	 list->head = NULL;
+   }
+   else					/* pos == HEAD */
+   {
+      element = list->head;
+      if (element)
+      {
+	 list->head = element->next;
+	 valueptr   = element->value;
+	 Free (element);
+      }
+      else
+	 valueptr = NULL;
+      if (!list->head)			/* 'element' was last node */
+	 list->tail = NULL;
+   }
+
+   if (valueptr)			/* copy value of node */
+   {
+      if (data)				
+	 memcpy (data, valueptr, list->size_of_element);
+      Free (valueptr);
+   }
+   
+   return valueptr ? TRUE : FALSE;
+}
+
+bool_t
+list_element_n (const list_t *list, pos_e pos, unsigned n, void *data)
+/*
+ *  Get value of 'list' element number 'n'.
+ *  (First element is list head if 'pos' == HEAD
+ *                 or list tail if 'pos' == TAIL.
+ *   Accordingly, traverse the list in ascending or descending order).
+ *  
+ *  Return value:
+ *	TRUE on success, FALSE if there is no element 'n'
+ *
+ *  Side effects:
+ *	value of list element 'n' is copied to 'data' 
+ */
+{
+   node_t *element;
+
+   assert (list && data);
+   
+   if (pos == HEAD)
+      for (element = list->head; element != NULL && n;
+	   element = element->next, n--)
+	 ;
+   else
+      for (element = list->tail; element != NULL && n;
+	   element = element->prev, n--)
+	 ;
+      
+   if (element)
+   {
+      memcpy (data, element->value, list->size_of_element);
+      return TRUE;
+   }
+   else
+      return FALSE;
+}
+
+unsigned
+list_sizeof (const list_t *list)
+/*
+ *  Count number of 'list' elements.
+ *
+ *  Return value:
+ *	number of 'list' elements.
+ */
+{
+   node_t   *element;
+   unsigned  n = 0;
+
+   assert (list);
+   
+   for (element = list->head; element != NULL; element = element->next)
+      n++;
+
+   return n;
+}
+
+void
+list_foreach (const list_t *list, void (*function)(void *, void *), void *data)
+/*
+ *  Call 'function' for each element of the 'list'.
+ *  Parameters given to 'function' are a pointer to the value of the
+ *  current 'list' element and the user pointer 'data'.
+ *
+ *  No return value.
+ */
+{
+   node_t *element;
+
+   assert (list && function && data);
+   
+   for (element = list->head; element; element = element->next)
+      function (element->value, data);
+}
+
diff --git a/converter/other/fiasco/lib/list.h b/converter/other/fiasco/lib/list.h
new file mode 100644
index 00000000..db7c08b2
--- /dev/null
+++ b/converter/other/fiasco/lib/list.h
@@ -0,0 +1,72 @@
+/*
+ *  list.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _LIST_H
+#define _LIST_H
+
+#include <stdio.h>
+#include <stddef.h>
+
+typedef struct node
+{
+   struct node *prev;			/* pointer to prev list element */
+   struct node *next;			/* pointer to next list element */
+   void	       *value;			/* pointer to value of node */
+} node_t;
+
+typedef struct list
+{
+   node_t *head;
+   node_t *tail;
+   size_t  size_of_element;		/* number of bytes to store value */
+} list_t;
+
+typedef enum {TAIL, HEAD} pos_e;
+
+/*
+ *  Alias definitions for queue and stack
+ */
+
+typedef list_t lqueue_t ;
+#define alloc_queue		alloc_list
+#define free_queue		free_list		
+#define queue_append(q, d)	(list_insert ((q), TAIL, (d)))
+#define queue_remove(q, d)	(list_remove ((q), HEAD, (d)))
+
+typedef list_t lstack_t ;
+#define alloc_stack		alloc_list
+#define free_stack		free_list
+#define stack_push(q, d)	(list_insert ((q), TAIL, (d)))
+#define stack_pop(q, d)		(list_remove ((q), TAIL, (d)))
+
+list_t *
+alloc_list (size_t size_of_element);
+void 
+free_list (list_t *list);
+bool_t
+list_element_n (const list_t *list, pos_e pos, unsigned n, void *data);
+void
+list_foreach (const list_t *list, void (*function)(void *, void *),
+	      void *data);
+void
+list_insert (list_t *list, pos_e pos, const void *data);
+bool_t
+list_remove (list_t *list, pos_e pos, void *data);
+unsigned
+list_sizeof (const list_t *list);
+
+#endif /* not _LIST_H */
+
diff --git a/converter/other/fiasco/lib/macros.h b/converter/other/fiasco/lib/macros.h
new file mode 100644
index 00000000..877abeea
--- /dev/null
+++ b/converter/other/fiasco/lib/macros.h
@@ -0,0 +1,70 @@
+/*
+ *  macros.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _MACROS_H
+#define _MACROS_H
+
+#include <string.h>
+/*******************************************************************************
+
+			  System configuration section
+  
+*******************************************************************************/
+
+#ifndef SEEK_CUR
+#   define SEEK_CUR	1
+#endif /* not SEEK_CUR */
+
+#ifdef WIN32
+#undef max
+#undef min
+#endif /* not WIN32 */
+
+/*****************************************************************************
+
+				Various macros
+  
+*****************************************************************************/
+
+#define streq(str1, str2)	(strcmp ((str1), (str2)) == 0)
+#define strneq(str1, str2)	(strcmp ((str1), (str2)) != 0)
+#define square(x)		((x) * (x))
+#define first_band(color)	((unsigned) ((color) ? Y  : GRAY))
+#define last_band(color)        ((unsigned) ((color) ? Cr : GRAY))
+#define width_of_level(l)	((unsigned) (1 << ((l) >> 1)))
+#define height_of_level(l)	((unsigned) (1 << (((l) + 1) >> 1)))
+#define size_of_level(l)	((unsigned) (1 << (l)))
+#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) 
+
+
+#define	MAXSTRLEN 1024
+#define	MAXSTRLEN_SCANF "%1024s"
+
+typedef enum color {GRAY = 0, Y = 0, Cb = 1, Cr = 2} color_e;
+
+#endif /* _MACROS_H */
+
+
+
diff --git a/converter/other/fiasco/lib/misc.c b/converter/other/fiasco/lib/misc.c
new file mode 100644
index 00000000..02a1314f
--- /dev/null
+++ b/converter/other/fiasco/lib/misc.c
@@ -0,0 +1,563 @@
+/*
+ *  misc.c:		Some usefull functions, that don't fit in one of 
+ *			the other files and that are needed by at least
+ *			two modules. 
+ *
+ *  Written by:		Stefan Frank
+ *			Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <ctype.h>
+
+#ifdef TIME_WITH_SYS_TIME
+#	include <sys/time.h>
+#	include <time.h>
+#else  /* not TIME_WITH_SYS_TIME */
+#	if HAVE_SYS_TIME_H
+#		include <sys/time.h>
+#	else /* not HAVE_SYS_TIME_H */
+#		include <time.h>
+#	endif /* not HAVE_SYS_TIME_H */
+#endif /* not TIME_WITH_SYS_TIME */
+
+#if STDC_HEADERS
+#	include <stdlib.h>
+#endif /* not STDC_HEADERS */
+
+#if HAVE_STRING_H
+#	include <string.h>
+#else /* not HAVE_STRING_H */
+#	include <strings.h>
+#endif /* not HAVE_STRING_H */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "bit-io.h"
+#include "misc.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+remove_comments (FILE *file);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void *
+Calloc (size_t n, size_t size)
+/*
+ *  Allocate memory like calloc ().
+ *
+ *  Return value: Pointer to the new block of memory on success,
+ *		  otherwise the program is terminated.
+ */
+{
+   void	*ptr;				/* pointer to the new memory block */
+
+   if (n <= 0 || size <= 0)
+      error ("Can't allocate memory for %d items of size %d",
+	     (int) n, (int) size);
+
+   ptr = calloc (n, size);
+   if (!ptr)
+      error ("Out of memory!");
+
+   return ptr;
+}
+
+void
+Free (void *memory)
+/*
+ *  Free memory given by the pointer 'memory'
+ *
+ *  No return value.
+ */
+{
+   if (memory != NULL)
+      free (memory);
+   else
+      warning ("Can't free memory block <NULL>.");
+}
+
+unsigned
+prg_timer (clock_t *last_timer, enum action_e action)
+/*
+ *  If 'action' == START then store current value of system timer.
+ *  If 'action' == STOP	 then compute number of elapsed micro seconds since
+ *			 the last time 'prg_timer' was called
+ *			 with 'action' == START.
+ *
+ *  Return value:
+ *	Number of elapsed micro seconds if 'action' == STOP
+ *	0				if 'action' == START
+ *
+ *  Side effects:
+ *	last_timer is set to current timer if action == START
+ */
+{
+   assert (last_timer);
+   
+   if (action == START)
+   {
+      *last_timer = clock ();
+      return 0;
+   }
+   else
+      return (clock () - *last_timer) / (CLOCKS_PER_SEC / 1000.0);
+}
+
+real_t 
+read_real (FILE *infile)
+/* 
+ *  Read one real value from the given input stream 'infile'.
+ *  
+ *  Return value:
+ *	real value on success
+ */
+{
+   float input;
+
+   assert (infile);
+   
+   remove_comments (infile);
+   if (fscanf(infile, "%f", &input) != 1)
+      error("Can't read float value!");
+
+   return (real_t) input;
+}
+
+int 
+read_int (FILE *infile)
+/* 
+ *  Read one integer value from the given input stream 'infile'.
+ *
+ *  Return value:
+ *	integer value on success
+ */
+{
+   int input;				/* integer */
+
+   assert (infile);
+   
+   remove_comments (infile);
+   if (fscanf(infile, "%d", &input) != 1)
+      error("Can't read integer value!");
+
+   return input;
+}
+   
+static void
+remove_comments (FILE *file)
+/*
+ *  Remove shell/pgm style comments (#) from the input 'file'
+ *
+ *  No return value.
+ */
+{
+   int c;				/* current character */
+   
+   assert (file);
+   
+   do
+   {
+      while (isspace(c = getc (file)))
+	 ;
+      if (c == EOF)
+	 error ("EOF reached, input seems to be truncated!");
+      if (c == '#')
+      {
+	 int dummy;
+	 
+	 while (((dummy = getc (file)) != '\n') && dummy != EOF)
+	    ;
+	 if (dummy == EOF)
+	    error ("EOF reached, input seems to be truncated!");
+      }
+      else 
+	 ungetc (c, file);
+   } while (c == '#');
+}
+
+void
+write_rice_code (unsigned value, unsigned rice_k, bitfile_t *output)
+/*
+ *  Write 'value' to the stream 'output' using Rice coding with base 'rice_k'.
+ *
+ *  No return value.
+ */
+{
+   unsigned unary;			/* unary part of Rice Code */
+
+   assert (output);
+   
+   for (unary = value >> rice_k; unary; unary--)
+      put_bit (output, 1);
+   put_bit (output, 0);
+   put_bits (output, value & ((1 << rice_k) - 1), rice_k);
+}
+
+unsigned
+read_rice_code (unsigned rice_k, bitfile_t *input)
+/*
+ *  Read a Rice encoded integer (base 'rice_k') from the stream 'input'.
+ *
+ *  Return value:
+ *	decoded integer
+ */
+{
+   unsigned unary;			/* unary part of Rice code */
+   
+   assert (input);
+   
+   for (unary = 0; get_bit (input); unary++) /* unary part */
+      ;
+
+   return (unary << rice_k) | get_bits (input, rice_k);
+}
+
+void
+write_bin_code (unsigned value, unsigned maxval, bitfile_t *output)
+/*
+ *  Write 'value' to the stream 'output' using an adjusted binary code
+ *  based on given 'maxval'.
+ *
+ *  No return value.
+ */
+{
+   unsigned k;
+   unsigned r;
+   
+   assert (output && maxval && value <= maxval);
+
+   k = log2 (maxval + 1);
+   r = (maxval + 1) % (1 << k);
+
+   if (value < maxval + 1 - 2 * r)	/* 0, ... , maxval - 2r */
+      put_bits (output, value, k);
+   else					/* maxval - 2r + 1, ..., maxval */
+      put_bits (output, value + maxval + 1 - 2 * r, k + 1);
+}
+
+unsigned
+read_bin_code (unsigned maxval, bitfile_t *input)
+/*
+ *  Read a bincode encoded integer from the stream 'input'.
+ *
+ *  Return value:
+ *	decoded integer
+ */
+{
+   unsigned k;
+   unsigned r;
+   unsigned value;
+   
+   assert (input);
+
+   k = log2 (maxval + 1);
+   r = (maxval + 1) % (1 << k);
+
+   value = get_bits (input, k);
+   if (value < maxval + 1 - 2 * r)
+      return value;
+   else
+   {
+      value <<= 1;
+      if (get_bit (input))
+	 value++;
+      return value - maxval - 1 + 2 * r;
+   }
+}
+
+unsigned
+bits_rice_code (unsigned value, unsigned rice_k)
+/*
+ *  Compute number of bits needed for coding integer 'value'
+ *  with given Rice code 'rice_k'.
+ *
+ *  Return value:
+ *	number of bits
+ */
+{
+   unsigned unary;
+   unsigned bits = 0;
+   
+   for (unary = value >> rice_k; unary; unary--)
+      bits++;
+   bits += rice_k + 1;
+
+   return bits;
+}
+
+unsigned
+bits_bin_code (unsigned value, unsigned maxval)
+/*
+ *  Compute number of bits needed for coding integer 'value'
+ *  with adjusted binary code of given maximum value 'maxval'.
+ *
+ *  Return value:
+ *	number of bits
+ */
+{
+   unsigned k;
+   unsigned r;
+
+   assert (maxval && value <= maxval);
+
+   k = log2 (maxval + 1);
+   r = (maxval + 1) % (1 << k);
+
+   return value < maxval + 1 - 2 * r ? k : k + 1;
+}
+
+unsigned *
+init_clipping (void)
+/*
+ *  Initialize the clipping tables
+ *
+ *  Return value:
+ *	pointer to clipping table
+ */
+{
+   static unsigned *gray_clip = NULL;	/* clipping array */
+
+   if (gray_clip == NULL)		/* initialize clipping table */
+   {
+      int i;				/* counter */
+
+      gray_clip  = calloc (256 * 3, sizeof (unsigned));
+      if (!gray_clip)
+      {
+	 set_error (_("Out of memory."));
+	 return NULL;
+      }
+      gray_clip += 256;
+
+      for (i = -256; i < 512; i++)
+	 if (i < 0)
+	    gray_clip [i] = 0;
+	 else if (i > 255)
+	    gray_clip [i] = 255;
+	 else
+	    gray_clip [i] = i;
+   }
+
+   return gray_clip;
+}
+
+#ifndef HAVE_MEMMOVE
+void *
+memmove (void *v_dst, const void *v_src, size_t n)
+/*
+ *  Copy 'n' bytes from memory area 'src' to memory area 'dest'.
+ *  The memory areas may overlap.
+ *
+ *  Return value:
+ *	pointer 'dest'
+ */
+{
+   byte_t	*to, *dst = (byte_t *) v_dst;
+   const byte_t	*from, *src = (byte_t *) v_src;
+   
+   assert (v_dst && v_src);
+   
+   if (dst <= src)
+   {
+      from = src;
+      to   = dst;
+      for (; n; n--)
+	 *to++ = *from++;
+   }
+   else
+   { 
+      from = src + (n - 1);
+      to   = dst + (n - 1);
+      for (; n; n--)
+	 *to-- = *from--;
+   }
+   
+   return v_dst;
+}
+#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
+   macro log2 in config.h to expand to Log2.
+   */
+double
+Log2 (double x)
+/*
+ *  Return value:
+ *	base-2 logarithm of 'x'
+ */
+{
+   return log (x) / 0.69314718;
+}
+
+#ifndef HAVE_STRCASECMP
+bool_t
+strcaseeq (const char *s1, const char *s2)
+/*
+ *  Compare strings 's1' and 's2', ignoring  the  case of the characters.
+ *
+ *  Return value:
+ *	TRUE if strings match, else FALSE
+ */
+{
+   bool_t  matched;
+   char	  *ls1, *ls2, *ptr;
+
+   assert (s1 && s2);
+   
+   ls1 = strdup (s1);
+   ls2 = strdup (s2);
+   
+   for (ptr = ls1; *ptr; ptr++)
+      *ptr = tolower (*ptr);
+   for (ptr = ls2; *ptr; ptr++)
+      *ptr = tolower (*ptr);
+
+   matched = streq (ls1, ls2) ? YES : NO;
+
+   Free (ls1);
+   Free (ls2);
+   
+   return matched;
+}
+#endif /* not HAVE_STRCASECMP */
+
+real_t
+variance (const word_t *pixels, unsigned x0, unsigned y0,
+	  unsigned width, unsigned height, unsigned cols)
+/*
+ *  Compute variance of subimage ('x0', y0', 'width', 'height') of 
+ *  the image data given by 'pixels' ('cols' is the number of pixels
+ *  in one row of the image).
+ *
+ *  Return value:
+ *	variance
+ */
+{
+   real_t   average;			/* average of pixel values */
+   real_t   variance;			/* variance of pixel values */
+   unsigned x, y;			/* pixel counter */
+   unsigned n;				/* number of pixels */
+
+   assert (pixels);
+   
+   for (average = 0, n = 0, y = y0; y < y0 + height; y++)
+      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++)
+	 variance += square ((pixels [y * cols + x] / 16) - average);
+
+   return variance;
+}
+
+int
+sort_asc_word (const void *value1, const void *value2)
+/*
+ *  Sorting function for quicksort.
+ *  Smallest values come first.
+ */
+{
+   if (* (word_t *) value1 < * (word_t *) value2)
+      return -1;
+   else if (* (word_t *) value1 > * (word_t *) value2)
+      return +1;
+   else
+      return 0;
+}
+
+int
+sort_desc_word (const void *value1, const void *value2)
+/*
+ *  Sorting function for quicksort.
+ *  Largest values come first.
+ */
+{
+   if (* (word_t *) value1 > * (word_t *) value2)
+      return -1;
+   else if (* (word_t *) value1 < * (word_t *) value2)
+      return +1;
+   else
+      return 0;
+}
+
+int
+sort_asc_pair (const void *value1, const void *value2)
+/*
+ *  Sorting function for quicksort.
+ *  Smallest values come first.
+ */
+{
+   word_t v1 = ((pair_t *) value1)->key;
+   word_t v2 = ((pair_t *) value2)->key;
+   
+   if (v1 < v2)
+      return -1;
+   else if (v1 > v2)
+      return +1;
+   else
+      return 0;
+}
+
+int
+sort_desc_pair (const void *value1, const void *value2)
+/*
+ *  Sorting function for quicksort.
+ *  Largest values come first.
+ */
+{
+   word_t v1 = ((pair_t *) value1)->key;
+   word_t v2 = ((pair_t *) value2)->key;
+
+   if (v1 > v2)
+      return -1;
+   else if (v1 < v2)
+      return +1;
+   else
+      return 0;
+}
diff --git a/converter/other/fiasco/lib/misc.h b/converter/other/fiasco/lib/misc.h
new file mode 100644
index 00000000..29456590
--- /dev/null
+++ b/converter/other/fiasco/lib/misc.h
@@ -0,0 +1,98 @@
+/*
+ *  misc.h
+ *
+ *  Written by:		Stefan Frank
+ *			Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _MISC_H
+#define _MISC_H
+
+#include "config.h"
+
+#if TIME_WITH_SYS_TIME
+#	include <sys/time.h>
+#	include <time.h>
+#else  /* not TIME_WITH_SYS_TIME */
+#	if HAVE_SYS_TIME_H
+#		include <sys/time.h>
+#	else /* not HAVE_SYS_TIME_H */
+#		include <time.h>
+#	endif /* not HAVE_SYS_TIME_H */
+#endif /* not TIME_WITH_SYS_TIME */
+
+#include <stdio.h>
+#include "types.h"
+#include "bit-io.h"
+
+enum action_e {START, STOP};
+
+void *
+Calloc (size_t n, size_t size);
+void
+Free (void *memory);
+unsigned
+prg_timer (clock_t *ptimer, enum action_e action);
+int 
+read_int(FILE *infile);
+real_t 
+read_real(FILE *infile);
+unsigned
+read_rice_code (unsigned rice_k, bitfile_t *input);
+void
+write_rice_code (unsigned value, unsigned rice_k, bitfile_t *output);
+void
+write_bin_code (unsigned value, unsigned maxval, bitfile_t *output);
+unsigned
+bits_bin_code (unsigned value, unsigned maxval);
+unsigned
+bits_rice_code (unsigned value, unsigned rice_k);
+unsigned
+read_bin_code (unsigned maxval, bitfile_t *input);
+unsigned *
+init_clipping (void);
+real_t
+variance (const word_t *pixels, unsigned x0, unsigned y0,
+	  unsigned width, unsigned height, unsigned cols);
+
+#ifndef HAVE_MEMMOVE
+void *
+memmove(void *dest, const void *src, size_t n);
+#endif /* not HAVE_MEMMOVE */
+
+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);
+#else  /* HAVE_STRCASECMP */
+int
+strcasecmp (const char *s1, const char *s2);
+#define strcaseeq(s1, s2) (strcasecmp ((s1), (s2)) == 0)
+#endif /* HAVE_STRCASECMP */
+
+int
+sort_asc_word (const void *value1, const void *value2);
+int
+sort_desc_word (const void *value1, const void *value2);
+int
+sort_asc_pair (const void *value1, const void *value2);
+int
+sort_desc_pair (const void *value1, const void *value2);
+
+#endif /* not _MISC_H */
+
diff --git a/converter/other/fiasco/lib/mvcode.c b/converter/other/fiasco/lib/mvcode.c
new file mode 100644
index 00000000..d9ce91e2
--- /dev/null
+++ b/converter/other/fiasco/lib/mvcode.c
@@ -0,0 +1,14 @@
+#include "mvcode.h"
+
+unsigned mv_code_table [33][2] =
+/*
+ *  MPEG's huffman code for vector components. Format: code_value, length
+ */
+{
+   {0x19, 11}, {0x1b, 11}, {0x1d, 11}, {0x1f, 11}, {0x21, 11}, {0x23, 11},
+   {0x13, 10}, {0x15, 10}, {0x17, 10}, {0x7, 8}, {0x9, 8}, {0xb, 8}, {0x7, 7},
+   {0x3, 5}, {0x3, 4}, {0x3, 3}, {0x1, 1}, {0x2, 3}, {0x2, 4}, {0x2, 5},
+   {0x6, 7}, {0xa, 8}, {0x8, 8}, {0x6, 8}, {0x16, 10}, {0x14, 10}, {0x12, 10}, 
+   {0x22, 11}, {0x20, 11}, {0x1e, 11}, {0x1c, 11}, {0x1a, 11}, {0x18, 11}
+};
+
diff --git a/converter/other/fiasco/lib/mvcode.h b/converter/other/fiasco/lib/mvcode.h
new file mode 100644
index 00000000..f43f2081
--- /dev/null
+++ b/converter/other/fiasco/lib/mvcode.h
@@ -0,0 +1,6 @@
+#ifndef MVCODE_H_INCLUDED
+#define MVCODE_H_INCLUDED
+
+extern unsigned mv_code_table [33][2];
+
+#endif
diff --git a/converter/other/fiasco/lib/rpf.c b/converter/other/fiasco/lib/rpf.c
new file mode 100644
index 00000000..ac7d48ca
--- /dev/null
+++ b/converter/other/fiasco/lib/rpf.c
@@ -0,0 +1,223 @@
+/*
+ *  rpf.c:		Conversion of float to reduced precision format values
+ *
+ *  Written by:		Stefan Frank
+ *			Richard Krampfl
+ *			Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "misc.h"
+#include "rpf.h"
+
+/* 
+ * CAUTION: The IEEE float format must be used by your compiler,
+ *          or all following code is void!
+ */
+
+#ifdef WORDS_BIGENDIAN
+/*
+ *  Big-Endian Architecture (e.g. SUN, Motorola)
+ *  Memory representation of integer 0x00112233 is 00,11,22,33
+ */
+
+enum real_bytes {BYTE_0, BYTE_1, BYTE_2, BYTE_3};
+
+#else  /* not WORDS_BIGENDIAN */
+/*
+ *  Little-Endian Architecture (e.g. Intel, VAX, Alpha)
+ *  Memory representation of integer 0x00112233 is 33,22,11,00
+ */
+
+enum real_bytes {BYTE_3, BYTE_2, BYTE_1, BYTE_0};
+
+#endif /* not WORDS_BIGENDIAN */
+
+const int RPF_ZERO = -1;
+
+/*****************************************************************************
+
+			       private code
+  
+*****************************************************************************/
+
+int
+rtob (real_t f, const rpf_t *rpf)
+/*
+ *  Convert real number 'f' into fixed point format.
+ *  The real number in [-'range'; +'range'] is scaled to [-1 ; +1].
+ *  Sign and the first 'precision' - 1 bits of the mantissa are
+ *  packed into one integer.  
+ *
+ *  Return value:
+ *	real value in reduced precision format
+ */
+{  
+   unsigned int	mantissa;
+   int		exponent, sign;
+   union
+   {
+      float f;
+      unsigned char c[4];
+   } v;					/* conversion dummy */
+
+   f  /= rpf->range;			/* scale f to [-1,+1] */	
+   v.f = f;
+
+   /*
+    *  Extract mantissa (23 Bits), exponent (8 Bits) and sign (1 Bit)
+    */
+
+   mantissa = ((((v.c[BYTE_1] & 127) << 8 ) | v.c[BYTE_2]) << 8) | v.c[BYTE_3];
+   exponent = (((v.c[BYTE_0] & 127) << 1) | (v.c[BYTE_1] & 128 ? 1 : 0)) - 126;
+   sign     = v.c[BYTE_0] & 128 ? 1 : 0;
+		
+   /*
+    *  Generate reduced precision mantissa.
+    */
+   mantissa >>= 1;				/* shift 1 into from left */
+   mantissa  |= (1 << 22);
+   if (exponent > 0) 
+      mantissa <<= exponent;
+   else
+      mantissa >>= -exponent;  
+   
+   mantissa >>= (23 - rpf->mantissa_bits - 1);
+
+   mantissa +=  1;			/* Round last bit. */
+   mantissa >>= 1;
+   
+   if (mantissa == 0)			/* close to zero */
+      return RPF_ZERO;
+   else if (mantissa >= (1U << rpf->mantissa_bits)) /* overflow */
+      return sign;
+   else
+      return ((mantissa & ((1U << rpf->mantissa_bits) - 1)) << 1) | sign;
+}
+
+float
+btor (int binary, const rpf_t *rpf)
+/*
+ *  Convert value 'binary' in reduced precision format to a real value.
+ *  For more information refer to function lin_rtob() above.
+ *
+ *  Return value:
+ *	converted value
+ */
+{
+   unsigned int	mantissa;
+   int		sign, exponent;
+   union
+   {
+      float f;
+      unsigned char c[4];
+   } value;
+
+   if (binary == RPF_ZERO)
+      return 0;
+
+   if (binary < 0 || binary >= 1 << (rpf->mantissa_bits + 1))
+      error ("Reduced precision format: value %d out of range.", binary);
+
+   /*
+    *  Restore IEEE float format:
+    *  mantissa (23 Bits), exponent (8 Bits) and sign (1 Bit)
+    */
+   
+   sign       = binary & 1;
+   mantissa   = (binary & ((1 << (rpf->mantissa_bits + 1)) - 1)) >> 1; 
+   mantissa <<= (23 - rpf->mantissa_bits);
+   exponent   = 0;
+
+   if (mantissa == 0)
+   {
+      value.f = (sign ? -1.0 : 1.0);
+   }
+   else
+   {
+      while (!(mantissa & (1 << 22)))	/* normalize mantissa */
+      {
+	 exponent--;
+	 mantissa <<= 1;
+      }
+      mantissa <<= 1;
+
+      value.c[BYTE_0] = (sign << 7) | ((exponent + 126) >> 1);
+      value.c[BYTE_1] = (((exponent + 126) & 1) << 7)
+			| ((mantissa  >> 16) & 127);
+      value.c[BYTE_2] = (mantissa >> 8) & 255;
+      value.c[BYTE_3] = mantissa & 255;
+   }
+   
+   return value.f * rpf->range;		/* expand [ -1 ; +1 ] to
+					   [ -range ; +range ] */
+}
+
+rpf_t *
+alloc_rpf (unsigned mantissa, fiasco_rpf_range_e range)
+/*
+ *  Reduced precision format constructor.
+ *  Allocate memory for the rpf_t structure.
+ *  Number of mantissa bits is given by `mantissa'.
+ *  The range of the real values is in the interval [-`range', +`range'].
+ *  In case of invalid parameters, a structure with default values is
+ *  returned. 
+ *
+ *  Return value
+ *	pointer to the new rpf structure
+ */
+{
+   rpf_t *rpf = Calloc (1, sizeof (rpf_t));
+   
+   if (mantissa < 2)
+   {
+      warning (_("Size of RPF mantissa has to be in the interval [2,8]. "
+		 "Using minimum value 2.\n"));
+      mantissa = 2;
+   }
+   else if (mantissa > 8)
+   {
+      warning (_("Size of RPF mantissa has to be in the interval [2,8]. "
+		 "Using maximum value 8.\n"));
+      mantissa = 2;
+   }
+
+   rpf->mantissa_bits = mantissa;
+   rpf->range_e       = range;
+   switch (range)
+   {
+      case FIASCO_RPF_RANGE_0_75:
+	 rpf->range = 0.75;
+	 break;
+      case FIASCO_RPF_RANGE_1_50:
+	 rpf->range = 1.50;
+	 break;
+      case FIASCO_RPF_RANGE_2_00:
+	 rpf->range = 2.00;
+	 break;
+      case FIASCO_RPF_RANGE_1_00:
+	 rpf->range = 1.00;
+	 break;
+      default:
+	 warning (_("Invalid RPF range specified. Using default value 1.0."));
+	 rpf->range   = 1.00;
+	 rpf->range_e = FIASCO_RPF_RANGE_1_00;
+	 break;
+   }
+   return rpf;
+}
diff --git a/converter/other/fiasco/lib/rpf.h b/converter/other/fiasco/lib/rpf.h
new file mode 100644
index 00000000..ba3ff6be
--- /dev/null
+++ b/converter/other/fiasco/lib/rpf.h
@@ -0,0 +1,47 @@
+/*
+ *  rpf.h
+ *
+ *  Written by:		Stefan Frank
+ *			Richard Krampfl
+ *			Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _RPF_H
+#define _RPF_H
+
+#include "types.h"
+#include "fiasco.h"
+
+typedef struct rpf
+{
+   unsigned    	      mantissa_bits;	/* number of bits used for mantissa */
+   real_t      	      range;		/* scale value to [-range, +range] */
+   fiasco_rpf_range_e range_e;
+} rpf_t;
+
+int
+rtob (real_t real, const rpf_t *rpf);
+real_t 
+btor (int b, const rpf_t *rpf);
+rpf_t *
+alloc_rpf (unsigned mantissa, fiasco_rpf_range_e range);
+
+extern const int RPF_ZERO;
+
+#endif /* not _RPF_H */
+
+
+
+
+
+
diff --git a/converter/other/fiasco/lib/types.h b/converter/other/fiasco/lib/types.h
new file mode 100644
index 00000000..16d8028c
--- /dev/null
+++ b/converter/other/fiasco/lib/types.h
@@ -0,0 +1,38 @@
+/*
+ *  types.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:49:37 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _FIASCO_TYPES_H
+#define _FIASCO_TYPES_H
+
+#undef FALSE
+#undef NO
+#undef TRUE
+#undef YES
+
+enum fiasco_boolean { NO = 0, FALSE = 0, YES = 1, TRUE = 1};
+
+typedef float                real_t;
+typedef enum fiasco_boolean  bool_t;
+typedef unsigned char        byte_t;
+typedef short                word_t;
+typedef unsigned short       u_word_t;
+typedef struct pair
+{
+   word_t key;
+   word_t value;
+} pair_t;
+
+#endif
diff --git a/converter/other/fiasco/output/Makefile b/converter/other/fiasco/output/Makefile
new file mode 100644
index 00000000..3bdc4635
--- /dev/null
+++ b/converter/other/fiasco/output/Makefile
@@ -0,0 +1,26 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../../..
+  BUILDDIR = $(SRCDIR)
+endif
+FIASCOSUBDIR = converter/other/fiasco
+SUBDIR = $(FIASCOSUBDIR)/output
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+OBJECTS =  matrices.o mc.o nd.o tree.o weights.o write.o
+
+MERGE_OBJECTS = $(OBJECTS)
+
+INCLUDES = -I$(SRCDIR)/$(FIASCOSUBDIR) \
+	   -I$(SRCDIR)/$(FIASCOSUBDIR)/lib \
+	   -I$(SRCDIR)/$(FIASCOSUBDIR)/codec 
+
+all: libfiasco_output.a
+
+include $(SRCDIR)/Makefile.common
+
+libfiasco_output.a: $(OBJECTS)
+	$(AR) -rc $@ $(OBJECTS)
+	$(RANLIB) $@
+
diff --git a/converter/other/fiasco/output/matrices.c b/converter/other/fiasco/output/matrices.c
new file mode 100644
index 00000000..fd8d31e2
--- /dev/null
+++ b/converter/other/fiasco/output/matrices.c
@@ -0,0 +1,547 @@
+/*
+ *  matrices.c:		Output of transitions matrices
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/* NETPBM: When you call delta_encoding() with last_domain < 4, it
+   crashes.  And we have seen it happen.
+*/
+
+/*
+ *  $Date: 2000/06/14 20:50:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#if STDC_HEADERS
+#	include <stdlib.h>
+#endif /* not STDC_HEADERS */
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "bit-io.h"
+#include "arith.h"
+#include "misc.h"
+#include "wfalib.h"
+
+#include "matrices.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static unsigned
+delta_encoding (bool_t use_normal_domains, bool_t use_delta_domains,
+		const wfa_t *wfa, unsigned last_domain, bitfile_t *output);
+static unsigned
+column_0_encoding (const wfa_t *wfa, unsigned last_row, bitfile_t *output);
+static unsigned
+chroma_encoding (const wfa_t *wfa, bitfile_t *output);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+unsigned
+write_matrices (bool_t use_normal_domains, bool_t use_delta_domains,
+		const wfa_t *wfa, bitfile_t *output)
+/*
+ *  Write transition matrices of 'wfa' to stream 'output'.
+ *
+ *  Return value:
+ *	number of transitions encoded
+ */
+{
+   unsigned root_state;			/* root of luminance */
+   unsigned total = 0;			/* number of transitions */
+   
+   root_state = wfa->wfainfo->color
+		? wfa->tree [wfa->tree [wfa->root_state][0]][0]
+		: wfa->root_state;
+   
+   total  = column_0_encoding (wfa, root_state, output);
+
+   total += delta_encoding (use_normal_domains, use_delta_domains,
+			    wfa, root_state, output);
+   
+   if (wfa->wfainfo->color)
+      total += chroma_encoding (wfa, output);
+   
+   return total;
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static unsigned
+delta_encoding (bool_t use_normal_domains, bool_t use_delta_domains,
+		const wfa_t *wfa, unsigned last_domain, bitfile_t *output)
+/*
+ *  Write transition matrices with delta coding to stream 'input'.
+ *  'last_domain' is the maximum state number used as domain image.
+ *
+ *  Return value:
+ *	number of non-zero matrix elements (WFA edges)
+ */
+{
+   range_sort_t	rs;			/* ranges are sorted as in the coder */
+   unsigned	max_domain;		/* dummy used for recursion */
+   unsigned	total = 0;
+      
+   /*
+    *  Generate a list of range blocks.
+    *  The order is the same as in the coder.
+    */
+   rs.range_state      = Calloc ((last_domain + 1) * MAXLABELS,
+				 sizeof (u_word_t));
+   rs.range_label      = Calloc ((last_domain + 1) * MAXLABELS,
+				 sizeof (byte_t));
+   rs.range_max_domain = Calloc ((last_domain + 1) * MAXLABELS,
+				 sizeof (u_word_t));
+   rs.range_subdivided = Calloc ((last_domain + 1) * MAXLABELS,
+				 sizeof (bool_t));
+   rs.range_no	       = 0;
+   max_domain 	       = wfa->basis_states - 1;
+   sort_ranges (last_domain, &max_domain, &rs, wfa);
+   
+   /*
+    *  Compute and write distribution of #edges
+    */
+   {
+      unsigned state, label;
+      unsigned edge;
+      unsigned count [MAXEDGES + 1];
+      unsigned n;
+      unsigned edges = 0;
+      unsigned M     = 0;
+      unsigned bits  = bits_processed (output);
+      
+      for (n = 0; n < MAXEDGES + 1; n++)
+	 count [n] = 0;
+      
+      for (state = wfa->basis_states; state <= last_domain; state++)
+	 for (label = 0; label < MAXLABELS; label++)
+	    if (isrange (wfa->tree [state][label]))
+	    {
+	       for (edge = 0; isedge (wfa->into [state][label][edge]); edge++)
+		  ;
+	       count [edge]++;
+	       edges++;
+	       M = max (edge, M);
+	    }
+      write_rice_code (M, 3, output);
+      for (n = 0; n <= M; n++)
+/* NETPBM: The following causes a crash when last_domain < 4, because
+   it requests writing of a negative number of bits.  And we have seen
+   last_domain = 3.  But we have no clue what last_domain means, or 
+   even what a rice code is, so we don't know where the error lies.
+   -Bryan 2001.02.09 
+*/
+	 write_rice_code (count [n], (int) log2 (last_domain) - 2, output);
+
+      /*
+       * Arithmetic coding of values */
+      {
+	 unsigned  range;
+	 model_t  *elements = alloc_model (M + 1, 0, 0, count);
+	 arith_t  *encoder  = alloc_encoder (output);
+	       
+	 for (range = 0; range < rs.range_no; range++)
+	    if (!rs.range_subdivided [range])
+	    {
+	       state = rs.range_state [range];
+	       label = rs.range_label [range];
+	       for (edge = 0; isedge (wfa->into [state][label][edge]); edge++)
+		  ;
+	       
+	       encode_symbol (edge, encoder, elements);
+	    }
+	 free_encoder (encoder);
+	 free_model (elements);
+      }
+      debug_message ("delta-#edges: %5d bits. (%5d symbols => %5.2f bps)",
+		     bits_processed (output) - bits, edges,
+		     edges > 0 ? ((bits_processed (output) - bits) /
+				  (double) edges) : 0);
+   }
+
+   /*
+    *  Write matrix elements
+    */
+   {
+      unsigned	bits  	 = bits_processed (output);
+      u_word_t *mapping1 = Calloc (wfa->states, sizeof (u_word_t));
+      u_word_t *mapping2 = Calloc (wfa->states, sizeof (u_word_t));
+      unsigned	range;
+
+      put_bit (output, use_normal_domains);
+      put_bit (output, use_delta_domains);
+      
+      /*
+       *  Generate array of states which are admitted domains.
+       *  When coding intra frames 'mapping1' == 'mapping2' otherwise
+       *  'mapping1' is a list of 'normal' domains which are admitted for 
+       *             coding intra blocks
+       *  'mapping2' is a list of 'delta' domains which are admitted for
+       *             coding the motion compensated prediction error 
+       */
+      {
+	 unsigned n1, n2, state;
+	 
+	 for (n1 = n2 = state = 0; state < wfa->states; state++)
+	 {
+	    mapping1 [state] = n1;
+	    if (usedomain (state, wfa)
+		&& (state < wfa->basis_states || use_delta_domains
+		    || !wfa->delta_state [state]))
+	       n1++;
+	    
+	    mapping2 [state] = n2;
+	    if (usedomain (state, wfa)
+		&& (state < wfa->basis_states || use_normal_domains
+		    || wfa->delta_state [state]))
+	       n2++;
+	 }
+	 debug_message ("# normal states = %d, # delta states = %d,"
+			" # WFA states = %d", n1, n2, wfa->states);
+      }
+      
+      for (range = 0; range < rs.range_no; range++)
+	 if (!rs.range_subdivided [range])
+	 {
+	    unsigned  state = rs.range_state [range];
+	    unsigned  label = rs.range_label [range];
+	    unsigned  last  = 1;
+	    u_word_t *mapping;
+	    unsigned  max_value;
+	    unsigned  edge;
+	    word_t    domain;
+
+	    if (wfa->delta_state [state] ||
+		wfa->mv_tree [state][label].type != NONE)
+	       mapping = mapping2;
+	    else
+	       mapping = mapping1;
+	    
+	    max_value = mapping [rs.range_max_domain [range]];
+	    
+	    for (edge = 0; isedge (domain = wfa->into [state][label][edge]);
+		 edge++)
+	       if (domain > 0)
+	       {
+		  total++;
+		  if (max_value - last)
+		  {
+		     write_bin_code (mapping [domain] - last,
+				     max_value - last, output);
+		     last = mapping [domain] + 1;
+		  }
+	       }
+	 }
+
+      debug_message ("delta-index:  %5d bits. (%5d symbols => %5.2f bps)",
+		     bits_processed (output) - bits, total,
+		     total > 0 ? ((bits_processed (output) - bits) /
+				  (double) total) : 0);
+      Free (mapping1);
+      Free (mapping2);
+   }
+   
+   Free (rs.range_state);
+   Free (rs.range_label);
+   Free (rs.range_max_domain);
+   Free (rs.range_subdivided);
+
+   return total;
+}
+
+static unsigned
+column_0_encoding (const wfa_t *wfa, unsigned last_row, bitfile_t *output)
+/*
+ *  Write column 0 of the transition matrices of the 'wfa' to stream 'output'
+ *  with quasi arithmetic coding.
+ *  All rows from 'wfa->basis_states' up to 'last_row' are decoded.
+ *
+ *  Return value:
+ *	number of non-zero matrix elements (WFA edges)
+ */
+{
+   u_word_t  high;			/* Start of the current code range */
+   u_word_t  low;			/* End of the current code range */
+   unsigned *prob;			/* probability array */
+   unsigned  row;			/* current matrix row */
+   unsigned  label;			/* current matrix label */
+   unsigned  underflow;			/* Underflow bits */
+   unsigned  index;			/* probability index */
+   unsigned  total = 0;			/* Number of '1' elements */
+   unsigned  bits  = bits_processed (output);
+
+   /*
+    *  Compute the probability array:
+    *  prob[] = { 1/2, 1/2, 1/4, 1/4, 1/4, 1/4,
+    *             1/8, ... , 1/16, ..., 1/(MAXPROB+1)}
+    */
+   {
+      unsigned n;
+      unsigned exp;			/* current exponent */
+      
+      prob = Calloc (1 << (MAX_PROB + 1), sizeof (unsigned));
+   
+      for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++)
+	 for (exp = 0; exp < 1U << n; exp++, index++)
+	    prob [index] = n;
+   }
+   
+   high      = HIGH;			/* 1.0 */
+   low       = LOW;			/* 0.0 */
+   underflow = 0;			/* no underflow bits */
+
+   index = 0;
+
+   /*
+    *  Encode column 0 with a quasi arithmetic coder (QAC).
+    *  Advantage of this QAC with respect to a binary AC:
+    *  Instead of using time consuming multiplications and divisions
+    *  to compute the probability of the most probable symbol (MPS) and
+    *  the range of the interval, a table look up procedure linked
+    *  with a shift operation is used for both computations.
+    */
+   for (row = wfa->basis_states; row <= last_row; row++)
+      for (label = 0; label < MAXLABELS; label++)
+	 if (isrange (wfa->tree [row][label]))
+	 {
+	    if (wfa->into [row][label][0] != 0)
+	    {
+	       /*
+		*  encode the MPS '0'
+		*/
+	       high = high - ((high - low) >> prob [index]) - 1;
+	       RESCALE_OUTPUT_INTERVAL;
+	       
+	       if (index < 1020)
+		  index++;
+	    }
+	    else
+	    {
+	       /*
+		*  encode the LPS '1'
+		*/
+	       low = high - ((high - low) >> prob [index]);
+
+	       RESCALE_OUTPUT_INTERVAL;
+	       
+	       total++;
+	       index >>= 1;
+	    }
+	 }
+   /*
+    *  Flush the quasi-arithmetic encoder
+    */
+   low = high;
+
+   RESCALE_OUTPUT_INTERVAL;
+   
+   OUTPUT_BYTE_ALIGN (output);
+
+   Free (prob);
+
+   debug_message ("delta-state0: %5d bits. (%5d symbols => %5.2f bps)",
+		  bits_processed (output) - bits, total,
+		  total > 0 ? ((bits_processed (output) - bits) /
+			       (double) total) : 0);
+
+   return total;
+}   
+
+static unsigned
+chroma_encoding (const wfa_t *wfa, bitfile_t *output)
+/*
+ *  Write transition matrices of 'wfa' states which are part of the
+ *  chroma channels Cb and Cr to stream 'output'.
+ *
+ *  Return value:
+ *	number of non-zero matrix elements (WFA edges)
+ */
+{
+
+   unsigned  domain;			/* current domain, counter */
+   unsigned  label;			/* current label */
+   unsigned  total = 0;			/* number of '1' elements */
+   u_word_t  high;			/* Start of the current code range */
+   u_word_t  low;			/* End of the current code range */
+   unsigned  underflow;			/* underflow bits */
+   unsigned *prob;			/* probability array */
+   unsigned  index;			/* probability index, counter */
+   unsigned  next_index;		/* probability of last domain */
+   unsigned  row;			/* current matrix row */
+   word_t   *y_domains;
+   unsigned  count = 0;			/* number of transitions for part 1 */
+   unsigned  bits  = bits_processed (output);
+   
+   /*
+    *  Compute the asymmetric probability array
+    *  prob[] = { 1/2, 1/2, 1/4, 1/4, 1/4, 1/4,
+    *                     1/8, ... , 1/16, ..., 1/(MAXPROB+1)}
+    */
+   {
+      unsigned n;
+      unsigned exp;			/* current exponent */
+      
+      prob = Calloc (1 << (MAX_PROB + 1), sizeof (unsigned));
+   
+      for (index = 0, n = MIN_PROB; n <= MAX_PROB; n++)
+	 for (exp = 0; exp < 1U << n; exp++, index++)
+	    prob [index] = n;
+   }
+   
+   high      = HIGH;			/* 1.0 */
+   low       = LOW;			/* 0.0 */
+   underflow = 0;			/* no underflow bits */
+
+   next_index = index = 0;
+
+   y_domains = compute_hits (wfa->basis_states,
+			     wfa->tree [wfa->tree [wfa->root_state][0]][0],
+			     wfa->wfainfo->chroma_max_states, wfa);
+
+   /*
+    *  First of all, read all matrix columns given in the list 'y_domains'
+    *  which note all admitted domains.
+    *  These matrix elements are stored with QAC (see column_0_encoding ()).
+    */
+   for (domain = 0; y_domains [domain] != -1; domain++)
+   {
+      bool_t save_index = YES;		/* YES: store current prob. index */
+      
+      row   = wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1;
+      index = next_index;
+	 
+      for (; row < wfa->states; row++)
+      {
+	 for (label = 0; label < MAXLABELS; label++)
+	    if (isrange (wfa->tree [row][label]))
+	    {
+	       unsigned	edge;
+	       int	into;
+	       bool_t    match;		/* approx with current domain found */
+	       
+	       for (match = NO, edge = 0;
+		    isedge (into = wfa->into [row][label][edge])
+			    && (unsigned) into < row;
+		    edge++)
+		  if (into == y_domains [domain]
+		      && into != wfa->y_state [row][label])
+		     match = YES;
+	       if (!match)
+	       {
+		  /*
+		   *  encode the MPS '0'
+		   */
+		  high = high - ((high - low) >> prob [index]) - 1;
+
+		  RESCALE_OUTPUT_INTERVAL;
+		     
+		  if (index < 1020)
+		     index++;
+	       }
+	       else
+	       {
+		  /*
+		   *  encode the LPS '1'
+		   */
+		  low = high - ((high - low) >> prob [index]);
+
+		  RESCALE_OUTPUT_INTERVAL;
+		     
+		  total++;
+		  index >>= 1;
+	       }
+	    }
+	 if (save_index)
+	 {
+	    next_index = index;
+	    save_index = NO;
+	 }
+      }
+   }
+
+   debug_message ("CbCr_matrix:  %5d bits. (%5d symbols => %5.2f bps)",
+		  bits_processed (output) - bits, total,
+		  total > 0 ? ((bits_processed (output) - bits) /
+			       (double) total) : 0);
+   count = total;
+   bits  = bits_processed (output);
+   
+   /*
+    *  Encode the additional column which indicates whether there
+    *  are transitions to a state with same spatial coordinates
+    *  in the Y component.
+    *
+    *  Again, quasi arithmetic coding is used for this task.
+    */
+
+   next_index = index = 0;
+
+   for (row = wfa->tree [wfa->tree [wfa->root_state][0]][0] + 1;
+	row < wfa->states; row++)
+      for (label = 0; label < MAXLABELS; label++)
+	 if (!wfa->y_column [row][label])
+	 {
+	    /*
+	     *  encode the MPS '0'
+	     */
+	    high = high - ((high - low) >> prob [index]) - 1;
+
+	    RESCALE_OUTPUT_INTERVAL;
+	    
+	    if (index < 1020)
+	       index++;
+	 }
+	 else
+	 {
+	    /*
+	     *  encode the LPS '1'
+	     */
+	    low = high - ((high - low) >> prob [index]);
+
+	    RESCALE_OUTPUT_INTERVAL;
+
+	    index >>= 1;
+	    total++;
+	 }
+
+   /*
+    *  Flush the quasi-arithmetic encoder
+    */
+   low = high;
+
+   RESCALE_OUTPUT_INTERVAL;
+   OUTPUT_BYTE_ALIGN (output);
+
+   debug_message ("Yreferences:  %5d bits. (%5d symbols => %5.2f bps)",
+		  bits_processed (output) - bits, total - count,
+		  total - count > 0 ? ((bits_processed (output) - bits) /
+				       (double) (total - count)) : 0);
+
+   Free (prob);
+   Free (y_domains);
+   
+   return total;
+}
diff --git a/converter/other/fiasco/output/matrices.h b/converter/other/fiasco/output/matrices.h
new file mode 100644
index 00000000..f880fef8
--- /dev/null
+++ b/converter/other/fiasco/output/matrices.h
@@ -0,0 +1,28 @@
+/*
+ *  matrices.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _MATRICES_H
+#define _MATRICES_H
+
+#include "wfa.h"
+#include "bit-io.h"
+
+unsigned
+write_matrices (bool_t use_normal_domains, bool_t use_delta_domains,
+		const wfa_t *wfa, bitfile_t *output);
+
+#endif /* _MATRICES_H */
+
diff --git a/converter/other/fiasco/output/mc.c b/converter/other/fiasco/output/mc.c
new file mode 100644
index 00000000..afff586b
--- /dev/null
+++ b/converter/other/fiasco/output/mc.c
@@ -0,0 +1,250 @@
+/*
+ *  mc.c:		Output of motion compensation	
+ *
+ *  Written by:		Michael Unger
+ *			Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "bit-io.h"
+#include "mvcode.h"
+
+#include "mc.h"
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+static unsigned p_frame_codes [4][2] =
+/*
+ *  Code values and bits for P-frame prediction
+ *  NONE,  FORWARD
+ */
+{
+   {1, 1}, {0, 1}, {0, 0}, {0, 0} 
+};
+
+static unsigned b_frame_codes [4][2] =
+/*
+ *  Code values and bits for B-frame prediction
+ *  NONE,  FORWARD,  BACKWARD, INTERPOLATED
+ */
+{
+   {1, 1}, {000, 3}, {001, 3}, {01, 2} 
+};
+
+enum vlc_e {CODE = 0, BITS = 1};
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+encode_mc_tree (unsigned max_state, frame_type_e frame_type, const wfa_t *wfa,
+	       bitfile_t *output);
+static void
+encode_mc_coords (unsigned max_state, const wfa_t *wfa, bitfile_t *output);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+write_mc (frame_type_e frame_type, const wfa_t *wfa, bitfile_t *output)
+{
+   unsigned max_state = wfa->wfainfo->color
+			? wfa->tree[wfa->tree[wfa->root_state][0]][0]
+			: wfa->states;
+
+   encode_mc_tree (max_state, frame_type, wfa, output);
+   encode_mc_coords (max_state, wfa, output);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+encode_mc_tree (unsigned max_state, frame_type_e frame_type, const wfa_t *wfa,
+		bitfile_t *output)
+/*
+ *  Write tree of motion compensation decisions to the 'output' stream.
+ *  Depending on 'frame_type' different decoding methods are used.
+ *  'max_state' is the last state with motion compensation infos.
+ *
+ *  No return value.
+ */
+{
+   unsigned  label;			/* current label */
+   unsigned  state;			/* current state */
+   unsigned  total = 0;			/* number of motion tree decisions */
+   unsigned  queue [MAXSTATES];		/* state numbers in BFO */
+   unsigned  current;			/* current node to process */
+   unsigned  last;			/* last node (update every new node) */
+   mc_type_e type;			/* type of motion compensation */
+   unsigned	     (*mc_tree_codes)[2]; /* pointer to VLC table */
+   unsigned  bits  = bits_processed (output); /* number of bits used */
+   
+   if (frame_type == P_FRAME)
+      mc_tree_codes = p_frame_codes;	/* binary code */
+   else 
+      mc_tree_codes = b_frame_codes;	/* variable length code */
+   
+   /*
+    *  Traverse tree in breadth first order (starting at
+    *  level 'wfa->p_max_level'). Use a queue to store the childs
+    *  of each node ('last' is the next free queue element).  
+    */
+
+   for (last = 0, state = wfa->basis_states; state < max_state; state++)
+      if (wfa->level_of_state [state] - 1 == (int) wfa->wfainfo->p_max_level)
+	 queue [last++] = state;	/* init level = 'mc_max_level' */
+   
+   for (current = 0; current < last; current++)
+      for (label = 0; label < MAXLABELS; label++)
+      {
+	 state = queue [current];
+	 type  = wfa->mv_tree [state][label].type;
+	 if (wfa->x [state][label]
+	     + width_of_level (wfa->level_of_state [state] - 1)
+	     <= wfa->wfainfo->width
+	     &&
+	     wfa->y [state][label]
+	     + height_of_level (wfa->level_of_state [state] - 1)
+	     <= wfa->wfainfo->height)
+	 {
+	    put_bits (output, mc_tree_codes [type][CODE],
+		      mc_tree_codes [type][BITS]);
+	    total++;
+	 }
+	 if (type == NONE && !isrange (wfa->tree [state][label]) &&
+	     wfa->level_of_state [state] - 1 >=
+	     (int) wfa->wfainfo->p_min_level)
+	    queue [last++] = wfa->tree [state][label]; /* append child */
+	 
+      }
+
+   OUTPUT_BYTE_ALIGN (output);
+   debug_message ("mc-tree:      %5d bits. (%5d symbols => %5.2f bps)",
+		  bits_processed (output) - bits, total,
+		  total > 0 ? ((bits_processed (output) - bits) /
+			       (double) total) : 0);
+}
+
+static void
+encode_mc_coords (unsigned max_state, const wfa_t *wfa, bitfile_t *output)
+/*
+ *  Write motion vector coordinates to the 'output' stream. They are stored
+ *  with the static Huffman code of the MPEG and H.263 standards.
+ *  'max_state' is the last state with motion compensation infos.
+ *
+ *  No return value.
+ */
+{
+   unsigned  state;			/* current state */
+   unsigned  label;			/* current label */
+   unsigned  level_count [MAXLEVEL];	/* number of mv per level */
+   unsigned  level;			/* counter */
+   unsigned  ftotal = 0;		/* #forward motion tree decisions */
+   unsigned  btotal = 0;		/* #backward decisions */
+   unsigned  itotal = 0;		/* #interpolated decisions */
+   unsigned  bits   = bits_processed (output); /* number of bits used */
+   unsigned  sr     = wfa->wfainfo->search_range; /* search range */
+   
+   for (level = wfa->wfainfo->p_max_level;
+	level >= wfa->wfainfo->p_min_level; level--)
+      level_count [level] = 0;
+   
+   for (state = wfa->basis_states; state < max_state; state++)
+      for (label = 0; label < MAXLABELS; label++)
+      {
+	 mv_t *mv = &wfa->mv_tree[state][label]; /* motion vector info */
+	 
+	 if (mv->type != NONE)
+	 {
+	    level_count [wfa->level_of_state [state] - 1]++;
+	    switch (mv->type)
+	    {
+	       case FORWARD:
+		  put_bits (output,
+			    mv_code_table[(mv->fx + sr)][CODE],
+			    mv_code_table[(mv->fx + sr)][BITS]);
+		  put_bits (output,
+			    mv_code_table[(mv->fy + sr)][CODE],
+			    mv_code_table[(mv->fy + sr)][BITS]);
+		  ftotal++;
+		  break;
+	       case BACKWARD:
+		  put_bits (output,
+			    mv_code_table[(mv->bx + sr)][CODE],
+			    mv_code_table[(mv->bx + sr)][BITS]);
+		  put_bits (output,
+			    mv_code_table[(mv->by + sr)][CODE],
+			    mv_code_table[(mv->by + sr)][BITS]);
+		  btotal++;
+		  break;
+	       case INTERPOLATED:
+		  put_bits (output,
+			    mv_code_table[(mv->fx + sr)][CODE],
+			    mv_code_table[(mv->fx + sr)][BITS]);
+		  put_bits (output,
+			    mv_code_table[(mv->fy + sr)][CODE],
+			    mv_code_table[(mv->fy + sr)][BITS]);
+		  put_bits (output,
+			    mv_code_table[(mv->bx + sr)][CODE],
+			    mv_code_table[(mv->bx + sr)][BITS]);
+		  put_bits (output,
+			    mv_code_table[(mv->by + sr)][CODE],
+			    mv_code_table[(mv->by + sr)][BITS]);
+		  itotal++;
+		  break;
+	       default:
+		  break;
+	    }
+	 }
+      }
+
+   OUTPUT_BYTE_ALIGN (output);
+   
+   debug_message ("Motion compensation: %d forward, %d backward, "
+		  "%d interpolated", ftotal, btotal, itotal);
+
+   for (level = wfa->wfainfo->p_max_level;
+	level >= wfa->wfainfo->p_min_level; level--)
+      debug_message ("Level %d: %d motion vectors", level, level_count[level]);
+   
+   {
+      unsigned  total = ftotal * 2 + btotal * 2 + itotal * 4;
+
+      debug_message ("mv-coord:     %5d bits. (%5d symbols => %5.2f bps)",
+		     bits_processed (output) - bits, total,
+		     total > 0 ? ((bits_processed (output) - bits) /
+				  (double) total) : 0);
+   }
+
+   return;
+}
diff --git a/converter/other/fiasco/output/mc.h b/converter/other/fiasco/output/mc.h
new file mode 100644
index 00000000..b7843fd8
--- /dev/null
+++ b/converter/other/fiasco/output/mc.h
@@ -0,0 +1,28 @@
+/*
+ *  mc.h
+ *
+ *  Written by:		Michael Unger
+ *			Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _MC_H
+#define _MC_H
+
+#include "wfa.h"
+#include "bit-io.h"
+
+void
+write_mc (frame_type_e frame_type, const wfa_t *wfa, bitfile_t *output);
+
+#endif /* not _MC_H */
+
diff --git a/converter/other/fiasco/output/nd.c b/converter/other/fiasco/output/nd.c
new file mode 100644
index 00000000..a09ff762
--- /dev/null
+++ b/converter/other/fiasco/output/nd.c
@@ -0,0 +1,244 @@
+/*
+ *  nd.c:		Output of prediction tree	
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "arith.h"
+#include "misc.h"
+#include "bit-io.h"
+#include "rpf.h"
+#include "list.h"
+
+#include "nd.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static unsigned
+encode_nd_tree (const wfa_t *wfa, bitfile_t *output);
+static void
+encode_nd_coefficients (unsigned total, const wfa_t *wfa, bitfile_t *output);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+write_nd (const wfa_t *wfa, bitfile_t *output)
+/*
+ *  Write prediction information of 'wfa' to given stream 'output'.
+ *  Coefficients are quantized with model 'p_rpf'.
+ *
+ *  No return value.
+ */
+{
+   unsigned total = encode_nd_tree (wfa, output);
+   
+   if (total > 0)
+      encode_nd_coefficients (total, wfa, output);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static unsigned
+encode_nd_tree (const wfa_t *wfa, bitfile_t *output)
+/*
+ *  Write prediction tree of 'wfa' to given stream 'output'. 
+ *
+ *  No return value.
+ */
+{
+   lqueue_t *queue;			/* queue of states */
+   int	     state, next;		/* state and its current child */
+   unsigned  used, not_used;		/* counter ND used/not used */
+   u_word_t  low;			/* Start of the current code range */
+   u_word_t  high;			/* End of the current code range */
+   u_word_t  underflow;			/* Number of underflow bits pending */
+   u_word_t  sum0, sum1;		/* Probability model */
+   unsigned  bits = bits_processed (output);
+
+   used = not_used = 0;
+   
+   /*
+    *  Initialize arithmetic coder
+    */
+   low       = 0;
+   high      = 0xffff;
+   underflow = 0;
+   sum0      = 1;
+   sum1      = 11;
+   
+   queue = alloc_queue (sizeof (int));
+   state = wfa->root_state;
+   queue_append (queue, &state);
+   
+   /*
+    *  Traverse the WFA tree in breadth first order (using a queue).
+    */
+   while (queue_remove (queue, &next))
+   {
+      unsigned label;
+      
+      if (wfa->level_of_state [next] > wfa->wfainfo->p_max_level + 1)
+      {
+	 /*
+	  *  Nondetermismn is not allowed at levels larger than
+	  *  'wfa->wfainfo->p_max_level'.
+	  */
+	 for (label = 0; label < MAXLABELS; label++)
+	    if (ischild (state = wfa->tree [next][label]))
+	       queue_append (queue, &state); /* continue with childs */
+      }
+      else if (wfa->level_of_state [next] > wfa->wfainfo->p_min_level)
+      {
+	 for (label = 0; label < MAXLABELS; label++)
+	    if (ischild (state = wfa->tree [next][label]))
+	    {
+	       unsigned range;		/* Current interval range */
+
+	       if (isedge (wfa->into [next][label][0])) /* prediction used */
+	       {
+		  used++;
+		  
+		  /*
+		   *  Encode a '1' symbol
+		   */
+		  range =  (high - low) + 1;
+		  low   = low + (u_word_t) ((range * sum0) / sum1);
+		  RESCALE_OUTPUT_INTERVAL;
+	       }
+	       else			/* no predict., continue with childs */
+	       {
+		  not_used++;
+		  if (wfa->level_of_state [state] > wfa->wfainfo->p_min_level)
+		     queue_append (queue, &state);
+		  
+		  /*
+		   *  Encode a '0' symbol
+		   */
+		  range =  (high - low) + 1;
+		  high  = low + (u_word_t) ((range * sum0) / sum1 - 1);
+		  RESCALE_OUTPUT_INTERVAL;
+		  sum0++;
+	       }
+	       /*
+		*  Update the frequency counts
+		*/
+	       sum1++;
+	       if (sum1 > 50)		/* Scale the symbol frequencies */
+	       {
+		  sum0 >>= 1;
+		  sum1 >>= 1;
+		  if (!sum0)
+		     sum0 = 1;
+		  if (sum0 >= sum1)
+		     sum1 = sum0 + 1;
+	       }
+	    }
+	 
+      }
+   }
+   free_queue (queue);
+
+   /*
+    *  Flush the quasi-arithmetic encoder
+    */
+   low = high;
+   RESCALE_OUTPUT_INTERVAL;
+   OUTPUT_BYTE_ALIGN (output);
+
+   debug_message ("%d nd fields: %d used nd, %d used not nd", used + not_used,
+		  used, not_used);
+   {
+      unsigned total = used + not_used;
+      
+      debug_message ("nd-tree:      %5d bits. (%5d symbols => %5.2f bps)",
+		     bits_processed (output) - bits, total,
+		     total > 0 ? ((bits_processed (output) - bits) /
+				  (double) total) : 0);
+   }
+
+   return used;
+}
+
+static void
+encode_nd_coefficients (unsigned total, const wfa_t *wfa, bitfile_t *output)
+/*
+ *  Write #'total' weights of nondeterministic part of 'wfa' to given 'output'
+ *  stream. Coefficients are stored with arithmetic coding (the model is
+ *  given by 'p_rpf').
+ *
+ *  No return value.
+ */
+{
+   unsigned bits = bits_processed (output);
+
+   {
+      unsigned *coefficients;		/* array of factors to encode */
+      unsigned *ptr;			/* pointer to current factor */
+      unsigned	state, label, edge;
+      word_t	domain;
+      
+      ptr = coefficients  = Calloc (total, sizeof (unsigned));
+
+      for (state = wfa->basis_states; state < wfa->states; state++)
+	 for (label = 0; label < MAXLABELS; label++)
+	    if (ischild (wfa->tree [state][label])
+		&& isedge (wfa->into [state][label][0]))
+	       for (edge = 0; isedge (domain = wfa->into [state][label][edge]);
+		    edge++)
+	       {
+		  if (ptr - coefficients >= (int) total)
+		     error ("Can't write more than %d coefficients.", total);
+
+		  *ptr++ = rtob (wfa->weight [state][label][edge],
+				 wfa->wfainfo->dc_rpf);
+	       }
+
+      /*
+       *  Encode array of coefficients with arithmetic coding
+       */
+      {
+	 const int scaling = 50;	/* scaling factor of prob. model */
+	 unsigned  c_symbols = 1 << (wfa->wfainfo->dc_rpf->mantissa_bits + 1);
+
+	 encode_array (output, coefficients, NULL, &c_symbols, 1,
+		       total, scaling);
+      }
+      
+      debug_message ("nd-factors:   %5d bits. (%5d symbols => %5.2f bps)",
+		     bits_processed (output) - bits, total,
+		     total ? ((bits_processed (output) - bits)
+			      / (double) total) : 0);
+      Free (coefficients);
+   }
+}
+
+
diff --git a/converter/other/fiasco/output/nd.h b/converter/other/fiasco/output/nd.h
new file mode 100644
index 00000000..600b3d73
--- /dev/null
+++ b/converter/other/fiasco/output/nd.h
@@ -0,0 +1,27 @@
+/*
+ *  nd.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _ND_H
+#define _ND_H
+
+#include "wfa.h"
+#include "bit-io.h"
+
+void
+write_nd (const wfa_t *wfa, bitfile_t *output);
+
+#endif /* not _ND_H */
+
diff --git a/converter/other/fiasco/output/tree.c b/converter/other/fiasco/output/tree.c
new file mode 100644
index 00000000..0056d7dd
--- /dev/null
+++ b/converter/other/fiasco/output/tree.c
@@ -0,0 +1,176 @@
+/*
+ *  tree.c:		Output of bintree partitioning
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "bit-io.h"
+#include "arith.h"
+#include "misc.h"
+
+#include "tree.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+encode_tree (bitfile_t *output, const byte_t *data, unsigned n_data,
+	     unsigned scaling, u_word_t sum0, u_word_t sum1);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+write_tree (const wfa_t *wfa, bitfile_t *output)
+/*
+ *  Write bintree to stream 'output'.
+ *  Traverse tree in breadth first order and save a '1' for each child
+ *  and a '0' for each range image.
+ *
+ *  No return value.
+ */
+{
+   unsigned  queue [MAXSTATES];		/* state numbers in BFO */
+   unsigned  current;			/* current node to process */
+   unsigned  last;			/* last node (update every new node) */
+   unsigned  label;			/* current label */
+   int	     into;			/* next child */
+   byte_t   *tree_string;		/* bitstring to encode */
+   unsigned  total = 0;			/* number of ranges */
+   unsigned  bits  = bits_processed (output); /* number of bits */
+
+   /*
+    *  Traverse tree in breadth first order. Use a queue to store
+    *  the childs of each node ('last' is the next free queue element).
+    *  The first element ('current') of this queue will get the new parent
+    *  node. 
+    */
+   tree_string = Calloc (MAXSTATES * MAXLABELS, sizeof (byte_t));
+   queue [0] = wfa->root_state;
+   for (last = 1, current = 0; current < last; current++)
+      for (label = 0; label < MAXLABELS; label++)
+	 if (!isrange (into = wfa->tree [queue[current]][label])) /* child ? */
+	 {
+	    queue [last++]        = into;
+	    tree_string [total++] = 1;
+	 }
+	 else				/* or range ? */
+	    tree_string [total++] = 0;
+
+   if (total != (wfa->states - wfa->basis_states) * MAXLABELS)
+      error ("total [%d] != (states - basis_states) * 2 [%d]", total,
+	     (wfa->states - wfa->basis_states) * MAXLABELS);
+   
+   {
+      unsigned scale = total / 20 ;
+
+      encode_tree (output, tree_string, total, scale, 1, 11);
+   }
+
+   Free (tree_string);
+   
+   debug_message ("tree:         %5d bits. (%5d symbols => %5.2f bps)",
+		  bits_processed (output) - bits, total,
+		  total > 0 ? ((bits_processed (output) - bits)
+			       / (double) total) : 0);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+encode_tree (bitfile_t *output, const byte_t *data, unsigned n_data,
+	     unsigned scaling, u_word_t sum0, u_word_t sum1)
+/*
+ *  Encode bintree data with adaptive binary arithmetic coding.
+ *  Write 'n_data' output symbols stored in 'data' to stream 'output'.
+ *  Rescale probability model after every 'scaling' symbols.
+ *  Initial counts are given by 'sum0' and 'sum1'.
+ *
+ *  No return value.
+ */
+{
+   u_word_t low;			/* Start of the current code range */
+   u_word_t high;			/* End of the current code range */
+   u_word_t underflow;			/* Number of underflow bits pending */
+   unsigned n;				/* Data counter */
+
+   low       = 0;
+   high      = 0xffff;
+   underflow = 0;
+
+   for (n = n_data; n; n--)
+   {
+      unsigned range;			/* Current interval range */
+      
+      if (!*data++)
+      {
+	 /*
+	  *  encode a '0'
+	  */
+	 range =  (high - low) + 1;
+	 high  = low + (u_word_t) ((range * sum0) / sum1 - 1);
+
+	 RESCALE_OUTPUT_INTERVAL;
+
+	 sum0++;
+      }
+      else
+      {
+	 /*
+	  *  encode a '1'
+	  */
+	 range =  (high - low) + 1;
+	 low   = low + (u_word_t) ((range * sum0) / sum1);
+
+	 RESCALE_OUTPUT_INTERVAL;
+      }
+      /*
+       *  Update the frequency counts
+       */
+      sum1++;
+      if (sum1 > scaling) /* Scale the symbol frequencies */
+      {
+	 sum0 >>= 1;
+	 sum1 >>= 1;
+	 if (!sum0)
+	    sum0 = 1;
+	 if (sum0 >= sum1)
+	    sum1 = sum0 + 1;
+      }
+   }
+   /*
+    *  Flush the quasi-arithmetic encoder
+    */
+   low = high;
+
+   RESCALE_OUTPUT_INTERVAL;
+
+   OUTPUT_BYTE_ALIGN (output);
+}
diff --git a/converter/other/fiasco/output/tree.h b/converter/other/fiasco/output/tree.h
new file mode 100644
index 00000000..6f8a3800
--- /dev/null
+++ b/converter/other/fiasco/output/tree.h
@@ -0,0 +1,27 @@
+/*
+ *  tree.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _TREE_H
+#define _TREE_H
+
+#include "wfa.h"
+#include "bit-io.h"
+
+void
+write_tree (const wfa_t *wfa, bitfile_t *output);
+
+#endif /* not _TREE_H */
+
diff --git a/converter/other/fiasco/output/weights.c b/converter/other/fiasco/output/weights.c
new file mode 100644
index 00000000..085a1f00
--- /dev/null
+++ b/converter/other/fiasco/output/weights.c
@@ -0,0 +1,200 @@
+/*
+ *  weights.c:		Output of weights
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "wfa.h"
+#include "misc.h"
+#include "bit-io.h"
+#include "arith.h"
+#include "wfalib.h"
+
+#include "weights.h"
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+void
+write_weights (unsigned total, const wfa_t *wfa, bitfile_t *output)
+/*
+ *  Traverse the transition matrices of the 'wfa' and write #'total'
+ *  weights != 0 to stream '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);
+   
+   /*
+    *  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;
+   
+   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++)
+            {
+	       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);
+      
+      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);
+
+   Free (weights_array);
+   Free (level_array);
+}
diff --git a/converter/other/fiasco/output/weights.h b/converter/other/fiasco/output/weights.h
new file mode 100644
index 00000000..271203ad
--- /dev/null
+++ b/converter/other/fiasco/output/weights.h
@@ -0,0 +1,27 @@
+/*
+ *  weights.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:50:31 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef _WEIGHTS_H
+#define _WEIGHTS_H
+
+#include "wfa.h"
+#include "bit-io.h"
+
+void
+write_weights (unsigned total, const wfa_t *wfa, bitfile_t *output);
+
+#endif /* not _WEIGHTS_H */
+
diff --git a/converter/other/fiasco/output/write.c b/converter/other/fiasco/output/write.c
new file mode 100644
index 00000000..e6185ad3
--- /dev/null
+++ b/converter/other/fiasco/output/write.c
@@ -0,0 +1,250 @@
+/*
+ *  write.c:        Output of WFA files
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/07/18 15:44:59 $
+ *  $Author: hafner $
+ *  $Revision: 5.3 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+
+#include "types.h"
+#include "macros.h"
+#include "error.h"
+
+#include "cwfa.h"
+#include "image.h"
+#include "misc.h"
+#include "bit-io.h"
+#include "rpf.h"
+
+#include "tree.h"
+#include "matrices.h"
+#include "weights.h"
+#include "mc.h"
+#include "nd.h"
+#include "write.h"
+ 
+/*****************************************************************************
+
+                prototypes
+  
+*****************************************************************************/
+
+static void
+write_tiling (const tiling_t *tiling, bitfile_t *output);
+
+/*****************************************************************************
+
+                public code
+
+                
+*****************************************************************************/
+
+
+void
+write_next_wfa (const wfa_t *wfa, const coding_t *c, bitfile_t *output)
+/*
+ *  Write 'wfa' to stream 'output'. If the first frame should be written
+ *  then also store the header information of the coding struct 'c'.
+ *
+ *  No return value.
+ */
+{
+   unsigned edges = 0;          /* number of transitions */
+   unsigned bits;
+   
+   debug_message ("--------------------------------------"
+          "--------------------------------------");
+
+   if (c->mt->number == 0)              /* first WFA */
+      write_header (wfa->wfainfo, output);
+  
+   bits = bits_processed (output);
+   
+   /*
+    *  Frame header information
+    */
+   {
+      const int rice_k = 8;     /* parameter of Rice Code */
+
+      write_rice_code (wfa->states, rice_k, output);      
+      write_rice_code (c->mt->frame_type, rice_k, output); 
+      write_rice_code (c->mt->number, rice_k, output);     
+   }
+   
+   OUTPUT_BYTE_ALIGN (output);
+
+   debug_message ("frame-header: %5d bits.", bits_processed (output) - bits);
+
+   if (c->tiling->exponent)     /* write tiling permutation */
+   {
+      put_bit (output, 1);
+      write_tiling (c->tiling, output);
+   }
+   else
+      put_bit (output, 0);
+
+   OUTPUT_BYTE_ALIGN (output);
+
+   write_tree (wfa, output);
+
+   if (c->options.prediction)       /* write nondeterministic approx. */
+   {
+      put_bit (output, 1); 
+      write_nd (wfa, output);
+   }
+   else
+      put_bit (output, 0);
+
+   if (c->mt->frame_type != I_FRAME)    /* write motion compensation info */
+      write_mc (c->mt->frame_type, wfa, output);
+   
+   edges = write_matrices (c->options.normal_domains,
+               c->options.delta_domains, wfa, output);
+
+   if (edges)               /* found at least one approximation */
+      write_weights (edges, wfa, output);
+
+   debug_message ("--------------------------------------"
+          "--------------------------------------");
+}
+
+void
+write_header (const wfa_info_t *wi, bitfile_t *output)
+/*
+ *  Write the header information describing the type of 'wfa'
+ *  to stream 'output'.
+ *
+ *  No return value.
+ */
+{
+   const unsigned rice_k = 8;       /* parameter of Rice Code */
+   unsigned   bits   = bits_processed (output);
+   const char *text;            /* next character to write */
+
+   /*
+    *  Write magic number and name of initial basis
+    */
+   for (text = FIASCO_MAGIC; *text; text++)
+      put_bits (output, *text, 8);
+   put_bits (output, '\n', 8);
+   for (text = wi->basis_name; *text; text++)
+      put_bits (output, *text, 8);
+   put_bits (output, *text, 8);
+   
+   write_rice_code (FIASCO_BINFILE_RELEASE, rice_k, output);
+
+   write_rice_code (HEADER_TITLE, rice_k, output);
+   for (text = wi->title;
+    text && *text && text - wi->title < MAXSTRLEN - 2;
+    text++)
+      put_bits (output, *text, 8);
+   put_bits (output, 0, 8);
+   
+   write_rice_code (HEADER_COMMENT, rice_k, output);
+   for (text = wi->comment;
+    text && *text && text - wi->comment < MAXSTRLEN - 2;
+    text++)
+      put_bits (output, *text, 8);
+   put_bits (output, 0, 8);
+   
+   write_rice_code (HEADER_END, rice_k, output);
+   
+   write_rice_code (wi->max_states, rice_k, output); 
+   put_bit (output, wi->color ? 1 : 0); 
+   write_rice_code (wi->width, rice_k, output);
+   write_rice_code (wi->height, rice_k, output);
+   if (wi->color)
+      write_rice_code (wi->chroma_max_states, rice_k, output); 
+   write_rice_code (wi->p_min_level, rice_k, output); 
+   write_rice_code (wi->p_max_level, rice_k, output); 
+   write_rice_code (wi->frames, rice_k, output);
+   write_rice_code (wi->smoothing, rice_k, output);
+
+   put_bits (output, wi->rpf->mantissa_bits - 2, 3);
+   put_bits (output, wi->rpf->range_e, 2);
+   if (wi->rpf->mantissa_bits != wi->dc_rpf->mantissa_bits ||
+       wi->rpf->range != wi->dc_rpf->range)
+   {
+      put_bit (output, YES);
+      put_bits (output, wi->dc_rpf->mantissa_bits - 2, 3);
+      put_bits (output, wi->dc_rpf->range_e, 2);
+   }
+   else
+      put_bit (output, NO);
+   if (wi->rpf->mantissa_bits != wi->d_rpf->mantissa_bits ||
+       wi->rpf->range != wi->d_rpf->range)
+   {
+      put_bit (output, YES);
+      put_bits (output, wi->d_rpf->mantissa_bits - 2, 3);
+      put_bits (output, wi->d_rpf->range_e, 2);
+   }
+   else
+      put_bit (output, NO);
+   if (wi->dc_rpf->mantissa_bits != wi->d_dc_rpf->mantissa_bits ||
+       wi->dc_rpf->range != wi->d_dc_rpf->range)
+   {
+      put_bit (output, YES);
+      put_bits (output, wi->d_dc_rpf->mantissa_bits - 2, 3);
+      put_bits (output, wi->d_dc_rpf->range_e, 2);
+   }
+   else
+      put_bit (output, NO);
+
+   if (wi->frames > 1)          /* motion compensation stuff */
+   {
+      write_rice_code (wi->fps, rice_k, output); 
+      write_rice_code (wi->search_range, rice_k, output); 
+      put_bit (output, wi->half_pixel ? 1 : 0); 
+      put_bit (output, wi->B_as_past_ref ? 1 : 0);
+   }
+
+   OUTPUT_BYTE_ALIGN (output);
+   debug_message ("header:         %d bits.", bits_processed (output) - bits);
+}
+
+/*****************************************************************************
+
+                private code
+  
+*****************************************************************************/
+
+static void
+write_tiling (const tiling_t *tiling, bitfile_t *output)
+/*
+ *  Write image tiling information given by 'tiling' to stream 'output'.
+ *
+ *  No return value.
+ */
+{
+   const unsigned rice_k = 8;       /* parameter of Rice Code */
+   unsigned       bits   = bits_processed (output);
+   
+   write_rice_code (tiling->exponent, rice_k, output);
+   if (tiling->method == FIASCO_TILING_VARIANCE_ASC
+       || tiling->method == FIASCO_TILING_VARIANCE_DSC)
+   {
+      unsigned tile;            /* current image tile */
+
+      put_bit (output, 1);      
+      for (tile = 0; tile < 1U << tiling->exponent; tile++)
+     if (tiling->vorder [tile] != -1) /* image tile is visible */
+        put_bits (output, tiling->vorder [tile], tiling->exponent);
+   }
+   else
+   {
+      put_bit (output, 0);      
+      put_bit (output, tiling->method == FIASCO_TILING_SPIRAL_ASC);
+   }
+
+   debug_message ("tiling:        %4d bits.", bits_processed (output) - bits);
+}
diff --git a/converter/other/fiasco/output/write.h b/converter/other/fiasco/output/write.h
new file mode 100644
index 00000000..a3ede1f4
--- /dev/null
+++ b/converter/other/fiasco/output/write.h
@@ -0,0 +1,28 @@
+/*
+ *  write.h
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/07/15 17:27:30 $
+ *  $Author: hafner $
+ *  $Revision: 5.2 $
+ *  $State: Exp $
+ */
+
+#ifndef _WRITE_H
+#define _WRITE_H
+
+#include "cwfa.h"
+#include "bit-io.h"
+
+void
+write_next_wfa (const wfa_t *wfa, const coding_t *c, bitfile_t *output);
+void
+write_header (const wfa_info_t *wi, bitfile_t *output);
+
+#endif /* not _WRITE_H */
diff --git a/converter/other/fiasco/params.c b/converter/other/fiasco/params.c
new file mode 100644
index 00000000..3d0a0252
--- /dev/null
+++ b/converter/other/fiasco/params.c
@@ -0,0 +1,727 @@
+/*
+ *  params.c:		Parameter file and command line parsing
+ *
+ *  Written by:		Stefan Frank
+ *			Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/07/15 17:24:21 $
+ *  $Author: hafner $
+ *  $Revision: 5.2 $
+ *  $State: Exp $
+ */
+
+#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>			/* strtod() on SUN sparc */
+
+#include <stdlib.h>
+#include <string.h>
+ 
+#include <getopt.h>			/* system or ../lib */
+
+#include "nstring.h"
+
+#include "types.h"
+#include "macros.h"
+#include "bit-io.h"
+#include "misc.h"
+#include "fiasco.h"
+
+#include "binerror.h"
+
+#include "params.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+read_parameter_file (param_t *params, FILE *file);
+static int
+get_parameter_index (const param_t *params, const char *search_string);
+static void
+set_parameter (param_t *parameter, const char *value);
+static void 
+usage (const param_t *params, const char *progname, const char *synopsis,
+       const char *comment, const char *non_opt_string,
+       bool_t show_all_options, const char *sys_file_name,
+       const char *usr_file_name);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+int
+parseargs (param_t *usr_params, 
+           int argc, char **argv, 
+           const char *synopsis,
+           const char *comment, 
+           const char *non_opt_string, 
+           const char *path,
+           const char *sys_file_name, 
+           const char *usr_file_name)
+/*
+ *  Perform the command line parsing.
+ *  List of allowed parameters is given by 'usr_params'.
+ *  Command line and number of parameters are given by 'argv' and 'argc'.
+ *  'synopsis' contains a brief description of the program and
+ *  'comment' may contain some additional advice.
+ *  Initialization order of parameters:
+ *	1.) Default values given by the param_t struct
+ *	2.) System parameter-file ('path'/'sys_file_name')
+ *	3.) User parameter-file ($HOME/'usr_file_name')
+ *	4.) Command line parameters
+ *	5.) Parameter-file forced by option -f (--config-file)
+ *
+ *  Return value:
+ *	index in ARGV of the first ARGV-element that is not an option.
+ *
+ *  Side effects:
+ *	the elements of ARGV are permuted
+ *      usr_params [].value is modified 
+ */
+{
+   extern int optind;			/* index in ARGV of the 1st element
+					   that is not an option */
+   bool_t     detailed_help = NO;	/* NO if all parameters can be modified
+					   with short options too */
+   unsigned   n1;			/* number of user parameters */
+   unsigned   n2;			/* number of system parameters */
+   bool_t     read_config_file = NO;	/* will override command line */
+   param_t    *params;			/* array of user and system params */
+   param_t    *sys_params;		/* array of system parameters */
+   param_t    detailed_sys_params [] =  /* detailed system parameters */
+   {
+      {"version", NULL, 'v', PFLAG, {0}, NULL,
+       "Print program version number, then exit."},
+      {"verbose", "NUM", 'V', PINT, {0}, "1",
+       "Set level of verbosity to `%s'."},
+      {"config", "FILE", 'f', PSTR, {0}, NULL,
+       "Load `%s' to initialize parameters."},
+      {"info", NULL, 'h', PFLAG, {0}, NULL,
+       "Print brief help, then exit."},
+      {"help", NULL, 'H', PFLAG, {0}, NULL,
+       "Print detailed help, then exit."},
+      {NULL, NULL, 0, PSTR, {0}, NULL, NULL }
+   };
+   param_t    short_sys_params [] =	/* short system parameters */
+   {
+      {"version", NULL, 'v', PFLAG, {0}, NULL,
+       "Print program version number, then exit."},
+      {"verbose", "NUM", 'V', PINT, {0}, "1",
+       "Set level of verbosity to `%s'."},
+      {"config", "FILE", 'f', PSTR, {0}, NULL,
+       "Load `%s' to initialize parameters."},
+      {"help", NULL, 'h', PFLAG, {0}, NULL,
+       "Print this help, then exit."},
+      {NULL, NULL, 0, PSTR, {0}, NULL, NULL }
+   };
+   char *sys_path;			/* path to system config file */
+
+   sys_path = calloc (strlen (path) + strlen (sys_file_name) + 2,
+		      sizeof (char));
+   if (!sys_path)
+      error ("Out of memory.");
+   sprintf (sys_path, "%s/%s", path, sys_file_name);
+
+   /*
+    *  Set parameters defaults
+    */
+   {
+       param_t *p;
+      
+       for (p = usr_params; p->name != NULL; p++)
+       {
+           set_parameter (p, p->default_value);
+           if (p->optchar == '\0')
+               detailed_help = YES;
+       }
+
+      sys_params = detailed_help ? detailed_sys_params : short_sys_params;
+      
+      for (p = sys_params; p->name != NULL; p++)
+          set_parameter (p, p->default_value);
+   }
+   /*
+    *  Append system command line option to user parameters
+    */
+   for (n1 = 0; usr_params [n1].name != NULL; n1++)
+      ;
+   for (n2 = 0; sys_params [n2].name != NULL; n2++)
+      ;
+   params = calloc (n1 + n2 + 1, sizeof (param_t));
+   if (!params)
+      error ("Out of memory.");
+
+   memcpy (params, usr_params, n1 * sizeof (param_t));
+   memcpy (params + n1, sys_params, (n2 + 1) * sizeof (param_t));
+   /*
+    *  Try to open the system resource file 'path'/'sys_file_name'
+    */
+   {
+      FILE *parameter_file = open_file (sys_path, NULL, READ_ACCESS);
+      if (parameter_file == NULL)
+/*
+	 warning ("No system resource file found.");
+*/ {}
+      else
+      {
+	 read_parameter_file (params, parameter_file);
+	 fclose (parameter_file);
+      }
+   }
+   /*
+    *  Try to read user resource file $HOME/'usr_file_name'
+    */
+   {
+      FILE *parameter_file = open_file (usr_file_name, "HOME", READ_ACCESS);
+      if (parameter_file != NULL)
+      {
+	 read_parameter_file (params, parameter_file);
+	 fclose (parameter_file);
+      }
+   }
+   /*
+    *  Parse command line options
+    */
+   {
+      extern char   *optarg;		/* argument of current option */
+      struct option *long_options;	/* array of long options */
+      int	     option_index = 0;
+      char	     optstr [MAXSTRLEN]; /* string containing the legitimate
+					    option characters */
+      int	     optchar;		/* found option character */
+
+      /*
+       *  Build short option string for getopt_long (). 
+       */
+      {
+	 param_t *p;			/* counter */
+	 char	 *ptr_optstr;		/* pointer to position in string */
+	 
+	 ptr_optstr = optstr;
+	 for (p = params; p->name != NULL; p++)
+	    if (p->optchar != '\0')
+	    {
+	       *ptr_optstr++ = p->optchar;
+	       if (p->type == POSTR)
+	       {
+		  *ptr_optstr++ = ':';
+		  *ptr_optstr++ = ':';
+	       }
+	       else if (p->type != PFLAG)
+		  *ptr_optstr++ = ':';
+	    }
+	 *ptr_optstr = '\0';
+      }
+      
+      /*
+       *  Build long option string for getopt_long (). 
+       */
+      {
+	 int i;
+	 
+	 long_options = calloc (n1 + n2 + 1, sizeof (struct option));
+	 if (!long_options)
+	    error ("Out of memory.");
+	 for (i = 0; params [i].name != NULL; i++)
+	 {
+	    long_options [i].name    = params [i].name;
+	    switch (params [i].type)
+	    {
+	       case PFLAG:
+		  long_options [i].has_arg = 0;
+		  break;
+	       case POSTR:
+		  long_options [i].has_arg = 2;
+		  break;
+	       case PINT:
+	       case PSTR:
+	       case PFLOAT:
+	       default:
+		  long_options [i].has_arg = 1;
+		  break;
+	    }
+	    long_options [i].has_arg = params [i].type != PFLAG;
+	    long_options [i].flag    = NULL;
+	    long_options [i].val     = 0;
+	 }
+      }
+      
+      /*
+       *  Parse comand line
+       */
+      while ((optchar = getopt_long (argc, argv, optstr, long_options,
+				     &option_index)) != EOF)
+      {
+	 int param_index = -1;
+	 
+	 switch (optchar)
+	 {
+	    case 0:
+	       param_index = option_index;
+	       break;
+	    case ':':
+	       if (detailed_help)
+		  fprintf (stderr,
+			   "Try `%s -h' or `%s --help' for "
+			   "more information.\n",
+			   argv [0], argv [0]);
+	       else
+		  fprintf (stderr, "Try `%s --help' for more information.\n",
+			   argv [0]);
+	       exit (2);
+	       break;
+	    case '?':
+	       if (detailed_help)
+		  fprintf (stderr,
+			   "Try `%s -h' or `%s --help' "
+			   "for more information.\n",
+			   argv [0], argv [0]);
+	       else
+		  fprintf (stderr, "Try `%s --help' for more information.\n",
+			   argv [0]);
+	       exit (2);
+	       break;
+	    default:
+	       {
+		  int i;
+		  
+		  for (i = 0; params [i].name != NULL; i++)
+		     if (params [i].optchar == optchar)
+		     {
+			param_index = i;
+			break;
+		     }
+	       }
+	 }
+	 /*
+	  *  Check for system options
+	  */
+	 if (param_index >= 0)
+	 {
+	    set_parameter (params + param_index, optarg ? optarg : "");
+	    if (streq (params [param_index].name, "help"))
+	       usage (params, argv [0], synopsis, comment, non_opt_string,
+		      YES, sys_path, usr_file_name);
+	    else if (streq (params [param_index].name, "info"))
+	       usage (params, argv [0], synopsis, comment, non_opt_string,
+		      NO, sys_path, usr_file_name);
+	    else if (streq (params [param_index].name, "version"))
+	    {
+	       fprintf (stderr, "%s " VERSION "\n", argv [0]);
+	       exit (2);
+	    }
+	    else if (streq (params [param_index].name, "verbose"))
+	       fiasco_set_verbosity (
+               * (fiasco_verbosity_e *) parameter_value (params,
+                                                         "verbose"));
+	    else if (streq (params [param_index].name, "config"))
+	       read_config_file = YES;
+	    param_index = -1;		/* clear index flag */
+	 }
+      }
+
+      free (long_options);
+   }
+   
+   /*
+    *  Read config-file if specified by option -f
+    */
+   if (read_config_file)
+   {
+      char *filename;
+
+      if ((filename = (char *) parameter_value (params, "config")) != NULL)
+      {
+	 FILE *parameter_file;		/* input file */
+	 
+	 warning ("Options set in file `%s' will override"
+		  " command line options.", filename);
+	 parameter_file = open_file (filename, NULL, READ_ACCESS);
+	 if (parameter_file != NULL)
+	 {
+	    read_parameter_file (params, parameter_file);
+	    fclose (parameter_file);
+	 }
+	 else
+	    file_error (filename);
+      }
+      else
+	 error ("Invalid config filename.");
+   }
+
+   memcpy (usr_params, params, n1 * sizeof (param_t)); /* fill user struct */
+   free (sys_path);
+   
+   return optind;
+}
+ 
+void *
+parameter_value (const param_t *params, const char *name)
+/*
+ *  Extract value of parameter 'name.' of the given parameters 'params'.
+ *
+ *  Return value:
+ *	value of given parameter
+ */
+{
+   int pind = get_parameter_index (params, name);
+
+   if (pind < 0)
+      error ("Invalid parameter `%s'.", name);
+
+   if (params [pind].type == PSTR || params [pind].type == POSTR)
+      return (void *) params [pind].value.s;
+      
+   return (void *) &(params [pind].value);
+}
+
+void
+ask_and_set (param_t *params, const char *name, const char *msg)
+/*
+ *  Ask user (print given message 'msg') for missing mandatory
+ *  parameter 'name' of the given parameters 'params'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'params ['name'].value' is changed
+ */
+{ 
+   char answer [MAXSTRLEN];
+   int  index = get_parameter_index (params, name);
+
+   if (index < 0)
+      error ("Invalid parameter %s.", name);
+
+   if (msg)
+      fprintf (stderr, "%s\n", msg);
+  
+   switch (params [index].type)
+   {
+      case PFLAG:			/* Unusual, at least. */
+	 warning ("Flags should be initialized and set on demand, "
+		  "not request");
+      case PINT:
+      case PSTR:
+      case POSTR:
+      case PFLOAT:
+	 scanf (MAXSTRLEN_SCANF, answer);
+	 set_parameter (&params [index], answer);
+	 break;
+      default:
+	 error ("Invalid parameter type for %s", name);
+   }
+} 
+
+void
+write_parameters (const param_t *params, FILE *output)
+/*
+ *  Write all parameter settings to 'output'.
+ *
+ *  No return value.
+ */
+{
+   int pind;
+
+   if (!params || !output)
+      error ("Parameters must be not NULL.");
+
+   for (pind = 0; params [pind].name != NULL; pind++)
+   {
+      fprintf (output, "# %s = ", params [pind].name);
+      switch (params [pind].type)
+      {
+	 case PFLAG:
+	    fprintf (output, "%s\n", params [pind].value.b ? "TRUE" : "FALSE");
+	    break;
+	 case PINT:
+	    fprintf (output, "%d\n", params [pind].value.i);
+	    break;
+	 case PFLOAT:
+	    fprintf (output, "%.4f\n", (double) params [pind].value.f);
+	    break;
+	 case PSTR:
+	 case POSTR:
+	    fprintf (output, "%s\n", params [pind].value.s);
+	    break;
+	 default:
+	    error ("Invalid type %d for parameter %s",
+		   params [pind].type, params [pind].name);
+      }
+   }
+   fputc ('\n', output);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+set_parameter (param_t *parameter, const char *value)
+/*
+ *  Set value of 'parameter' to 'value'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'parameter.value' is changed accordingly
+ */
+{
+   assert (parameter);
+   
+   switch (parameter->type)
+   {
+      case PFLAG:
+	 if (value != NULL && *value != '\0')
+	 {
+	    if (strcaseeq (value, "TRUE"))
+	       parameter->value.b = YES;
+	    else if (strcaseeq (value, "FALSE"))
+	       parameter->value.b = NO;
+	    else if (strcaseeq (value, "YES"))
+	       parameter->value.b = YES;
+	    else if (strcaseeq (value, "NO"))
+	       parameter->value.b = NO;
+	    else
+	    {
+	       long int	data;
+	       char	*endptr;
+	    
+	       data = strtol (value, &endptr, 0);
+	       if (*endptr != '\0' || endptr == value)
+		  warning ("Invalid value `%s' converted to %d",
+			   value, (int) data);
+	       parameter->value.b = data ? YES : NO;
+	    }
+	 }
+	 else
+	    parameter->value.b = !parameter->value.b;
+	 break;
+      case PINT:
+	 {
+	    long int  data;
+	    char     *endptr;
+	    
+	    data = strtol (value, &endptr, 0);
+	    if (*endptr != '\0' || endptr == value)
+	       warning ("Invalid value `%s' converted to %d",
+			value, (int) data);
+	    parameter->value.i = data;
+	 }
+	 break;
+      case PFLOAT:
+	 {
+	    double	data;
+	    char	*endptr;
+	    
+	    data = strtod (value, &endptr);
+	    if (*endptr != '\0' || endptr == value)
+	       warning ("Invalid value `%s' converted to %f",
+			value, (double) data);
+	    parameter->value.f = data;
+	 }
+	 break;
+      case PSTR:
+      case POSTR:
+	 parameter->value.s = value ? strdup (value) : NULL;
+	 break;
+      default:				
+	 error ("Invalid parameter type for %s", parameter->name);
+   }
+}
+
+static int
+get_parameter_index (const param_t *params, const char *search_string)
+/*
+ *  Search for parameter with name 'search_string' in parameter struct.
+ *
+ *  Return value:
+ *	index of parameter or -1 if no matching parameter has been found
+ */
+{
+   int n;
+   int index = -1;
+
+   assert (params && search_string);
+
+   for (n = 0; params [n].name != NULL; n++)
+      if (strcaseeq (params [n].name, search_string))
+      {
+	 index = n;
+	 break;
+      }
+
+   return index;
+}
+
+static void
+read_parameter_file (param_t *params, FILE *file)
+/*
+ *  Read parameter settings from 'file'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'params [].value' are changed if specified in 'file'
+ */
+{
+   char buffer [MAXSTRLEN];
+   int  n = 0;
+
+   assert (params && file);
+
+   while (fgets (buffer, MAXSTRLEN, file) != NULL)
+   {
+      char *b;				/* temporary variable */
+      char *name;			/* parameter name */
+      char *value;			/* parameter value */
+      int   pind;			/* current argument number */
+      
+      b = strchr (buffer, '#');
+      if (b != NULL)			/* Strip comments. */
+	 *b = '\0';
+
+      b = strchr (buffer, '=');
+      if (b == NULL)			/* Strip lines that contain no '=' */
+	 continue;
+      *b = '\0';			/* Replace '=' by string terminator */
+
+      /*
+       *  Extract value of parameter
+       */
+      for (value = b + 1; ISSPACE (*value); value++) 
+	 ;				/* Delete leading spaces */
+
+      for (b = value + strlen (value) - 1; b >= value && ISSPACE (*b); b--)
+	 *b = '\0';			/* Delete trailing spaces. */
+
+      /*
+       *  Extract parameter name
+       */
+      for (name = buffer; ISSPACE (*name); name++) 
+	 ;				/* Delete leading spaces */
+
+      for (b = name + strlen (name) - 1; b >= name && ISSPACE (*b); b--)
+	 *b = '\0';			/* Delete trailing spaces. */
+
+      pind = get_parameter_index (params, name);
+      if (pind >= 0)
+	 set_parameter (&params [pind], value);
+      
+      n++;
+   }
+}   
+
+static void 
+usage (const param_t *params, const char *progname, const char *synopsis,
+       const char *comment, const char *non_opt_string,
+       bool_t show_all_options, const char *sys_file_name,
+       const char *usr_file_name)
+/*
+ *  Generates and prints command line description from param_t struct 'params'.
+ *  'progname' is the name of the excecutable, 'synopsis' a short program
+ *  description, and 'comment' some more advice.
+ *  If flag 'show_all_options' is set then print also options that are not
+ *  associated with a short option character.
+ *  'sys_file_name' and 'usr_file_name' are filenames to parameter files.
+ *
+ *  No return value.
+ */
+{
+   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);
+      }
+   
+   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);
+	 
+	 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/params.h b/converter/other/fiasco/params.h
new file mode 100644
index 00000000..810a9ff0
--- /dev/null
+++ b/converter/other/fiasco/params.h
@@ -0,0 +1,61 @@
+/*
+ *  params.h
+ *
+ *  Written by:     Stefan Frank
+ *          Ullrich Hafner
+ *      
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/06/14 20:51:17 $
+ *  $Author: hafner $
+ *  $Revision: 5.1 $
+ *  $State: Exp $
+ */
+
+#ifndef PARAMS_H
+#define PARAMS_H
+
+#include <stdio.h>
+
+typedef union pdata_t           /* Allow for different */
+{                   /* parameter types. */
+    int    b;
+    int    i;
+    float  f;
+    char  *s;
+} pdata_t;
+
+typedef enum {PFLAG = 1, PINT, PFLOAT, PSTR, POSTR} param_e;
+
+typedef struct param_t
+{
+    const char  *name;           /* Parameter name */
+    const char  *argument_name;      /* Argument name */
+    char         optchar;            /* Corresponding command line switch */
+    param_e      type;           /* Parameter type */
+    pdata_t      value;          /* Parameter value */
+    const char  *default_value;      /* Parameters default value */
+    const char  *use;            /* One line usage. Must contain %s,
+                                    which will be replaced by 'name'. */
+} param_t;
+
+int
+parseargs (param_t *usr_params, 
+           int argc, char **argv, 
+           const char *synopsis,
+           const char *comment, 
+           const char *non_opt_string, 
+           const char *path,
+           const char *sys_file_name, 
+           const char *usr_file_name);
+void
+write_parameters (const param_t *params, FILE *output);
+void
+ask_and_set (param_t *params, const char *name, const char *msg);
+void *
+parameter_value (const param_t *params, const char *name);
+
+#endif /* not PARAMS_H */
diff --git a/converter/other/fiasco/pnmtofiasco.c b/converter/other/fiasco/pnmtofiasco.c
new file mode 100644
index 00000000..2218256d
--- /dev/null
+++ b/converter/other/fiasco/pnmtofiasco.c
@@ -0,0 +1,411 @@
+/*
+ *  cwfa.c:		FIASCO coder
+ *
+ *  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 <hafner@bigfoot.de>
+ */
+ 
+/*
+ *  $Date: 2000/10/28 17:39:29 $
+ *  $Author: hafner $
+ *  $Revision: 5.4 $
+ *  $State: Exp $
+ */
+
+#include "config.h"
+#include "pnm.h"
+
+#if STDC_HEADERS
+#	include <stdlib.h>
+#	include <string.h>
+#else /* not STDC_HEADERS */
+#	if HAVE_STRING_H
+#		include <string.h>
+#	else /* not HAVE_STRING_H */
+#		include <strings.h>
+#	endif /* not HAVE_STRING_H */
+#endif /* not STDC_HEADERS */
+
+#include "types.h"
+#include "macros.h"
+
+#include "binerror.h"
+#include "misc.h"
+#include "params.h"
+#include "fiasco.h"
+
+/*****************************************************************************
+
+			     local variables
+  
+*****************************************************************************/
+
+static param_t params [] =
+{
+  /*
+   *  Options for standard user
+   */
+  {"image-name", "FILE", 'i', PSTR, {0}, NULL,
+   "Compress raw PPM/PGM image(s) `%s'."},
+  {"output-name", "FILE", 'o', PSTR, {0}, "-",
+   "Write automaton to `%s' (`-' means stdout)."},
+  {"quality", "REAL", 'q', PFLOAT, {0}, "20.0",
+   "Set quality of compression to `%s'."},
+  {"title", "NAME", 't', PSTR, {0}, "",
+   "Set title of FIASCO stream to `%s'."},
+  {"comment", "NAME", 'c', PSTR, {0}, "",
+   "Set comment of FIASCO stream to `%s'."},
+  {"chroma-qfactor", "REAL", '\0', PFLOAT, {0}, "2",
+   "Decrease chroma band quality `%s' times."},
+  {"basis-name", "FILE", '\0', PSTR, {0}, "small.fco",
+   "Preload basis `%s' into FIASCO."},
+  {"optimize", "NUM", 'z', PINT, {0}, "0",
+   "Set optimization level to `%s'."},
+  {"dictionary-size", "NUM", '\0', PINT, {0}, "10000",
+   "Set max# size of dictionary to `%s'."},
+  {"chroma-dictionary", "NUM", '\0', PINT, {0}, "40",
+   "Set max# size of chroma dictionary to `%s'.."},
+  {"min-level", "NUM", '\0', PINT, {0}, "6",
+   "Start prediction on block level `%s'."},
+  {"max-level", "NUM", '\0', PINT, {0}, "10",
+   "Stop prediction on block level `%s'."},
+  {"tiling-exponent", "NUM", '\0', PINT, {0}, "4",
+   "Set exponent of image permutation to `%s'."},
+  {"tiling-method", "NAME", '\0', PSTR, {0}, "desc-variance",
+   "Set type of permutation to `%s'."},
+  {"rpf-range", "REAL", '\0', PFLOAT, {0}, "1.5",
+   "Set quantization range to `%s'."},
+  {"rpf-mantissa", "NUM", '\0', PINT, {0}, "3",
+   "Set quantization mantissa to `%s' bits."},
+  {"dc-rpf-range", "REAL", '\0', PFLOAT, {0}, "1",
+   "Set quant. range (DC part) to `%s'."},
+  {"dc-rpf-mantissa", "NUM", '\0', PINT, {0}, "5",
+   "Set quant. mantissa (DC part) to `%s' bits."},
+  {"pattern", "NAME", '\0', PSTR, {0}, "ippppppppp",
+   "Set frame type sequence to `%s'."},
+  {"fps", "NUM", '\0', PINT, {0}, "25",
+   "Set display rate to `%s' frames per second."},
+  {"half-pixel", NULL, '\0', PFLAG, {0}, "FALSE",
+   "Use half-pixel precision for mc."},
+  {"cross-B-search", NULL, '\0', PFLAG, {0}, "FALSE",
+   "Use cross-B-search for interpolated mc."},
+  {"B-as-past-ref", NULL, '\0', PFLAG, {0}, "FALSE",
+   "Use B-frames as reference images." },
+  {"prediction", NULL, '\0', PFLAG, {0}, "FALSE",
+   "Use additional predictive coding."},
+  {"progress-meter", "NUM", '\0', PINT, {0}, "2",
+   "Set type of progress meter to `%s'."},
+  {"smooth", "NUM", '\0', PINT, {0}, "70",
+   "Smooth image(s) by factor `%s' (0-100)"},
+#if 0
+  /*
+   *  Options currently not activated (maybe in future versions of FIASCO)
+   */
+  {"min-level", "NUM", 'm', PINT, {0}, "4",
+   "Start compression on block level `%s'."},
+  {"max-level", "NUM", 'M', PINT, {0}, "12",
+   "Stop compression on block level `%s'."},
+  {"max-elements", "NUM", 'N', PINT, {0}, "8",
+   "Set max# of elements in an approx. to `%s'." },
+  {"domain-pool", "NAME", '\0', PSTR, {0}, "rle",
+   "Set domain pool of r-lc to `%s'."},
+  {"coeff", "NAME", '\0', PSTR, {0}, "adaptive",
+   "Set coefficients model to `%s'."},
+  /*  DELTA APPROXIATION  */
+  {"d-domain-pool", "NAME", '\0', PSTR, {0}, "rle",
+   "Set domain pool of d-lc to `%s'."},
+  {"d-coeff", "NAME", '\0', PSTR, {0}, "adaptive",
+   "Set d coefficients model to `%s'."},
+  {"d-range", "REAL", '\0', PFLOAT, {0}, "1.5",
+   "Set range of RPF for delta lc to `%s'."},
+  {"d-mantissa", "NUM", '\0', PINT, {0}, "3",
+   "Set #m-bits of RPF for delta lc to `%s'."},
+  {"d-dc-range", "REAL", '\0', PFLOAT, {0}, "1",
+   "Set DC range of RPF of delta lc to `%s'."},
+  {"d-dc-mantissa", "NUM", '\0', PINT, {0}, "5",
+   "Set #m-bits of delta RPF for DC domain to `%s'."},
+  /*  ADVANCED  */
+  {"images-level", "NUM", '\0', PINT, {0}, "5",
+   "Compute state images up to level `%s'."},
+  {"delta-domains", NULL, '\0', PFLAG, {0}, "FALSE",
+   "Use delta domains every time."},
+  {"normal-domains", NULL, '\0', PFLAG, {0}, "FALSE",
+   "Use normal domains every time."},
+  /*  VIDEO COMPRESSION  */
+  {"smooth", "REAL", 's', PFLOAT, {0}, "1.0",
+   "Smooth frames by factor `%s' (0.5 - 1.0)"},
+  {"reference-frame", "FILE", '\0', PSTR, {0}, NULL,
+   "Use PPM/PGM image `%s' as reference frame."},
+#endif  
+  {NULL, NULL, 0, PSTR, {0}, NULL, NULL }
+};
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void 
+checkargs (int argc, char **argv, char const ***image_template,
+	   char **wfa_name, float *quality, fiasco_c_options_t **options);
+
+/*****************************************************************************
+
+				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 */
+   
+   pnm_init(&argc, argv);
+   
+   init_error_handling (argv [0]);
+
+   checkargs (argc, argv, &image_template, &wfa_name, &quality, &options);
+
+   if (fiasco_coder (image_template, wfa_name, quality, options))
+      return 0;
+   else
+   {
+      fprintf (stderr, fiasco_get_error_message ());
+      fprintf (stderr, "\n");
+      return 1;
+   }
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void 
+checkargs (int argc, char **argv, char const ***image_template,
+	   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
+ *  
+ *
+ *  Side effects:
+ *	'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 */
+   
+   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): ");
+   }
+   
+   if (optind < argc)			/* Additional command line param */
+   {
+      if (image_name)
+	 error ("Multiple image_template arguments."
+		"\nOption -i %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 ();
+      
+      {
+	 char *pattern = (char *) parameter_value (params, "pattern");
+
+	 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 ());
+      }
+
+      {
+	 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 ());
+      }
+      
+      {
+	 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;
+      
+          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 *c = (char *) parameter_value (params, "comment");
+
+	 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");
+
+	 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 ());
+      }
+      
+      {
+	 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 (fiasco_get_verbosity () == FIASCO_ULTIMATE_VERBOSITY)
+	 write_parameters (params, stderr);
+   }
+}	
diff --git a/converter/other/fiasco/system.fiascorc b/converter/other/fiasco/system.fiascorc
new file mode 100644
index 00000000..86ff2da2
--- /dev/null
+++ b/converter/other/fiasco/system.fiascorc
@@ -0,0 +1,120 @@
+#
+#  system.wfarc:	Resource file WFA coder
+# 
+#  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 <hafner@bigfoot.de>
+
+#
+#  $Date: 2000/06/25 16:38:01 $
+#  $Author: hafner $
+#  $Revision: 5.2 $
+#  $State: Exp $
+
+#
+# Options for FIASCO coder `cfiasco':
+#
+
+# Initial basis to start with
+# small.fco:  domains 1, x, y
+# medium.fco: domains 1, x, y and 129 additional images
+# large.fco: domains 1, x, y and 226 additional images
+basis-name = small.fco
+
+# Limit the number of elements in the dictionary by `dictionary-size' 
+# The smaller the value is the faster the coder runs and the worse
+# the image quality will be.  
+dictionary-size = 10000
+
+# Optimization level
+#  0: standard approximation method, process blocks of level [6, 10],
+#     use up to 3 dictionary vectors
+#  1: standard approximation method, process blocks of level [4, 12],
+#     use up to 5 dictionary vectors
+#  2: significantly increases the approximation quality,
+#     running time is twice as high as with the standard method
+#  3: hardly increases the approximation quality of method 2, 
+#     running time is twice as high as with method 21
+#     (this method just remains for completeness)
+optimize = 0
+
+# Approximation quality (typical range = [1-100]) 
+quality = 20.0                    
+
+# For compression of chroma bands the dictionary can be reduced to
+# the best #`chroma-dictionary' elements.
+# Furthermore, the quality of the approximation is decreased
+# 'chroma-qfactor' times.
+chroma-dictionary = 40
+chroma-qfactor    = 2
+
+# Verbosity level
+# 0 no debug output
+# 1 some verbosity and statistics of the output size
+# 2 lots of debug information and log-files are written
+verbose = 1
+
+# Set exponent and method of image tiling
+# 0   image is processed in normal bintree order
+# >0  image is subdivided into 2^`tiling-exponent' tiles. 
+# Set type of image tiling
+# asc-variance  Tiles with large variances are processed first
+# desc-variance Tiles with small variances are processed first
+# asc-spiral    Tiles are process in spiral order starting in the middle
+# desc-spiral   Tiles are process in spiral order starting at the border
+tiling-exponent = 4
+tiling-method   = desc-variance
+
+# Quantization parameters define the accuracy of coefficients quantization.
+# DC coefficients (of the constant dictionary vector f(x,y) = 1) are quantized
+# to values of the interval [-`dc-rpf-range', `dc-rpf-range'] using
+# #`dc-rpf-mantissa' bits. All other quantized coefficients are quantized in
+# an analogous way using the parameters `rpf-range' and `rpf-mantissa'.
+rpf-mantissa    = 3
+rpf-range       = 1.5
+dc-rpf-mantissa = 5
+dc-rpf-range    = 1
+
+# Search for prediction (coarse approximation or motion compensation)
+# on all levels between minlevel and maxlevel
+min-level = 6
+max-level = 10
+
+# Set various parameters used for video compensation.
+# 'fps' defines the frame rate which should be
+# used when the video is decoded. This value has no effect during coding,
+# it is just passed to the FIASCO output file.
+# If 'half-pixel' is set then half pixel precise
+# motion compensated prediction is used.
+# If 'cross-B-search' is set then the fast Cross-B-Search algorithm is
+# used to determine the motion vectors of interpolated prediction. Otherwise
+# exhaustive search (in the given search range) is used.
+# If 'B-as-past-ref' is set then B frames are allowed to be used
+# for B frame predicion.
+fps            = 25
+half-pixel     = NO
+cross-B-search = NO
+B-as-past-ref  = NO
+
+# Set `pattern' of input frames.
+# `pattern' has to be a sequence of the following
+# characters (case insensitive):
+# 'i' intra frame
+# 'p' predicted frame
+# 'b' bidirectional predicted frame
+# E.g. pattern = 'IBBPBBPBB'
+#
+# When coding video frames the prediction type of input frame N is determined
+# by reading `pattern' [N] (`pattern' is periodically extended).
+
+pattern = ippppppppp
+
+#
+# Options for FIASCO decoder `dfiasco':
+#
+
+double  = NO
+reduced = NO
+panel   = NO
+enlarge = 0
diff --git a/converter/other/fitstopnm.c b/converter/other/fitstopnm.c
new file mode 100644
index 00000000..796ca489
--- /dev/null
+++ b/converter/other/fitstopnm.c
@@ -0,0 +1,494 @@
+ /* fitstopnm.c - read a FITS file and produce a portable anymap
+ **
+ ** Copyright (C) 1989 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.
+ **
+ ** Hacked up version by Daniel Briggs  (dbriggs@nrao.edu)  20-Oct-92
+ **
+ ** Include floating point formats, more or less.  Will only work on
+ ** machines that understand IEEE-754.  Added -scanmax -printmax
+ ** -min -max and -noraw.  Ignore axes past 3, instead of error (many packages
+ ** use pseudo axes).  Use a finite scale when max=min.  NB: Min and max
+ ** are the real world FITS values (scaled), so watch out when bzer & bscale
+ ** are not 0 & 1.  Datamin & datamax interpreted correctly in scaled case,
+ ** and initialization changed to less likely values.  If datamin & max are
+ ** not present in the header, the a first pass is made to determine them
+ ** from the array values.
+ **
+ ** Modified by Alberto Accomazzi (alberto@cfa.harvard.edu), Dec 1, 1992.
+ **
+ ** Added understanding of 3-plane FITS files, the program is renamed
+ ** fitstopnm.  Fixed some non-ansi declarations (DBL_MAX and FLT_MAX
+ ** replace MAXDOUBLE and MAXFLOAT), fixed some scaling parameters to
+ ** map the full FITS data resolution to the maximum PNM resolution,
+ ** disabled min max scanning when reading from stdin.
+ */
+
+#include <string.h>
+
+#include "pm_c_util.h"
+#include "pnm.h"
+
+/* Do what you have to, to get a sensible value here.  This may not be so */
+/* portable as the rest of the program.  We want to use MAXFLOAT and */
+/* MAXDOUBLE, so you could define them manually if you have to. */
+/* #include <values.h> */
+#include <float.h>
+
+struct FITS_Header {
+  int simple;       /* basic format or not */
+  int bitpix;       /* number of bits per pixel */
+  int naxis;        /* number of axes */
+  int naxis1;       /* number of points on axis 1 */
+  int naxis2;       /* number of points on axis 2 */
+  int naxis3;       /* number of points on axis 3 */
+  double datamin;   /* min # (Physical value!) */
+  double datamax;   /* max #     "       "     */
+  double bzer;      /* Physical value = Array value*bscale + bzero */
+  double bscale;
+};
+
+static void read_fits_header ARGS(( FILE* fp, struct FITS_Header* hP ));
+static void read_card ARGS(( FILE* fp, char* buf ));
+static void read_val ARGS(( FILE* fp, int bitpix, double* vp ));
+     
+
+
+static void
+scanImageForMinMax(FILE *       const ifP,
+                   unsigned int const images,
+                   int          const cols,
+                   int          const rows,
+                   unsigned int const bitpix,
+                   double       const bscale,
+                   double       const bzer,
+                   unsigned int const imagenum,
+                   bool         const multiplane,
+                   double *     const dataminP,
+                   double *     const datamaxP) {
+
+    double dmax, dmin;
+    unsigned int image;
+    pm_filepos rasterPos;
+    double fmaxval;
+    
+    pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
+
+    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);
+    }
+
+    dmax = -fmaxval;
+    dmin = fmaxval;
+    for (image = 1; image <= images; ++image) {
+        unsigned int row;
+        for (row = 0; row < rows; ++row) {
+            unsigned int col;
+            for (col = 0; col < cols; ++col) {
+                double val;
+                read_val(ifP, bitpix, &val);
+                if (image == imagenum || multiplane ) {
+                    dmax = MAX(dmax, val);
+                    dmin = MIN(dmin, val);
+                }
+            }
+        }
+        if (bscale < 0.0) {
+            double const origDmax = dmax;
+            dmax = dmin;
+            dmin = origDmax;
+        }
+    }
+    *dataminP = dmin * bscale + bzer;
+    *datamaxP = dmax * bscale + bzer;
+
+    pm_message("Scan results: min=%f max=%f", *dataminP, *datamaxP);
+
+    pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
+}
+
+
+
+static void
+computeMinMax(FILE *             const ifP,
+              unsigned int       const images,
+              int                const cols,
+              int                const rows,
+              struct FITS_Header const h,
+              unsigned int       const imagenum,
+              bool               const multiplane,
+              bool               const forcemin,
+              bool               const forcemax,
+              double             const frmin,
+              double             const frmax,
+              double *           const dataminP,
+              double *           const datamaxP) {
+
+    double datamin, datamax;
+
+    datamin = -DBL_MAX;  /* initial assumption */
+    datamax = DBL_MAX;   /* initial assumption */
+
+    if (forcemin)
+        datamin = frmin;
+    if (forcemax)
+        datamax = frmax;
+
+    if (datamin == -DBL_MAX)
+        datamin = h.datamin;
+    if (datamax == DBL_MAX)
+        datamax = h.datamax;
+
+    if (datamin == -DBL_MAX || datamax == DBL_MAX) {
+        double scannedDatamin, scannedDatamax;
+        scanImageForMinMax(ifP, images, cols, rows, h.bitpix, h.bscale, h.bzer,
+                           imagenum, multiplane,
+                           &scannedDatamin, &scannedDatamax);
+
+        if (datamin == -DBL_MAX)
+            datamin = scannedDatamin;
+        if (datamax == DBL_MAX)
+            datamax = scannedDatamax;
+    }
+    *dataminP = datamin;
+    *datamaxP = datamax;
+}
+
+
+
+int
+main(int argc, char * argv[]) {
+
+    FILE* ifp;
+    int argn, imagenum, image, row;
+    register int col;
+    xelval maxval;
+    double val, frmin, frmax, scale, t;
+    double datamin, datamax;
+    int rows, cols, images, format;
+    struct FITS_Header h;
+    xel** pnmarray;
+    xelval tx, txv[4];
+    const char* fits_name;
+    const char* const usage = "[-image N] [-scanmax] [-printmax] [-min f] [-max f] [FITSfile]";
+
+    int doscan = 0;
+    int forceplain = 0;
+    int forcemin = 0;
+    int forcemax = 0;
+    int printmax = 0;
+    bool multiplane;
+  
+    pnm_init( &argc, argv );
+  
+    argn = 1;
+    imagenum = 0;
+  
+    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
+    {
+        if ( pm_keymatch( argv[argn], "-image", 2 ) )
+        {
+            ++argn;
+            if ( argn == argc || sscanf( argv[argn], "%d", &imagenum ) != 1 )
+                pm_usage( usage );
+        }
+        else if ( pm_keymatch( argv[argn], "-max", 3 ) )
+        {
+            ++argn;
+            forcemax = 1;
+            if ( argn == argc || sscanf( argv[argn], "%lf", &frmax ) != 1 )
+                pm_usage( usage );
+        }
+        else if ( pm_keymatch( argv[argn], "-min", 3 ) )
+        {
+            ++argn;
+            forcemin = 1;
+            if ( argn == argc || sscanf( argv[argn], "%lf", &frmin ) != 1 )
+                pm_usage( usage );
+        }
+        else if ( pm_keymatch( argv[argn], "-scanmax", 2 ) )
+            doscan = 1;
+        else if ( pm_keymatch( argv[argn], "-noraw", 2 ) )
+            /* This is for backward compatibility only.  Use the common option
+               -plain now.  (pnm_init() processes -plain).
+            */
+            forceplain = 1;
+        else if ( pm_keymatch( argv[argn], "-printmax", 2 ) )
+            printmax = 1;
+        else
+            pm_usage( usage );
+        ++argn;
+    }
+  
+    if ( argn < argc )
+    {
+        fits_name = argv[argn];
+        ++argn;
+    }
+    else
+        fits_name = "-";
+
+    if ( argn != argc )
+        pm_usage( usage );
+
+    ifp = pm_openr_seekable(fits_name);
+  
+    read_fits_header( ifp, &h );
+  
+    if ( ! h.simple )
+        pm_error( "FITS file is not in simple format, can't read" );
+    if ( h.naxis != 2 && h.naxis != 3 )
+        pm_message( "Warning: FITS file has %d axes", h.naxis );
+    cols = h.naxis1;
+    rows = h.naxis2;
+    if ( h.naxis == 2 )
+        images = imagenum = 1;
+    else
+        images = h.naxis3;
+    if ( imagenum > images )
+        pm_error( "only %d plane%s in this file", 
+                  images, images > 1 ? "s" : "" );
+    if ( images != 3 && images > 1 && imagenum == 0 )
+        pm_error( "need to specify a plane using the -imagenum flag" );
+
+    multiplane = ( images == 3 && imagenum == 0 );
+
+    computeMinMax(ifp, images, cols, rows, h, imagenum, multiplane,
+                  forcemin, forcemax, frmin, frmax,
+                  &datamin, &datamax);
+
+    if (h.bitpix < 0) {
+        /* samples are floating point, which means the resolution could be
+           anything.  So we just pick a convenient maxval of 255.  We should
+           have a program option to choose the maxval.  Before Netpbm 10.20
+           (January 2004), we did maxval = max - min for floating point as
+           well as integer samples.
+        */
+        maxval = 255;
+    } else
+        maxval = MAX(1, MIN(PNM_OVERALLMAXVAL, datamax - datamin));
+
+    if ( datamax - datamin == 0 )
+        scale = 1.0;
+    else
+        scale = maxval / ( datamax - datamin );
+
+    /* If printmax option is true, just print and exit. */
+    /* For use in shellscripts.  Ex:                    */
+    /* eval `fitstopnm -printmax $filename | \          */
+    /*   awk '{min = $1; max = $2}\                     */
+    /*         END {print "min=" min; " max=" max}'`    */
+    if (printmax) {
+        printf( "%f %f\n", datamin, datamax);
+        pm_close( ifp );
+        pm_close( stdout );
+        exit( 0 );
+    }
+
+    if (multiplane)
+        format = PPM_FORMAT;
+    else
+        format = PGM_FORMAT;
+
+    pnmarray = pnm_allocarray( cols, rows );
+
+    switch( PNM_FORMAT_TYPE( format ))
+    {
+    case PGM_TYPE:
+        pm_message( "writing PGM file" );
+        for ( image = 1; image <= imagenum; ++image )
+        {
+            if ( image != imagenum )
+                pm_message( "skipping image plane %d of %d", image, images );
+            else if ( images > 1 )
+                pm_message( "reading image plane %d of %d", image, images );
+            for ( row = 0; row < rows; ++row)
+                for ( col = 0; col < cols; ++col )
+                {
+                    read_val (ifp, h.bitpix, &val);
+                    t = scale * ( val * h.bscale + h.bzer - datamin );
+                    tx = MAX( 0, MIN( t, maxval ) );
+                    if ( image == imagenum )
+                        PNM_ASSIGN1( pnmarray[row][col], tx );
+                }
+        }
+        break;
+    case PPM_TYPE:
+        pm_message( "writing PPM file" );
+        for ( image = 1; image <= images; image++ )
+        {
+            pm_message( "reading image plane %d of %d", image, images );
+            for ( row = 0; row < rows; row++ )
+                for ( col = 0; col < cols; col++ )
+                {
+                    read_val (ifp, h.bitpix, &val);
+                    txv[1] = PPM_GETR( pnmarray[row][col] );
+                    txv[2] = PPM_GETG( pnmarray[row][col] );
+                    txv[3] = PPM_GETB( pnmarray[row][col] );
+                    t = scale * ( val * h.bscale + h.bzer - datamin );
+                    txv[image] = MAX( 0, MIN( t, maxval ));
+                    PPM_ASSIGN( pnmarray[row][col], txv[1], txv[2], txv[3] );
+                }
+        }
+        break;
+    default:
+        pm_error( "can't happen" );
+        break;
+    }
+
+    pnm_writepnm( stdout, pnmarray, cols, rows, maxval, format, forceplain );
+    pnm_freearray( pnmarray, rows );
+
+    pm_close( ifp );
+    pm_close( stdout );
+  
+    exit( 0 );
+}
+
+/*
+ ** This code will deal properly with integers, no matter what the byte order
+ ** or integer size of the host machine.  Sign extension is handled manually
+ ** to prevent problems with signed/unsigned characters.  Floating point
+ ** values will only be read properly when the host architecture is IEEE-754
+ ** conformant.  If you need to tweak this code for other machines, you might
+ ** want to snag a copy of the FITS documentation from nssdca.gsfc.nasa.gov
+ */
+
+static void
+read_val (fp, bitpix, vp)
+    FILE *fp;
+    int bitpix;
+    double *vp;
+
+{
+    int i, ich, ival;
+    long int lval;
+    unsigned char c[8];
+  
+    switch ( bitpix )
+    {
+        /* 8 bit FITS integers are unsigned */
+    case 8:
+        ich = getc( fp );
+        if ( ich == EOF )
+            pm_error( "EOF / read error" );
+        *vp = ich;
+        break;
+      
+    case 16:
+        ich = getc( fp );
+        if ( ich == EOF )
+            pm_error( "EOF / read error" );
+        c[0] = ich;
+        ich = getc( fp );
+        if ( ich == EOF )
+            pm_error( "EOF / read error" );
+        c[1] = ich;
+        if (c[0] & 0x80)
+            ival = ~0xFFFF | c[0]<<8 | c[1];
+        else
+            ival = c[0]<<8 | c[1];
+        *vp = ival;
+        break;
+      
+    case 32:
+        for (i=0; i<4; i++) {
+            ich = getc( fp );
+            if ( ich == EOF )
+                pm_error( "EOF / read error" );
+            c[i] = ich;
+        }
+        if (c[0] & 0x80)
+            lval = ~0xFFFFFFFF |
+                c[0]<<24 | c[1]<<16 | c[2]<<8 | c[3];
+        else
+            lval = c[0]<<24 | c[1]<<16 | c[2]<<8 | c[3];
+        *vp = lval;
+      
+    case -32:
+        for (i=0; i<4; i++) {
+            ich = getc( fp );
+            if ( ich == EOF )
+                pm_error( "EOF / read error" );
+            c[i] = ich;
+        }
+        *vp = *( (float *) c);
+        break;
+      
+    case -64:
+        for (i=0; i<8; i++) {
+            ich = getc( fp );
+            if ( ich == EOF )
+                pm_error( "EOF / read error" );
+            c[i] = ich;
+        }
+        *vp = *( (double *) c);
+        break;
+      
+    default:
+        pm_error( "Strange bitpix in read_value" );
+    }
+}
+
+static void
+read_fits_header( fp, hP )
+    FILE* fp;
+    struct FITS_Header* hP;
+{
+    char buf[80];
+    int seen_end;
+    int i;
+    char c;
+  
+    seen_end = 0;
+    hP->simple = 0;
+    hP->bzer = 0.0;
+    hP->bscale = 1.0;
+    hP->datamin = - DBL_MAX;
+    hP->datamax = DBL_MAX;
+  
+    while ( ! seen_end )
+        for ( i = 0; i < 36; ++i )
+        {
+            read_card( fp, buf );
+    
+            if ( sscanf( buf, "SIMPLE = %c", &c ) == 1 )
+            {
+                if ( c == 'T' || c == 't' )
+                    hP->simple = 1;
+            }
+            else if ( sscanf( buf, "BITPIX = %d", &(hP->bitpix) ) == 1 );
+            else if ( sscanf( buf, "NAXIS = %d", &(hP->naxis) ) == 1 );
+            else if ( sscanf( buf, "NAXIS1 = %d", &(hP->naxis1) ) == 1 );
+            else if ( sscanf( buf, "NAXIS2 = %d", &(hP->naxis2) ) == 1 );
+            else if ( sscanf( buf, "NAXIS3 = %d", &(hP->naxis3) ) == 1 );
+            else if ( sscanf( buf, "DATAMIN = %lf", &(hP->datamin) ) == 1 );
+            else if ( sscanf( buf, "DATAMAX = %lf", &(hP->datamax) ) == 1 );
+            else if ( sscanf( buf, "BZERO = %lf", &(hP->bzer) ) == 1 );
+            else if ( sscanf( buf, "BSCALE = %lf", &(hP->bscale) ) == 1 );
+            else if ( strncmp( buf, "END ", 4 ) == 0 ) seen_end = 1;
+        }
+}
+
+static void
+read_card( fp, buf )
+    FILE* fp;
+    char* buf;
+{
+    if ( fread( buf, 1, 80, fp ) == 0 )
+        pm_error( "error reading header" );
+}
diff --git a/converter/other/gemtopnm.c b/converter/other/gemtopnm.c
new file mode 100644
index 00000000..aac74793
--- /dev/null
+++ b/converter/other/gemtopnm.c
@@ -0,0 +1,305 @@
+/*
+ * Convert a GEM .img file to PBM
+ *
+ * Author: Diomidis D. Spinellis
+ * (C) Copyright 1988 Diomidis D. Spinellis.
+ *
+ * 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 file is provided AS IS with no warranties of any kind.  The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof.  In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * Comments and additions should be sent to the author:
+ *
+ *                     Diomidis D. Spinellis
+ *                     1 Myrsinis Str.
+ *                     GR-145 62 Kifissia
+ *                     GREECE
+ *
+ * 92/07/11 Johann Haider
+ * Changed to read from stdin if file is omitted
+ * Changed to handle line length not a multipe of 8
+ *
+ * 94/01/31 Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
+ * Changed to remove architecture dependency and conform to
+ * PBM coding standard.
+ * Added more tests for garbage.
+ *
+ * 2000/04/30 John Elliott <jce@seasip.demon.co.uk> Added ability to
+ * read 4-plane color IMG files.  Therefore changed from PBM to PPM.
+ * Bryan changed it further to use the PNM facilities so it outputs
+ * both PBM and PPM in the Netpbm tradition.  Name changed from
+ * gemtopbm to gemtopnm.  
+ */
+
+#include <assert.h>
+#include "pnm.h"
+
+#define MAXVAL 3
+#define LIGHT  2
+#define DARK   1
+#define BLACK  0
+
+char pattern[8];
+
+static void getinit ARGS ((FILE *file, int *colsP, int *rowsP, int *padrightP,
+			   int *patlenP, int *planesP));
+
+int
+main(argc, argv)
+	int             argc;
+	char           *argv[];
+{
+	int     debug = 0;
+	FILE    *f;
+    int     row;
+	int     rows, cols, padright, patlen, planes;
+      /* attributes of input image */
+    int type;  /* The format type (PBM/PPM) of the output image */
+	bit	*bitrow[4];
+      /* One row of input, one or four planes.  (If one, only [0] is defined)*/
+    xel * xelrow;  /* One row of output */
+	const char * const usage = "[-debug] [gem IMG file]";
+	int argn;
+
+/* Process multiple planes by maintaining a separate row of bits for each
+ * plane. In a single-plane image, all we have to do is write out the 
+ * first plane; in a multiple-plane image, we combine them just before writing
+ * out the row.
+ */
+	pnm_init( &argc, argv );
+    
+    argn = 1;
+
+	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 (argc == argn)
+		f = stdin;
+	else {
+		f = pm_openr (argv[argn]);
+		++argn;
+	}
+
+	if (argn != argc)
+	  pm_usage (usage);
+
+	getinit (f, &cols, &rows, &padright, &patlen, &planes);
+
+    if (planes == 1) 
+        type = PBM_TYPE;
+    else 
+        type = PPM_TYPE;
+
+	pnm_writepnminit( stdout, cols, rows, MAXVAL, type, 0 );
+
+    { 
+        /* allocate input row data structure */
+        int plane;
+        for (plane = 0; plane < planes; plane++) 
+            bitrow[plane] = malloc (cols + padright);
+    }
+    xelrow = pnm_allocrow(cols+padright);   /* Output row */
+
+	for (row = 0; row < rows; ) {
+      int linerep;
+      int plane;
+
+	  linerep = 1;
+	  for (plane = 0; plane < planes; plane++) {
+        int col;
+		col = 0;
+		while (col < cols) {
+            int c;
+			switch (c = getc(f)) {
+			case 0x80:	/* Bit String */
+            {
+                int j;
+				c = getc(f);	/* Byte count */
+				if (debug)
+                  pm_message("bit string of %d bytes", c);
+				
+				if (col + c * 8 > cols + padright)
+				  pm_error ("bad byte count");
+				for (j = 0; j < c; ++j) {
+                    int cc, k;
+					cc = getc(f);
+					for (k = 0x80; k; k >>= 1) {
+						bitrow[plane][col] = (k & cc) ? 0 : 1;
+						++col;
+					}
+				}
+            }
+            break;
+			case 0:		/* Pattern run */
+            {
+                int j, l;
+				c = getc(f);	/* Repeat count */
+				if (debug)
+					pm_message("pattern run of %d repetitions",	c);
+                /* line repeat */
+                if (c == 0) {
+                    c = getc(f);
+                    if (c != 0x00ff)
+                        pm_error( "badly formed line repeat" );
+                    linerep = getc(f);
+                    break;
+                }
+				fread (pattern, 1, patlen, f);
+				if (col + c * patlen * 8 > cols + padright)
+				  pm_error ("bad pattern repeat count");
+				for (j = 0; j < c; ++j)
+					for (l = 0; l < patlen; ++l) {
+                        int k;
+						for (k = 0x80; k; k >>= 1) {
+							bitrow[plane][col] = (k & pattern[l]) ? 0 : 1;
+							++col;
+						}
+                    }
+            }
+            break;
+
+			default:	/* Solid run */
+            {
+                int l, j;
+				if (debug)
+					pm_message("solid run of %d bytes %s", c & 0x7f,
+                               c & 0x80 ? "on" : "off" );
+                /* each byte had eight bits DSB */
+                l = (c & 0x80) ? 0: 1;
+                c = (c & 0x7f) * 8;
+                if (col + c > cols + padright)
+                    pm_error ("bad solid run repeat count");
+                for (j = 0; j < c; ++j) {
+                    bitrow[plane][col] = l;
+					++col;
+                }
+            }
+				break;
+
+			case EOF:	/* End of file */
+				pm_error( "end of file reached" );
+
+			}
+		}
+                if ( debug )
+                        pm_message( "EOL plane %d row %d", plane, row );
+                if (col != cols + padright)
+                        pm_error( "EOL beyond edge" );
+	  }
+
+	  if (planes == 4) {
+          /* Construct a pixel from the 4 planes of bits for this row */
+          int col;
+          for (col = 0; col < cols; col++) {
+            int r, g, b, i;
+
+            const int r_bit = !bitrow[0][col];
+            const int g_bit = !bitrow[1][col];
+            const int b_bit = !bitrow[2][col];
+            i = bitrow[3][col];
+
+			/* Deal with weird GEM palette - white/black/gray are
+               encoded oddly 
+            */
+			if (r_bit == g_bit && g_bit == b_bit) {
+                /* It's black, white, or gray */
+				if (r_bit && i) r = LIGHT;
+				else if (r_bit) r = BLACK;
+				else if (i) r = MAXVAL;
+				else r = DARK;
+				g = b = r;	
+			} else {
+                /* It's one of the twelve colored colors */
+                if (!i) {
+                    /* Low intensity */
+                    r = r_bit * LIGHT; 
+                    g = g_bit * LIGHT;
+                    b = b_bit * LIGHT;
+                } else {
+                    /* Normal intensity */
+                    r = r_bit * MAXVAL;
+                    g = g_bit * MAXVAL;
+                    b = b_bit * MAXVAL;
+                }
+            }
+            PPM_ASSIGN(xelrow[col], r, g, b);
+		}
+	  } else {
+          int col;
+          for (col = 0; col < cols; col++) 
+              PNM_ASSIGN1(xelrow[col], bitrow[0][col]);
+      }
+	  while (linerep--) {
+		pnm_writepnmrow( stdout, xelrow, cols, MAXVAL, type, 0 );
+		++row;
+	  }
+	}
+    pnm_freerow(xelrow);
+	pm_close( f );
+	pm_close( stdout );
+	exit(0);
+}
+
+
+static void
+getinit (file, colsP, rowsP, padrightP, patlenP, planesP)
+     FILE *file;
+     int *colsP;
+     int *rowsP;
+     int *padrightP;
+     int *patlenP;
+     int *planesP;
+{
+  short s;
+  short headlen;
+
+  if (pm_readbigshort (file, &s) == -1) /* Image file version */
+    pm_error ("EOF / read error");
+  if (s != 1)
+    pm_error ("unknown version number (%d)", (int) s);
+  if (pm_readbigshort (file, &headlen) == -1) /* Header length in words */
+    pm_error ("EOF / read error");
+  if (headlen < 8)
+    pm_error ("short header (%d)", (int) headlen);
+  if (pm_readbigshort (file, &s) == -1) /* Number of planes */
+    pm_error ("EOF / read error");
+  if (s != 4 && s != 1)
+    pm_error ("This program can interpret IMGs with only 1 or 4 planes");
+  *planesP = s;
+  if (pm_readbigshort (file, &s) == -1) /* Pattern definition length (bytes) */
+    pm_error ("EOF / read error");
+  if (s < 1 || s > 8)
+    pm_error ("illegal pattern length (%d)", (int) s);
+  *patlenP = (int) s;
+  if (pm_readbigshort (file, &s) == -1 /* Pixel height (microns) */
+      || pm_readbigshort (file, &s) == -1 /* Pixel height (microns) */
+      || pm_readbigshort (file, &s) == -1) /* Scan line width */
+    pm_error ("EOF / read error");
+  *colsP = (int) s;
+  if (pm_readbigshort (file, &s) == -1) /* Number of scan line items */
+    pm_error ("EOF / read error");
+  *rowsP = (int) s;
+  *padrightP = 7 - ((*colsP + 7) & 7);
+
+  headlen -= 8;
+  while (headlen-- > 0)
+    {
+      (void) getc (file);
+      (void) getc (file);
+    }
+}
+
diff --git a/converter/other/giftopnm.c b/converter/other/giftopnm.c
new file mode 100644
index 00000000..d3d02fde
--- /dev/null
+++ b/converter/other/giftopnm.c
@@ -0,0 +1,1460 @@
+/* +-------------------------------------------------------------------+ */
+/* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@netcom.com)    | */
+/* |   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.           | */
+/* +-------------------------------------------------------------------+ */
+
+/* There is a copy of the GIF89 specification, as defined by its
+   inventor, Compuserve, in 1989, at http://members.aol.com/royalef/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.
+   An appendix describes extensions to Lempel-Ziv that GIF makes (variable
+   length compression codes and the clear and end codes), but does not
+   describe the Lempel-Ziv base.
+*/
+
+#define _BSD_SOURCE   /* Make sure strcasecmp() is in string.h */
+
+#include <string.h>
+#include <assert.h>
+
+#include "pnm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+
+#define GIFMAXVAL 255
+#define MAXCOLORMAPSIZE 256
+
+#define CM_RED 0
+#define CM_GRN 1
+#define CM_BLU 2
+
+#define MAX_LZW_BITS  12
+
+#define INTERLACE      0x40
+#define LOCALCOLORMAP  0x80
+#define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
+
+static __inline__ bool
+ReadOK(FILE *          const fileP,
+       unsigned char * const buffer,
+       size_t          const len) {
+
+    size_t bytesRead;
+
+    bytesRead = fread(buffer, len, 1, fileP);
+
+    return (bytesRead != 0);
+}
+
+
+#define LM_to_uint(a,b)                        (((b)<<8)|(a))
+
+static int const maxnum_lzwCode = (1<<MAX_LZW_BITS);
+
+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 */
+    unsigned int verbose;    /* -verbose option */
+    unsigned int comments;   /* -comments option */
+    bool all_images;  /* He wants all the images */
+    unsigned int image_no;
+        /* image number he wants from input, starting at 0.  Undefined
+           if all_images is TRUE
+        */
+    const char * alpha_filename;
+    unsigned int quitearly;
+};
+
+
+
+static void
+parseCommandLine(int argc, 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 optParseOptions3 on how to parse our options.
+         */
+    
+    optStruct3 opt;
+
+    unsigned int alphaSpec, imageSpec;
+    const char * image;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+    
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "verbose",     OPT_FLAG, NULL, 
+            &cmdlineP->verbose,         0);
+    OPTENT3(0, "comments",    OPT_FLAG, NULL,
+            &cmdlineP->comments,        0);
+    OPTENT3(0, "quitearly",    OPT_FLAG, NULL,
+            &cmdlineP->quitearly,       0);
+    OPTENT3(0, "image",       OPT_STRING, &image,
+            &imageSpec,                 0);
+    OPTENT3(0, "alphaout",    OPT_STRING, &cmdlineP->alpha_filename, 
+            &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);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (!imageSpec) {
+        cmdlineP->image_no = 0;
+        cmdlineP->all_images = FALSE;
+    } else {
+        if (strcasecmp(image, "all") == 0) 
+            cmdlineP->all_images = TRUE;
+        else {
+            char * tailptr;
+
+            long const imageNo = 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)
+                pm_error("Invalid value for '-image' option.  Must be "
+                         "positive.  You specified %ld", imageNo);
+            else if (imageNo == 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;
+        }
+    }
+    
+    if (argc-1 == 0) 
+        cmdlineP->input_filespec = "-";
+    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];
+
+    if (!alphaSpec) 
+        cmdlineP->alpha_filename = 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;
+        /* Aspect ratio of each pixel, times 64, minus 15.  (i.e. 1 => 1:4).
+           But Zero means 1:1.
+        */
+    int      hasGray;  
+        /* Boolean: global colormap has at least one gray color
+           (not counting black and white) 
+        */
+    int      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;
+};
+
+static void
+initGif89(struct gif89 * const gif89P) {
+    gif89P->transparent = -1;
+    gif89P->delayTime = -1;
+    gif89P->inputFlag = -1;
+    gif89P->disposal = -1;
+}       
+
+
+static int verbose;
+int    showComment;
+
+
+
+static void
+readColorMap(FILE *ifP, const int colormapsize, 
+             unsigned char colormap[3][MAXCOLORMAPSIZE],
+             int *hasGrayP, int * const hasColorP) {
+
+    int             i;
+    unsigned char   rgb[3];
+
+    assert(colormapsize <= 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);
+
+        colormap[CM_RED][i] = rgb[0] ;
+        colormap[CM_GRN][i] = rgb[1] ;
+        colormap[CM_BLU][i] = rgb[2] ;
+
+        if (rgb[0] == rgb[1] && rgb[1] == rgb[2]) {
+            if (rgb[0] != 0 && rgb[0] != GIFMAXVAL)
+                *hasGrayP = TRUE;
+        } else
+            *hasColorP = TRUE;
+    }
+}
+
+
+
+static bool zeroDataBlock = FALSE;
+    /* the most recently read DataBlock was an EOD marker, i.e. had
+       zero length */
+
+static void
+getDataBlock(FILE *          const ifP, 
+             unsigned char * const buf, 
+             bool *          const eofP,
+             unsigned int *  const lengthP) {
+/*----------------------------------------------------------------------------
+   Read a DataBlock from file 'ifP', return it at 'buf'.
+
+   The first byte of the datablock is the length, in pure binary, of the
+   rest of the datablock.  We return the data portion (not the length byte)
+   of the datablock at 'buf', and its length as *lengthP.
+
+   Except that if we hit EOF or have an I/O error reading the first
+   byte (size field) of the DataBlock, we return *eofP == TRUE and
+   *lengthP == 0.
+
+   We return *eofP == FALSE if we don't hit EOF or have an I/O error.
+
+   If we hit EOF or have an I/O error reading the data portion of the
+   DataBlock, we exit the program with pm_error().
+-----------------------------------------------------------------------------*/
+    unsigned char count;
+    bool successfulRead;
+    
+    long const pos=ftell(ifP);
+    successfulRead = ReadOK(ifP, &count, 1);
+    if (!successfulRead) {
+        pm_message("EOF or error in reading DataBlock size from file" );
+        *eofP = TRUE;
+        *lengthP = 0;
+    } else {
+        if (verbose)
+            pm_message("%d byte block at Position %ld", count, pos);
+        *eofP = FALSE;
+        *lengthP = count;
+
+        if (count == 0) 
+            zeroDataBlock = TRUE;
+        else {
+            bool successfulRead;
+
+            zeroDataBlock = FALSE;
+            successfulRead = ReadOK(ifP, buf, count); 
+            
+            if (!successfulRead) 
+                pm_error("EOF or error reading data portion of %d byte "
+                         "DataBlock from file", count);
+        }
+    }
+}
+
+
+
+static void
+readThroughEod(FILE * const ifP) {
+/*----------------------------------------------------------------------------
+  Read the file 'ifP' through the next EOD marker.  An EOD marker is a
+  a zero length data block.
+
+  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];
+    bool eod;
+
+    eod = FALSE;  /* initial value */
+    while (!eod) {
+        bool eof;
+        unsigned int count;
+
+        getDataBlock(ifP, buf, &eof, &count);
+        if (eof)
+            pm_message("EOF encountered before EOD marker.  The GIF "
+                       "file is malformed, but we are proceeding "
+                       "anyway as if an EOD marker were at the end "
+                       "of the file.");
+        if (eof || count == 0)
+            eod = TRUE;
+    }
+}
+
+
+
+static void
+doCommentExtension(FILE * const ifP) {
+/*----------------------------------------------------------------------------
+   Read the rest of a comment extension from the input file 'ifP' and handle
+   it.
+   
+   We ought to deal with the possibility that the comment is not text.  I.e.
+   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];
+    unsigned int blocklen;  
+    bool done;
+
+    done = FALSE;
+    while (!done) {
+        bool eof;
+        getDataBlock(ifP, (unsigned char*) buf, &eof, &blocklen); 
+        if (blocklen == 0 || eof)
+            done = TRUE;
+        else {
+            buf[blocklen] = '\0';
+            if (showComment) {
+                pm_message("gif comment: %s", buf);
+            }
+        }
+    }
+}
+
+
+
+static void 
+doGraphicControlExtension(FILE *         const ifP,
+                          struct gif89 * const gif89P) {
+
+    bool eof;
+    unsigned int length;
+    static unsigned char buf[256];
+
+    getDataBlock(ifP, buf, &eof, &length);
+    if (eof)
+        pm_error("EOF/error encountered reading "
+                 "1st DataBlock of Graphic Control Extension.");
+    else if (length < 4) 
+        pm_error("graphic control extension 1st DataBlock too short.  "
+                 "It must be at least 4 bytes; it is %d bytes.",
+                 length);
+    else {
+        gif89P->disposal = (buf[0] >> 2) & 0x7;
+        gif89P->inputFlag = (buf[0] >> 1) & 0x1;
+        gif89P->delayTime = LM_to_uint(buf[1],buf[2]);
+        if ((buf[0] & 0x1) != 0)
+            gif89P->transparent = buf[3];
+        readThroughEod(ifP);
+    }
+}
+
+
+
+static void
+doExtension(FILE * const ifP, int 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
+        break;
+    case 0xff:              /* Application Extension */
+        str = "Application";
+        readThroughEod(ifP);
+        break;
+    case 0xfe:              /* Comment Extension */
+        str = "Comment";
+        doCommentExtension(ifP);
+        break;
+    case 0xf9:              /* Graphic Control Extension */
+        str = "Graphic Control";
+        doGraphicControlExtension(ifP, gif89P);
+        break;
+    default: {
+        static char buf[256];
+        str = buf;
+        sprintf(buf, "UNKNOWN (0x%02x)", label);
+        pm_message("Ignoring unrecognized extension (type 0x%02x)", label);
+        readThroughEod(ifP);
+        }
+        break;
+    }
+    if (verbose)
+        pm_message(" got a '%s' extension", str );
+}
+
+
+
+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
+           blocks at a time, but our client wants one code at a time.
+           The buffer typically contains the contents of one data block
+           plus two bytes from the previous data block.
+        */
+    int bufCount;
+        /* This is the number of bytes of contents in buf[]. */
+    int curbit;
+        /* The bit number (starting at 0) within buf[] of the next bit
+           to be returned.  If the next bit to be returned is not yet in
+           buf[] (we've already returned everything in there), this points
+           one beyond the end of the buffer contents.
+        */
+    bool streamExhausted;
+        /* The last time we read from the input stream, we got an EOD marker
+           or EOF
+        */
+};
+
+
+
+static void
+initGetCode(struct getCodeState * const getCodeStateP) {
+    
+    /* Fake a previous data block */
+    getCodeStateP->buf[0] = 0;
+    getCodeStateP->buf[1] = 0;
+    getCodeStateP->bufCount = 2;
+    getCodeStateP->curbit = getCodeStateP->bufCount * 8;
+    getCodeStateP->streamExhausted = FALSE;
+}
+
+
+
+static void
+getAnotherBlock(FILE * const ifP, 
+                struct getCodeState * const gsP) {
+
+    unsigned int count;
+    unsigned int assumed_count;
+    bool eof;
+
+    /* Shift buffer down so last two bytes are now the
+       first two bytes.  Shift 'curbit' cursor, which must
+       be somewhere in or immediately after those two
+       bytes, accordingly.
+    */
+    gsP->buf[0] = gsP->buf[gsP->bufCount-2];
+    gsP->buf[1] = gsP->buf[gsP->bufCount-1];
+
+    gsP->curbit -= (gsP->bufCount-2)*8;
+    gsP->bufCount = 2;
+        
+    /* Add the next block to the buffer */
+    getDataBlock(ifP, &gsP->buf[gsP->bufCount], &eof, &count);
+    if (eof) {
+        pm_message("EOF encountered in image "
+                   "before EOD marker.  The GIF "
+                   "file is malformed, but we are proceeding "
+                   "anyway as if an EOD marker were at the end "
+                   "of the file.");
+        assumed_count = 0;
+    } else
+        assumed_count = count;
+
+    gsP->streamExhausted = (assumed_count == 0);
+
+    gsP->bufCount += assumed_count;
+}
+
+
+
+static void
+doGetCode(FILE *                const ifP, 
+          int                   const codeSize,
+          struct getCodeState * const gsP,
+          int *                 const retvalP) {
+
+    if ((gsP->curbit+codeSize) > gsP->bufCount*8 && !gsP->streamExhausted) 
+        /* Not enough left in buffer to satisfy request.  Get the next
+           data block into the buffer.
+        */
+        getAnotherBlock(ifP, gsP);
+
+    if ((gsP->curbit+codeSize) > gsP->bufCount*8) {
+        /* If the buffer still doesn't have enough bits in it, that means
+           there were no data blocks left to read.
+        */
+        *retvalP = -1;  /* EOF */
+
+        {
+            int const bitsUnused = gsP->bufCount*8 - gsP->curbit;
+            if (bitsUnused > 0)
+                pm_message("Stream ends with a partial code "
+                           "(%d bits left in file; "
+                           "expected a %d bit code).  Ignoring.",
+                           bitsUnused, codeSize);
+        }
+    } else {
+        int i, j;
+        int code;
+        unsigned char * const buf = gsP->buf;
+
+        code = 0;  /* initial value */
+        for (i = gsP->curbit, j = 0; j < codeSize; ++i, ++j)
+            code |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
+        gsP->curbit += codeSize;
+        *retvalP = code;
+    }
+}
+
+
+
+static int
+getCode(FILE * const ifP, 
+        int    const codeSize, 
+        bool   const init)
+{
+/*----------------------------------------------------------------------------
+   If 'init', initialize the code getter.
+
+   Otherwise, read and return the next lzw code from the file *ifP.
+
+   'codeSize' is the number of bits in the code we are to get.
+
+   Return -1 instead of a code if we encounter the end of the file.
+-----------------------------------------------------------------------------*/
+    static struct getCodeState getCodeState;
+
+    int retval;
+
+    if (init) {
+        initGetCode(&getCodeState);
+        retval = 0;
+    } else 
+        doGetCode(ifP, codeSize, &getCodeState, &retval);
+
+    return retval;
+}
+
+
+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 */
+};
+
+
+
+static void 
+initStack(struct stack * const stackP, unsigned int const size) {
+
+    MALLOCARRAY(stackP->stack, size);
+    if (stackP->stack == NULL)
+        pm_error("Unable to allocate %d-word stack.", size);
+    stackP->sp = stackP->stack;
+    stackP->top = stackP->stack + size;
+}
+
+
+
+static void
+pushStack(struct stack * const stackP, int const value) {
+
+    if (stackP->sp >= stackP->top)
+        pm_error("stack overflow");
+
+    *(stackP->sp++) = value;
+}
+
+
+
+static bool
+stackIsEmpty(const struct stack * const stackP) {
+    return stackP->sp == stackP->stack;
+}
+
+
+
+static int
+popStack(struct stack * const stackP) {
+
+    if (stackP->sp <= stackP->stack)
+        pm_error("stack underflow");
+    
+    return *(--stackP->sp);
+}
+
+
+
+static void
+termStack(struct stack * const stackP) {
+    free(stackP->stack);
+    stackP->stack = NULL;
+}
+
+
+/*----------------------------------------------------------------------------
+   Some notes on LZW.
+
+   LZW is an extension of Limpel-Ziv.  The two extensions are:
+
+     1) in Limpel-Ziv, codes are all the same number of bits.  In
+        LZW, they start out small and increase as the stream progresses.
+
+     2) LZW has a clear code that resets the string table and code
+        size.
+
+   The LZW code space is allocated as follows:
+
+   The true data elements are dataWidth bits wide, so the maximum
+   value of a true data element is 2**dataWidth-1.  We call that
+   max_dataVal.  The first byte in the stream tells you what dataWidth
+   is.
+
+   LZW codes 0 - max_dataVal are direct codes.  Each on represents
+   the true data element whose value is that of the LZW code itself.
+   No decompression is required.
+
+   max_dataVal + 1 and up are compression codes.  They encode
+   true data elements:
+
+   max_dataVal + 1 is the clear code.
+         
+   max_dataVal + 2 is the end code.
+
+   max_dataVal + 3 and up are string codes.  Each string code 
+   represents a string of true data elements.  The translation from a
+   string code to the string of true data elements varies as the stream
+   progresses.  In the beginning and after every clear code, the
+   translation table is empty, so no string codes are valid.  As the
+   stream progresses, the table gets filled and more string codes 
+   become valid.
+
+-----------------------------------------------------------------------------*/
+
+
+struct decompressor {
+    struct stack stack;
+    int      fresh;
+        /* The stream is right after a clear code or at the very beginning */
+    int      codeSize;
+        /* The current code size -- each LZW code in this part of the image
+           is this many bits.  Ergo, we read this many bits at a time from
+           the stream.
+        */
+    int      maxnum_code;
+        /* The maximum number of LZW codes that can be represented with the 
+           current code size.  (1 << codeSize)
+        */
+    int      next_tableSlot;
+        /* Index in the code translation table of the next free entry */
+    int      firstcode;
+        /* This is always a true data element code */
+    int      prevcode;
+        /* The code just before, in the image, the one we're processing now */
+    int      table[2][(1 << MAX_LZW_BITS)];
+
+    /* The following are constant for the life of the decompressor */
+    FILE * ifP;
+    int init_codeSize;
+    int max_dataVal;
+    int clear_code;
+    int end_code; 
+};
+
+
+
+static void
+resetDecompressor(struct decompressor * const decompP) {
+
+    decompP->codeSize = decompP->init_codeSize+1;
+    decompP->maxnum_code = 1 << decompP->codeSize;
+    decompP->next_tableSlot = decompP->max_dataVal + 3;
+    decompP->fresh = 1;
+}
+
+
+
+static void
+lzwInit(struct decompressor * const decompP, 
+        FILE *                const ifP,
+        int                   const init_codeSize) {
+
+    if (verbose)
+        pm_message("Image says the initial compression code size is "
+                   "%d bits", 
+                   init_codeSize);
+    
+    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;
+
+    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);
+    
+    /* The entries in the translation table for true data codes are
+       constant throughout the stream.  We set them now and they never
+       change.
+    */
+    {
+        unsigned int i;
+        for (i = 0; i <= decompP->max_dataVal; ++i) {
+            decompP->table[0][i] = 0;
+            decompP->table[1][i] = i;
+        }
+    }
+    resetDecompressor(decompP);
+
+    getCode(decompP->ifP, 0, TRUE);
+    
+    decompP->fresh = TRUE;
+    
+    initStack(&decompP->stack, maxnum_lzwCode * 2);
+}
+
+
+
+static void
+lzwTerm(struct decompressor * const decompP) {
+
+    termStack(&decompP->stack);
+}
+
+
+
+static void
+expandCodeOntoStack(struct decompressor * const decompP,
+                    int                   const incode,
+                    bool *                const errorP) {
+/*----------------------------------------------------------------------------
+   'incode' is an LZW string code.  It represents a string of true data
+   elements, as defined by the string translation table in *decompP.
+
+   Expand the code to a string of LZW direct codes and push them onto the
+   stack such that the leftmost code is on top.
+
+   Also add to the translation table where appropriate.
+
+   Iff the translation table contains a cycle (which means the LZW stream
+   from which it was built is invalid), return *errorP == TRUE.
+-----------------------------------------------------------------------------*/
+    int code;
+    bool error;
+
+    error = FALSE;
+
+    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;
+    }
+
+    {
+        /* 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.
+            */
+
+        unsigned int stringCount;
+        stringCount = 0;
+
+        while (code > decompP->max_dataVal && !error) {
+            if (stringCount > maxnum_lzwCode) {
+                pm_message("Error in GIF image: contains LZW string loop");
+                error = TRUE;
+            } 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);
+    }
+
+    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;
+            }
+        }
+    }
+
+    decompP->prevcode = incode;
+    *errorP = error;
+}
+
+
+
+static int
+lzwReadByte(struct decompressor * const decompP) {
+/*----------------------------------------------------------------------------
+  Return the next data element of the decompressed image.  In the context
+  of a GIF, a data element is the color table index of one pixel.
+
+  We read and return the next byte of the decompressed image, or:
+
+    Return -1 if we hit EOF prematurely (i.e. before an "end" code.  We
+    forgive the case that the "end" code is followed by EOF instead of
+    an EOD marker (zero length DataBlock)).
+
+    Return -2 if there are no more bytes in the image.  In that case,
+    make sure the file is positioned immediately after the image (i.e.
+    after the EOD marker that marks the end of the image or EOF).
+
+    Return -3 if we encounter errors in the LZW stream.
+-----------------------------------------------------------------------------*/
+    int retval;
+
+    if (!stackIsEmpty(&decompP->stack))
+        retval = popStack(&decompP->stack);
+    else if (decompP->fresh) {
+        decompP->fresh = FALSE;
+        /* 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.
+        */
+        do {
+            decompP->firstcode =
+                getCode(decompP->ifP, decompP->codeSize, FALSE);
+            decompP->prevcode = decompP->firstcode;
+        } while (decompP->firstcode == decompP->clear_code);
+        if (decompP->firstcode == decompP->end_code) {
+            if (!zeroDataBlock)
+                readThroughEod(decompP->ifP);
+            retval = -2;
+        } else
+            retval = decompP->firstcode;
+    } else {
+        int code;
+        code = getCode(decompP->ifP, decompP->codeSize, FALSE);
+        if (code == -1)
+            retval = -1;
+        else {
+            assert(code >= 0);  /* -1 is only possible error return */
+            if (code == decompP->clear_code) {
+                resetDecompressor(decompP);
+                retval = lzwReadByte(decompP);
+            } else {
+                if (code == decompP->end_code) {
+                    if (!zeroDataBlock)
+                        readThroughEod(decompP->ifP);
+                    retval = -2;
+                } else {
+                    bool error;
+                    expandCodeOntoStack(decompP, code, &error);
+                    if (error)
+                        retval = -3;
+                    else
+                        retval = popStack(&decompP->stack);
+                }
+            }
+        }
+    }
+    return retval;
+}
+
+
+
+enum pass {MULT8PLUS0, MULT8PLUS4, MULT4PLUS2, MULT2PLUS1};
+
+static void
+bumpRowInterlace(unsigned int * const rowP,
+                 unsigned int   const rows,
+                 enum pass *    const passP) {
+/*----------------------------------------------------------------------------
+   Move *pixelCursorP to the next row in the interlace pattern.
+-----------------------------------------------------------------------------*/
+    /* There are 4 passes:
+       MULT8PLUS0: Rows 8, 16, 24, 32, etc.
+       MULT8PLUS4: Rows 4, 12, 20, 28, etc.
+       MULT4PLUS2: Rows 2, 6, 10, 14, etc.
+       MULT2PLUS1: Rows 1, 3, 5, 7, 9, etc.
+    */
+    
+    switch (*passP) {
+    case MULT8PLUS0:
+        *rowP += 8;
+        break;
+    case MULT8PLUS4:
+        *rowP += 8;
+        break;
+    case MULT4PLUS2:
+        *rowP += 4;
+        break;
+    case MULT2PLUS1:
+        *rowP += 2;
+        break;
+    }
+    /* Set the proper pass for the next read.  Note that if there are
+       more than 4 rows, the sequence of passes is sequential, but
+       when there are fewer than 4, we may skip e.g. from MULT8PLUS0
+       to MULT4PLUS2.
+    */
+    while (*rowP >= rows && *passP != MULT2PLUS1) {
+        switch (*passP) {
+        case MULT8PLUS0:
+            *passP = MULT8PLUS4;
+            *rowP = 4;
+            break;
+        case MULT8PLUS4:
+            *passP = MULT4PLUS2;
+            *rowP = 2;
+            break;
+        case MULT4PLUS2:
+            *passP = MULT2PLUS1;
+            *rowP = 1;
+            break;
+        case MULT2PLUS1:
+            /* We've read the entire image */
+            break;
+        }
+    }
+}
+
+
+
+struct pnmBuffer {
+    xel ** xels;
+    unsigned int col;
+    unsigned int row;
+};
+
+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;
+    }
+}
+
+
+
+static void
+readImageData(FILE *       const ifP, 
+              xel **       const xels, 
+              unsigned int const cols,
+              unsigned int const rows,
+              gifColorMap        cmap, 
+              unsigned int const cmapSize,
+              bool         const interlace,
+              int          const transparentIndex,
+              bit **       const alphabits) {
+
+    unsigned char lzwMinCodeSize;      
+    enum pass pass;
+    struct decompressor decomp;
+    struct pnmBuffer pnmBuffer;
+    bool gotMinCodeSize;
+
+    pass = MULT8PLUS0;
+
+    pnmBuffer.xels = xels;
+    pnmBuffer.col  = 0;
+    pnmBuffer.row  = 0;
+
+    gotMinCodeSize =  ReadOK(ifP, &lzwMinCodeSize, 1);
+    if (!gotMinCodeSize)
+        pm_error("GIF stream ends (or read error) "
+                 "right after an image separator; no "
+                 "image data follows.");
+
+    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);
+
+    while (pnmBuffer.row < rows) {
+        int const rc = lzwReadByte(&decomp);
+
+        switch (rc) {
+        case -3:
+            pm_error("Error in GIF input stream");
+            break;
+        case -2:
+            pm_error("Error in GIF image: Not enough raster data to fill "
+                     "%u x %u dimensions.  Ran out of raster data in "
+                     "row %u", cols, rows, pnmBuffer.row);
+            break;
+        case -1:
+            pm_error("Premature end of file; no proper GIF closing");
+            break;
+        default:
+            addPixelToRaster(rc, &pnmBuffer, cols, rows, cmap, cmapSize,
+                             interlace, transparentIndex, alphabits, &pass);
+        }
+    }
+    if (lzwReadByte(&decomp) >= 0)
+        pm_message("Extraneous data at end of image.  "
+                   "Skipped to end of image");
+
+    lzwTerm(&decomp);
+}
+
+
+
+static void
+writePnm(FILE *outfile, xel ** const xels, 
+         const int cols, const int rows,
+         const int hasGray, const int hasColor) {
+/*----------------------------------------------------------------------------
+   Write a PNM image to the current position of file 'outfile' with
+   dimensions 'cols' x 'rows' and raster 'xels'.
+   
+   Make it PBM, PGM, or PBM according to 'hasGray' and 'hasColor'.
+-----------------------------------------------------------------------------*/
+    int format;
+    const char *format_name;
+           
+    if (hasColor) {
+        format = PPM_FORMAT;
+        format_name = "PPM";
+    } else if (hasGray) {
+        format = PGM_FORMAT;
+        format_name = "PGM";
+    } else {
+        format = PBM_FORMAT;
+        format_name = "PBM";
+    }
+    if (verbose) 
+        pm_message("writing a %s file", format_name);
+    
+    if (outfile) 
+        pnm_writepnm(outfile, xels, cols, rows,
+                     (xelval) GIFMAXVAL, format, FALSE);
+}
+
+
+
+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
+                );
+    }
+}
+
+static void
+readGifHeader(FILE * const gifFile, struct gifScreen * const gifScreenP) {
+/*----------------------------------------------------------------------------
+   Read the GIF stream header off the file gifFile, 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];
+
+
+    if (! ReadOK(gifFile,buf,6))
+        pm_error("error reading magic number" );
+    
+    if (strncmp((char *)buf,"GIF",3) != 0)
+        pm_error("File does not contain a GIF stream.  It does not start "
+                 "with 'GIF'.");
+    
+    strncpy(version, (char *)buf + 3, 3);
+    version[3] = '\0';
+    
+    if (verbose)
+        pm_message("GIF format version is '%s'", version);
+    
+    if ((!STREQ(version, "87a")) && (!STREQ(version, "89a")))
+        pm_error("bad version number, not '87a' or '89a'" );
+    
+    if (! ReadOK(gifFile,buf,7))
+        pm_error("failed to read screen descriptor" );
+    
+    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];
+
+    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);
+    }           
+    if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
+        readColorMap(gifFile, gifScreenP->ColorMapSize, gifScreenP->ColorMap,
+                     &gifScreenP->hasGray, &gifScreenP->hasColor);
+        if (verbose) {
+            pm_message("Color map %s grays, %s colors", 
+                       gifScreenP->hasGray ? "contains" : "doesn't contain",
+                       gifScreenP->hasColor ? "contains" : "doesn't contain");
+        }
+    }
+    
+    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 );
+    }
+}
+
+
+
+static void
+readExtensions(FILE*          const ifP, 
+               struct gif89 * const gif89P,
+               bool *         const eodP) {
+/*----------------------------------------------------------------------------
+   Read extension blocks from the GIF stream to which the file *ifP is
+   positioned.  Read up through the image separator that begins the
+   next image or GIF stream terminator.
+
+   If we encounter EOD (end of GIF stream) before we find an image 
+   separator, we return *eodP == TRUE.  Else *eodP == FALSE.
+
+   If we hit end of file before an EOD marker, we abort the program with
+   an error message.
+-----------------------------------------------------------------------------*/
+    bool imageStart;
+    bool eod;
+
+    eod = FALSE;
+    imageStart = FALSE;
+
+    /* Read the image descriptor */
+    while (!imageStart && !eod) {
+        unsigned char c;
+
+        if (! ReadOK(ifP,&c,1))
+            pm_error("EOF / read error on image data" );
+
+        if (c == ';') {         /* GIF terminator */
+            eod = TRUE;
+        } else if (c == '!') {         /* Extension */
+            if (! ReadOK(ifP,&c,1))
+                pm_error("EOF / "
+                         "read error on extension function code");
+            doExtension(ifP, c, gif89P);
+        } else if (c == ',') 
+            imageStart = TRUE;
+        else 
+            pm_message("bogus character 0x%02x, ignoring", (int) c );
+    }
+    *eodP = eod;
+}
+
+
+
+static void
+reportImageInfo(unsigned int const cols,
+                unsigned int const rows,
+                bool         const useGlobalColormap,
+                unsigned int const localColorMapSize,
+                bool         const interlaced) {
+
+
+    pm_message("reading %u by %u%s GIF image",
+               cols, rows, interlaced ? " interlaced" : "" );
+    if (useGlobalColormap)
+        pm_message("  Uses global colormap");
+    else
+        pm_message("  Uses local colormap of %u colors", localColorMapSize);
+}
+
+
+
+static void
+convertImage(FILE *           const ifP, 
+             bool             const skipIt, 
+             FILE *           const imageout_file, 
+             FILE *           const alphafile, 
+             struct gifScreen       gifScreen,
+             struct gif89     const gif89) {
+/*----------------------------------------------------------------------------
+   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.
+-----------------------------------------------------------------------------*/
+    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;
+
+    if (! ReadOK(ifP,buf,9))
+        pm_error("couldn't read left/top/width/height");
+
+    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);
+
+    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, 
+                     &hasGray, &hasColor);
+        transparencyMessage(gif89.transparent, localColorMap);
+        readImageData(ifP, xels, cols, rows, localColorMap, localColorMapSize,
+                      interlaced, gif89.transparent, alphabits);
+        if (!skipIt) {
+            writePnm(imageout_file, xels, cols, rows,
+                     hasGray, hasColor);
+        }
+    } else {
+        transparencyMessage(gif89.transparent, gifScreen.ColorMap);
+        readImageData(ifP, xels, cols, rows, 
+                      gifScreen.ColorMap, gifScreen.ColorMapSize,
+                      interlaced, gif89.transparent, alphabits);
+        if (!skipIt) {
+            writePnm(imageout_file, xels, cols, rows,
+                     gifScreen.hasGray, gifScreen.hasColor);
+        }
+    }
+
+    if (!skipIt && alphafile && alphabits)
+        pbm_writepbm(alphafile, alphabits, cols, rows, FALSE);
+
+    pnm_freearray(xels, rows);
+    if (alphabits)
+        pbm_freearray(alphabits, rows);
+}
+
+
+
+static void
+convertImages(FILE * const ifP, 
+              bool   const allImages,
+              int    const requestedImageSeq, 
+              bool   const drainStream,
+              FILE * const imageout_file, 
+              FILE * const alphafile) {
+/*----------------------------------------------------------------------------
+   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'.
+
+   'allImages' means Caller wants all the images in the stream.  
+
+   'requestedImageSeq' is meaningful only when 'allImages' is FALSE.  It 
+   is the sequence number of the one image Caller wants from the stream,
+   with the first image being 0.
+
+   'drainInput' means to read the entire GIF stream, even after
+   reading the image Caller asked for.  We read the stream, not just
+   the file it's in, so we still recognize certain errors in the GIF
+   format in the tail of the stream and there may yet be more stuff in
+   the file when we return.
+-----------------------------------------------------------------------------*/
+    int imageSeq;
+        /* Sequence within GIF stream of image we are currently processing.
+           First is 0.
+        */
+    struct gifScreen gifScreen;
+    struct gif89 gif89;
+    bool eod;
+        /* We've read through the GIF terminator character */
+
+    initGif89(&gif89);
+
+    readGifHeader(ifP, &gifScreen);
+
+    for (imageSeq = 0, eod = FALSE;
+         !eod && (imageSeq <= requestedImageSeq || allImages || drainStream);
+         ++imageSeq) {
+
+        readExtensions(ifP, &gif89, &eod);
+
+        if (eod) {
+            /* GIF stream ends before image with sequence imageSeq */
+            if (!allImages && (imageSeq <= requestedImageSeq))
+                pm_error("You requested Image %d, but "
+                         "only %d image%s found in GIF stream",
+                         requestedImageSeq+1,
+                         imageSeq, imageSeq>1?"s":"" );
+        } else {
+            if (verbose)
+                pm_message("Reading Image Sequence %d", imageSeq);
+            convertImage(ifP, !allImages && (imageSeq != requestedImageSeq), 
+                         imageout_file, alphafile, gifScreen, gif89);
+        }
+    }
+}
+
+
+
+int
+main(int argc, char **argv) {
+
+    struct cmdlineInfo cmdline;
+    FILE *ifP;
+    FILE *alpha_file, *imageout_file;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+    verbose = cmdline.verbose;
+    showComment = cmdline.comments;
+   
+    ifP = pm_openr(cmdline.input_filespec);
+
+    if (cmdline.alpha_filename == NULL)
+        alpha_file = NULL;
+    else
+        alpha_file = pm_openw(cmdline.alpha_filename);
+
+    if (alpha_file && STREQ(cmdline.alpha_filename, "-"))
+        imageout_file = NULL;
+    else
+        imageout_file = stdout;
+
+    convertImages(ifP, cmdline.all_images, cmdline.image_no, 
+                  !cmdline.quitearly, imageout_file, alpha_file);
+
+    pm_close(ifP);
+    if (imageout_file != NULL) 
+        pm_close( imageout_file );
+    if (alpha_file != NULL)
+        pm_close( alpha_file );
+
+    return 0;
+}
diff --git a/converter/other/hdifftopam.c b/converter/other/hdifftopam.c
new file mode 100644
index 00000000..444d6068
--- /dev/null
+++ b/converter/other/hdifftopam.c
@@ -0,0 +1,156 @@
+/******************************************************************************
+                                hdifftopam
+*******************************************************************************
+  This program recovers a PAM image from a horizontal difference images 
+  such as created by Pamtohdiff.
+
+  By Bryan Henderson, San Jose, CA 2002.04.15.
+******************************************************************************/
+#include <string.h>
+#include <stdio.h>
+
+#include "pam.h"
+#include "shhopt.h"
+#include "nstring.h"
+
+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 pnm;
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, 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 = malloc( 100*sizeof( optEntry ) );
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "pnm",       OPT_FLAG,    NULL, &cmdlineP->pnm,      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 */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 < 1)
+        cmdlineP->inputFilespec = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFilespec = argv[1];
+    else
+        pm_error("Too many arguments.");
+}
+
+
+
+static void
+makePnm(struct pam * const pamP) {
+
+    switch (pamP->depth) {
+    case 1: 
+        pamP->format = PGM_FORMAT;
+        break;
+    case 3:
+        pamP->format = PPM_FORMAT;
+        break;
+    default:
+        pm_error("Input depth (%d) does not correspond to a PNM format.",
+                 pamP->depth);
+    }
+}
+
+
+
+static void
+    describeOutput(struct pam const pam) {
+
+    pm_message("Output is %d x %d x %d, maxval %u",
+               pam.width, pam.height, pam.depth, (unsigned int) pam.maxval);
+}
+
+
+
+int 
+main(int argc, char *argv[]) {
+    FILE *ifP;
+    struct cmdlineInfo cmdline;
+    struct pam diffpam, outpam;
+    unsigned int row;
+    tuple * diffrow;
+    tuple * outrow;
+    tuple * prevrow;
+
+    pnm_init( &argc, argv );
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    pnm_readpaminit(ifP, &diffpam, PAM_STRUCT_SIZE(tuple_type));
+
+    if (diffpam.format != PAM_FORMAT) 
+        pm_error("Input must be a PAM file, not PNM");
+    else if (!STREQ(diffpam.tuple_type, "hdiff")) 
+        pm_error("Input tuple type is '%s'.  Must be 'hdiff'",
+                 diffpam.tuple_type);
+
+    outpam = diffpam;
+    outpam.file = stdout;
+    strcpy(outpam.tuple_type, "unhdiff");
+
+    if (cmdline.verbose)
+        describeOutput(outpam);
+    if (cmdline.pnm)
+        makePnm(&outpam);
+
+    pnm_writepaminit(&outpam);
+
+    diffrow = pnm_allocpamrow(&diffpam);
+    outrow =  pnm_allocpamrow(&outpam);
+    prevrow = pnm_allocpamrow(&diffpam);
+
+    pnm_setpamrow(&diffpam, prevrow, 0);
+
+    {
+        unsigned int const bias = diffpam.maxval/2;
+        
+        for (row = 0; row < diffpam.height; ++row) {
+            unsigned int col;
+            pnm_readpamrow(&diffpam, diffrow);
+            for (col = 0; col < diffpam.width; ++col) {
+                unsigned int plane;
+                for (plane = 0; plane < diffpam.depth; ++plane) {
+                    sample const prevSample = prevrow[col][plane];
+                    sample const diffSample = diffrow[col][plane];
+                    
+                    outrow[col][plane] = 
+                        (-bias + prevSample + diffSample) % (outpam.maxval+1);
+                    prevrow[col][plane] = outrow[col][plane];
+                }
+            }
+            pnm_writepamrow(&outpam, outrow);
+        }
+    }
+    pnm_freepamrow(prevrow);
+    pnm_freepamrow(outrow);
+    pnm_freepamrow(diffrow);
+
+    exit(0);
+}
+
diff --git a/converter/other/infotopam.c b/converter/other/infotopam.c
new file mode 100644
index 00000000..4f29eb07
--- /dev/null
+++ b/converter/other/infotopam.c
@@ -0,0 +1,543 @@
+/* infotopam:  A program to convert Amiga Info icon files to PAM files
+ * Copyright (C) 2004  Richard Griswold - griswold@acm.org
+ *
+ * Thanks to the following people on comp.sys.amiga.programmer for tips
+ * and pointers on decoding the info file format:
+ *
+ *   Ben Hutchings
+ *   Thomas Richter
+ *   Kjetil Svalastog Matheussen
+ *   Anders Melchiorsen
+ *   Dirk Stoecker
+ *   Ronald V.D.
+ *
+ * The format of the Amiga info file is as follows:
+ *
+ *   DiskObject header            (78 bytes)
+ *   Optional DrawerData header   (56 bytes)
+ *   First icon header            (20 bytes)
+ *   First icon data
+ *   Second icon header           (20 bytes)
+ *   Second icon data
+ *
+ * The DiskObject header contains, among other things, the magic number
+ * (0xE310), the object width and height (inside the embedded Gadget header),
+ * and the version.
+ *
+ * Each icon header contains the icon width and height, which can be smaller
+ * than the object width and height, and the number of bit-planes.
+ *
+ * The icon data has the following format:
+ *
+ *   BIT-PLANE planes, each with HEIGHT rows of (WIDTH +15) / 16 * 2 bytes
+ *   length.
+ *
+ * So if you have a 9x3x2 icon, the icon data will look like this:
+ *
+ *   aaaa aaaa a000 0000
+ *   aaaa aaaa a000 0000
+ *   aaaa aaaa a000 0000
+ *   bbbb bbbb b000 0000
+ *   bbbb bbbb b000 0000
+ *   bbbb bbbb b000 0000
+ *
+ * Where 'a' is a bit for the first bit-plane, 'b' is a bit for the second
+ * bit-plane, and '0' is padding.  Thanks again to Ben Hutchings for his
+ * very helpful post!
+ *
+ * This program uses code from "sidplay" and an older "infotoxpm" program I
+ * wrote, both of which are released under GPL.
+ *
+ *-------------------------------------------------------------------------
+ *
+ * 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 "pam.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* Struct to hold miscellaneous icon information */
+typedef struct IconInfo_ {
+    const char  *name;        /* Icon file name */
+    FILE        *fp;          /* Input file pointer */
+
+    bool         forceColor;  /* Convert 1 bitplane icon to color icon */
+    unsigned int numColors;   /* Number of colors to override */
+    bool         selected;    /* Converting selected (second) icon */
+
+    bool         drawerData;  /* Icon has drawer data */
+    unsigned int version;     /* Icon version */
+    unsigned int width;       /* Width in pixels */
+    unsigned int height;      /* Height in pixels */
+    unsigned int depth;       /* Bits of color per pixel */
+    pixel        colors[4];   /* Colors to use for converted icons */
+    unsigned char *icon;      /* Completed icon */
+
+} IconInfo;
+
+/* Header for each icon image */
+typedef struct IconHeader_ { /* 20 bytes */
+    unsigned char pad0[4];        /* Padding (always seems to be zero) */
+    unsigned char iconWidth[2];   /* Width (usually equal to Gadget width) */
+    unsigned char iconHeight[2];  
+    /* Height (usually equal to Gadget height -1) */
+    unsigned char bpp[2];         /* Bits per pixel */
+    unsigned char pad1[10];       /* ??? */
+} IconHeader;
+
+/*
+ * Gadget and DiskObject structs come from the libsidplay 1.36.57 info_.h file
+ * http://www.geocities.com/SiliconValley/Lakes/5147/sidplay/linux.html
+ */
+typedef struct DiskObject_ { /* 78 bytes (including Gadget struct) */
+    unsigned char magic[2];         /* Magic number at the start of the file */
+    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 pDefaultTool[4];  /* Pointer  to default tool */
+    unsigned char ppToolTypes[4];   /* Pointer pointer to tool types */
+    unsigned char currentX[4];      /* Current X position (?) */
+    unsigned char currentY[4];      /* Current Y position (?) */
+    unsigned char pDrawerData[4];   /* Pointer to drawer data */
+    unsigned char pToolWindow[4];   /* Ptr to tool window - only for tools */
+    unsigned char stackSize[4];     /* Stack size - only for tools */
+} DiskObject;
+
+
+
+static void
+parseCommandLine( int              argc,
+                  char *           argv[],
+                  IconInfo * const infoP ) {
+
+    unsigned int numColorArgs,  /* Number of arguments for overriding colors */
+        colorIdx,      /* Color index */
+        i;             /* Argument index */
+    const char  * const colors[4] = { 
+        /* Pixel colors based on original Amiga colors */
+        "#0055AA",    /*   Blue      0,  85, 170 */
+        "#FFFFFF",    /*   White   255, 255, 255 */
+        "#000020",    /*   Black     0,   0,  32 */
+        "#FF8A00"     /*   Orange  255, 138,   0 */
+    };
+
+    /* Option entry variables */
+    optEntry     *option_def;
+    optStruct3    opt;
+    unsigned int  option_def_index;
+    unsigned int numColorsSpec, forceColorSpec, selectedSpec;
+  
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    /* Set command line options */
+    option_def_index = 0;   /* Incremented by OPTENT3 */
+    OPTENT3(0, "forcecolor", OPT_FLAG, NULL, &forceColorSpec, 0);
+    OPTENT3(0, "numcolors",  OPT_UINT, &infoP->numColors, &numColorsSpec, 0);
+    OPTENT3(0, "selected",   OPT_FLAG, NULL, &selectedSpec,   0);
+
+    /* Initialize the iconInfo struct */
+    infoP->name = NULL;
+    infoP->fp = NULL;
+    infoP->drawerData = FALSE;
+    infoP->version = 0;
+    infoP->width = 0;
+    infoP->height = 0;
+    infoP->depth = 0;
+    infoP->icon = NULL;
+    for ( colorIdx = 0; colorIdx < 4; colorIdx++ )
+        infoP->colors[colorIdx] = 
+            ppm_parsecolor( (char*) colors[colorIdx], 0xFF );
+
+    /* Initialize option structure */
+    opt.opt_table     = option_def;
+    opt.short_allowed = FALSE;  /* No short (old-fashioned) options */
+    opt.allowNegNum   = FALSE;  /* No negative number parameters */
+
+    /* Parse the command line */
+    optParseOptions3( &argc, argv, opt, sizeof( opt ), 0 );
+
+    infoP->forceColor = forceColorSpec;
+    infoP->selected = selectedSpec;
+    if (!numColorsSpec)
+        infoP->numColors = 0;
+
+    /* Get colors and file name */
+    numColorArgs = infoP->numColors * 2;
+    if ( ( argc - 1 != numColorArgs ) && ( argc - 1 != numColorArgs + 1 ) ) {
+        pm_error( "Wrong number of arguments for number of colors.  "
+                  "For %u colors, you need %u color arguments, "
+                  "with possibly one more argument for the input file name.",
+                  infoP->numColors, numColorArgs );
+    }
+
+    /* Convert color arguments */
+    for ( i = 1; i < numColorArgs; i += 2 ) {
+        char *       endptr;        /* End pointer for strtol() */
+        unsigned int colorIdx;
+
+        /* Get color index from argument */
+        colorIdx = strtoul( argv[i], &endptr, 0 );
+
+        if ( *endptr != '\0' ) {
+            pm_error( "'%s' is not a valid color index", argv[i] );
+        }
+
+        /* Check color index range (current 0 to 3) */
+        if ( ( colorIdx < 0 ) || ( colorIdx > 3 ) ) {
+            pm_error( "%u is not a valid color index (minimum 0, maximum 3)",
+                      colorIdx );
+        }
+
+        /* Convert the color for this color index */
+        infoP->colors[colorIdx] = ppm_parsecolor( argv[i+1], 0xFF );
+    }
+
+    /* Set file name */
+    if ( i > argc-1 )
+        infoP->name = "-";  /* Read from standard input */
+    else
+        infoP->name = argv[i];
+}
+
+
+
+static void
+getDiskObject( IconInfo * const infoP ) {
+/*-------------------------------------------------------------------------
+ * Get fields from disk object portion of info file
+ *-------------------------------------------------------------------------*/
+    DiskObject  dobj;      /* Disk object structure */
+    size_t      bytesRead;
+
+    /* 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) );
+
+    /* 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] );
+
+    /* 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;
+}
+
+
+
+static void 
+getIconHeader( IconInfo * const infoP ) {
+/*-------------------------------------------------------------------------
+ * Get fields from icon header portion of info file
+ *-------------------------------------------------------------------------*/
+    IconHeader  ihead;      /* Icon header structure */
+    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) );
+
+    /* 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];
+
+    /* 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 );
+}
+
+
+
+static void
+addBitplane(unsigned char * const icon,
+            unsigned int    const bpsize,
+            unsigned char * const buff) {
+/*----------------------------------------------------------------------------
+   Add bitplane to existing icon image
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+    unsigned int j;
+    
+    for (i = j = 0; i < bpsize; ++i, j += 8) {
+        icon[j+0] = (icon[j+0] << 1) | ((buff[i] >> 0) & 0x01);
+        icon[j+1] = (icon[j+1] << 1) | ((buff[i] >> 1) & 0x01);
+        icon[j+2] = (icon[j+2] << 1) | ((buff[i] >> 2) & 0x01);
+        icon[j+3] = (icon[j+3] << 1) | ((buff[i] >> 3) & 0x01);
+        icon[j+4] = (icon[j+4] << 1) | ((buff[i] >> 4) & 0x01);
+        icon[j+5] = (icon[j+5] << 1) | ((buff[i] >> 5) & 0x01);
+        icon[j+6] = (icon[j+6] << 1) | ((buff[i] >> 6) & 0x01);
+        icon[j+7] = (icon[j+7] << 1) | ((buff[i] >> 7) & 0x01);
+    }
+}
+
+
+
+static void
+readIconData(FILE *           const fileP,
+             unsigned int     const width,
+             unsigned int     const height, 
+             unsigned int     const depth,
+             unsigned char ** const iconP) {
+/*-------------------------------------------------------------------------
+ * Read icon data from file
+ *-------------------------------------------------------------------------*/
+    int             bitplane; /* Bitplane index */
+    unsigned char * buff;     /* Buffer to hold bits for 1 bitplane */
+    unsigned char * icon;
+
+    unsigned int const bpsize = height * (((width + 15) / 16) * 2);
+        /* Bitplane size in bytes, with padding */
+
+  
+    MALLOCARRAY(buff, bpsize);
+    if ( buff == NULL )
+        pm_error( "Cannot allocate memory to hold icon pixels" );
+
+    MALLOCARRAY(icon, bpsize * 8);
+    if (icon == NULL)
+        pm_error( "Cannot allocate memory to hold icon" );
+
+    /* Initialize to zero */
+    memset(buff, 0, bpsize);
+    memset(icon, 0, bpsize * 8);
+
+    /* Each bitplane is stored independently in the icon file.  This
+     * loop reads one bitplane at a time into buff.  Since fread() may
+     * not read all of the bitplane on the first call, the inner loop
+     * continues until all bytes are read.  The buffer pointer, bp,
+     * points to the next byte in buff to fill in.  When the inner
+     * loop is done, bp points to the end of buff.
+     *
+     * After reading in the entire bitplane, the second inner loop splits the 
+     * eight pixels in each byte of the bitplane into eight separate bytes in 
+     * the icon buffer.  The existing contents of each byte in icon are left 
+     * shifted by one to make room for the next bit. 
+     *
+     * Each byte in the completed icon contains a value from 0 to
+     * 2^depth (0 to 1 for depth of 1 and 0 to 3 for a depth of 3).
+     * This is an index into the colors array in the info struct.  */
+
+    for (bitplane = 0; bitplane < depth; ++bitplane) {
+        /* Read bitplane into buffer */
+        int toread;   /* Number of bytes left to read */
+        unsigned char * buffp;    /* Buffer point for reading data */
+       
+        toread = bpsize; buffp = &buff[0];
+
+        while (toread > 0) {
+            size_t bytesRead;
+
+            bytesRead = fread(buffp, 1, toread, fileP);
+            if (ferror(fileP))
+                pm_error("Cannot read from file info file.  "
+                         "fread() errno = %d (%s)",
+                         errno, strerror(errno));
+            else if (bytesRead == 0)
+                pm_error("Premature end-of-file.  "
+                         "Still have 0x%X bytes to read",
+                         toread );
+            
+            toread -= bytesRead;
+            buffp  += bytesRead;
+        }
+        addBitplane(icon, bpsize, buff);
+    }
+    *iconP = icon;
+
+    free(buff);
+}
+
+
+
+static void
+writeIconData( IconInfo *   const infoP,
+               struct pam * const pamP ) {
+/*-------------------------------------------------------------------------
+ * Write icon data to file
+ *-------------------------------------------------------------------------*/
+    unsigned int const bpwidth = ( ( infoP->width + 15 ) / 16 ) * 16;
+        /* Bitplane width; Width of each row in icon, including padding */
+
+    tuple * row;      /* Output row */
+
+    /* Allocate row */
+    row = pnm_allocpamrow( pamP );
+
+    /* Write icon image to output file */
+    /* Put if check outside for loop to reduce number of times check is made */
+    if ( infoP->depth == 1 ) {
+        if ( infoP->forceColor ) {
+            /* Convert 1 bitplane icon into color PAM */
+            unsigned int i;
+            for ( i = 0; i < infoP->height; ++i ) {
+                unsigned int j;
+                for ( j = 0; j < infoP->width; ++j ) {
+                    /* 1 is black and 0 is white */
+                    unsigned int colorIdx =
+                        infoP->icon[ i * bpwidth + j ] ? 2 : 1;
+                    row[j][PAM_RED_PLANE] =
+                        PPM_GETR( infoP->colors[colorIdx] );
+                    row[j][PAM_GRN_PLANE] =
+                        PPM_GETG( infoP->colors[colorIdx] );
+                    row[j][PAM_BLU_PLANE] =
+                        PPM_GETB( infoP->colors[colorIdx] );
+                }
+                pnm_writepamrow( pamP, row );
+            }
+        } else {
+            /* Convert 1 bitplane icon into bitmap PAM */
+            unsigned int i;
+            for ( i = 0; i < infoP->height; ++i ) {
+                unsigned int j;
+                for ( j = 0; j < infoP->width; j++ ) {
+                    /* 1 is black and 0 is white */
+                    row[j][0] = infoP->icon[ i * bpwidth + j ] ? 0 : 1;
+                }
+                pnm_writepamrow( pamP, row );
+            }
+        }
+    } else {
+        /* Convert color icon into color PAM */
+        unsigned int i;
+        for ( i = 0; i < infoP->height; ++i ) {
+            unsigned int j;
+            for ( j = 0; j < infoP->width; ++j ) {
+                unsigned int const colorIdx = infoP->icon[ i * bpwidth + j ];
+                row[j][PAM_RED_PLANE] = PPM_GETR( infoP->colors[colorIdx] );
+                row[j][PAM_GRN_PLANE] = PPM_GETG( infoP->colors[colorIdx] );
+                row[j][PAM_BLU_PLANE] = PPM_GETB( infoP->colors[colorIdx] );
+            }
+            pnm_writepamrow( pamP, row );
+        }
+    }
+
+    /* Clean up allocated memory */
+    pnm_freepamrow( row );
+}
+
+
+
+int
+main( int argc,
+      char *argv[] ) {
+
+    IconInfo    info;    /* Miscellaneous icon information */
+    struct pam  pam;     /* PAM header */
+    int         skip;    /* Bytes to skip to read next icon header */
+
+    /* Init PNM library */
+    pnm_init( &argc, argv );
+
+    /* Parse command line arguments */
+    parseCommandLine( argc, argv, &info );
+
+    /* Open input file */
+    info.fp = pm_openr( info.name );
+
+    /* Read disk object header */
+    getDiskObject( &info );
+
+    /* Skip drawer data, if any */
+    if ( info.drawerData ) {
+        skip = 56;   /* Draw data size */
+        if ( fseek( info.fp, skip, SEEK_CUR ) < 0 )
+            pm_error( "Cannot skip header information in file '%s'.  "
+                      "fseek() errno = %d (%s)",
+                      info.name, errno, strerror( errno ) );
+    }
+
+    /* Get dimensions for first icon */
+    getIconHeader( &info );
+
+    /* Skip ahead to next header if converting second icon */
+    if ( info.selected ) {
+        skip = info.height * ( ( ( info.width + 15 ) / 16 ) * 2 ) * info.depth;
+
+        if ( fseek( info.fp, skip, SEEK_CUR ) < 0 )
+            pm_error( "Cannot skip to next icon in file '%s'.  "
+                      "fseek() errno = %d (%s)",
+                      info.name, errno, strerror( errno ) );
+
+        /* Get dimensions for second icon */
+        getIconHeader( &info );
+    }
+
+    /* Read icon data */
+    readIconData( info.fp, info.width, info.height, info.depth, &info.icon );
+
+    /* Print icon info */
+    pm_message( "converting %s, version %d, %s icon: %d X %d X %d",
+                info.name, info.version, info.selected ? "second" : "first",
+                info.width, info.height, info.depth );
+
+    /* Write PAM header */
+    pam.size   = sizeof( pam );
+    pam.len    = PAM_STRUCT_SIZE( tuple_type );
+    pam.file   = stdout;
+    pam.height = info.height;
+    pam.width  = info.width;
+    pam.format = PAM_FORMAT;
+
+    if ( ( info.depth == 1 ) && ( info.forceColor == FALSE ) ) {
+        pam.depth  = 1;
+        pam.maxval = 1;
+        strcpy( pam.tuple_type, "BLACKANDWHITE" );
+    } else {
+        pam.depth  = 3;
+        pam.maxval = 0xFF;
+        strcpy( pam.tuple_type, "RGB" );
+    }
+    pnm_writepaminit( &pam );
+
+    /* Write icon data */
+    writeIconData( &info, &pam );
+
+    free( info.icon );
+
+    /* Close input file and return */
+    pm_close( pam.file );
+    pm_close( info.fp );
+
+    return 0;
+}
diff --git a/converter/other/jbig/ANNOUNCE b/converter/other/jbig/ANNOUNCE
new file mode 100644
index 00000000..edbcc3f8
--- /dev/null
+++ b/converter/other/jbig/ANNOUNCE
@@ -0,0 +1,243 @@
+
+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",
+  <http://www.itu.ch/itudoc/itu-t/rec/t/t82_23822.html>,
+
+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 <benrg@math.berkeley.edu> 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 <saiga@itl.tnr.sharp.co.jp> 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
+    <Stefan.Willer@unnet.wupper.DE>
+
+  - 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 <jpg11@calvanet.calvacom.fr>)
+
+  - 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: <http://www.cl.cam.ac.uk/~mgk25/>
diff --git a/converter/other/jbig/Makefile b/converter/other/jbig/Makefile
new file mode 100644
index 00000000..ca98ef29
--- /dev/null
+++ b/converter/other/jbig/Makefile
@@ -0,0 +1,47 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/jbig
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+LIBJBIG_OBJECTS = jbig.o jbig_tab.o
+
+INCLUDES =
+ifneq ($(JBIGHDR_DIR),NONE)
+  INCLUDES += -I$(JBIGHDR_DIR)
+endif
+
+ifneq ($(JBIGHDR_DIR),NONE)
+  ifneq ($(JBIGLIB),NONE)
+    BINARIES = jbigtopnm pnmtojbig
+  endif
+endif
+
+SCRIPTS =
+
+ifeq ($(JBIGLIB),$(BUILDDIR)/$(SUBDIR)/libjbig.a)
+  JBIGLIB_DEP = $(JBIGLIB)
+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)
+
+all: $(BINARIES)
+
+include $(SRCDIR)/Makefile.common
+
+$(BINARIES): %: %.o $(JBIGLIB_DEP) $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $< \
+	  $(shell $(LIBOPT) $(NETPBMLIB) $(JBIGLIB)) $(MATHLIB) $(LDLIBS) \
+	  $(RPATH) $(LADD)
+
+
+$(BUILDDIR)/$(SUBDIR)/libjbig.a: $(LIBJBIG_OBJECTS)
+	$(AR) -rc $@ $^
+	$(RANLIB) $@
+
diff --git a/converter/other/jbig/README.Netpbm b/converter/other/jbig/README.Netpbm
new file mode 100644
index 00000000..3d593b92
--- /dev/null
+++ b/converter/other/jbig/README.Netpbm
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 00000000..ebd7c08f
--- /dev/null
+++ b/converter/other/jbig/jbig.c
@@ -0,0 +1,2905 @@
+/*
+ *  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 <stdio.h>
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+
+#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
new file mode 100644
index 00000000..10eeda80
--- /dev/null
+++ b/converter/other/jbig/jbig.doc
@@ -0,0 +1,721 @@
+
+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 <http://www.itu.ch/> or <http://www.iso.ch/>.
+
+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 <stdio.h>
+#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)
+  <http://www.cl.cam.ac.uk/~mgk25/kuhn-sta.pdf>
+
+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
new file mode 100644
index 00000000..dd9a76f3
--- /dev/null
+++ b/converter/other/jbig/jbig.h
@@ -0,0 +1,267 @@
+/*
+ *  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 <stddef.h>
+
+/*
+ * 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
new file mode 100644
index 00000000..55183503
--- /dev/null
+++ b/converter/other/jbig/jbig_tab.c
@@ -0,0 +1,428 @@
+/*
+ *  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
new file mode 100644
index 00000000..7a6e95c1
--- /dev/null
+++ b/converter/other/jbig/jbigtopnm.c
@@ -0,0 +1,286 @@
+/*
+    jbigtopnm - JBIG to PNM converter
+  
+    This program was derived from jbgtopbm.c in Markus Kuhn's
+    JBIG-KIT package by Bryan Henderson on 2000.05.11
+
+    The main difference is that this version uses the Netpbm libraries.
+  
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <jbig.h>
+#include "pnm.h"
+
+#define BUFSIZE 8192
+
+
+static void
+collect_image (unsigned char *data, size_t len, void *image) {
+    static int cursor = 0;
+    int i;
+
+    for (i = 0; i < len; i++) {
+        ((unsigned char *)image)[cursor++] = data[i];
+    }
+}
+
+
+
+static void 
+write_pnm (FILE *fout, const unsigned char * const image, const int bpp,
+           const int rows, const int cols, const int maxval,
+           const int format) {
+
+    int row;
+    xel *pnm_row;
+
+    pnm_writepnminit(fout, cols, rows, maxval, format, 0);
+
+    pnm_row = pnm_allocrow(cols);
+
+    for (row = 0; row < rows; row++) {
+        int col;
+        for (col = 0; col < cols; col++) {
+            int j;
+            for (j = 0; j < bpp; j++)
+                PNM_ASSIGN1(pnm_row[col], 
+                            image[(((row*cols)+col) * bpp) + j]);
+        }
+        pnm_writepnmrow(fout, pnm_row, cols, maxval, format, 0);
+    }
+    
+    pnm_freerow(pnm_row);
+}
+
+
+
+static void
+write_raw_pbm(FILE * const fout, 
+              const unsigned char * const binary_image,
+              int                   const cols,
+              int                   const rows) { 
+
+    unsigned int const bytes_per_row = pbm_packed_bytes(cols);
+
+    int row;
+
+    pbm_writepbminit(fout, cols, rows, 0);
+
+    for (row = 0; row < rows; ++row)
+        pbm_writepbmrow_packed(fout, &binary_image[row*bytes_per_row], cols, 
+                               0);
+}
+
+
+
+/*
+ *
+ */
+static void 
+diagnose_bie(FILE *f)
+{
+  unsigned char bih[20];
+  int len;
+  unsigned long xd, yd, l0;
+
+  len = fread(bih, 1, 20, f);
+  if (len < 20) {
+    printf("Input file is %d < 20 bytes long and does therefore not "
+	   "contain an intact BIE header!\n", len);
+    return;
+  }
+
+  printf("Decomposition of BIH:\n\n  DL = %d\n  D  = %d\n  P  = %d\n"
+	 "  -  = %d\n  XD = %lu\n  YD = %lu\n  L0 = %lu\n  MX = %d\n"
+	 "  MY = %d\n",
+	 bih[0], bih[1], bih[2], bih[3],
+	 xd = ((unsigned long) bih[ 4] << 24) | ((unsigned long)bih[ 5] << 16)|
+	 ((unsigned long) bih[ 6] <<  8) | ((unsigned long) bih[ 7]),
+	 yd = ((unsigned long) bih[ 8] << 24) | ((unsigned long)bih[ 9] << 16)|
+	 ((unsigned long) bih[10] <<  8) | ((unsigned long) bih[11]),
+	 l0 = ((unsigned long) bih[12] << 24) | ((unsigned long)bih[13] << 16)|
+	 ((unsigned long) bih[14] <<  8) | ((unsigned long) bih[15]),
+	 bih[16], bih[17]);
+  printf("  order   = %d %s%s%s%s%s\n", bih[18],
+	 bih[18] & JBG_HITOLO ? " HITOLO" : "",
+	 bih[18] & JBG_SEQ ? " SEQ" : "",
+	 bih[18] & JBG_ILEAVE ? " ILEAVE" : "",
+	 bih[18] & JBG_SMID ? " SMID" : "",
+	 bih[18] & 0xf0 ? " other" : "");
+  printf("  options = %d %s%s%s%s%s%s%s%s\n", bih[19],
+	 bih[19] & JBG_LRLTWO ? " LRLTWO" : "",
+	 bih[19] & JBG_VLENGTH ? " VLENGTH" : "",
+	 bih[19] & JBG_TPDON ? " TPDON" : "",
+	 bih[19] & JBG_TPBON ? " TPBON" : "",
+	 bih[19] & JBG_DPON ? " DPON" : "",
+	 bih[19] & JBG_DPPRIV ? " DPPRIV" : "",
+	 bih[19] & JBG_DPLAST ? " DPLAST" : "",
+	 bih[19] & 0x80 ? " other" : "");
+  printf("\n  %lu stripes, %d layers, %d planes\n\n",
+	 ((yd >> bih[1]) +  ((((1UL << bih[1]) - 1) & xd) != 0) + l0 - 1) / l0,
+	 bih[1] - bih[0], bih[2]);
+
+  return;
+}
+
+
+int main (int argc, char **argv)
+{
+    FILE *fin = stdin, *fout = stdout;
+    const char *fnin = "<stdin>", *fnout = "<stdout>";
+    int i, j, result;
+    int all_args = 0, files = 0;
+    struct jbg_dec_state s;
+    char *buffer;
+    unsigned char *p;
+    size_t len, cnt;
+    unsigned long xmax = 4294967295UL, ymax = 4294967295UL;
+    int plane = -1, use_graycode = 1, diagnose = 0;
+
+    pnm_init(&argc, argv);
+
+    buffer = malloc(BUFSIZE);
+    if (!buffer)
+        pm_error("Sorry, not enough memory available!");
+
+    /* parse command line arguments */
+    for (i = 1; i < argc; i++) {
+        if (!all_args && argv[i][0] == '-') {
+            if (argv[i][1] == '\0' && files == 0)
+                ++files;
+            else {
+                for (j = 1; j > 0 && argv[i][j]; j++) {
+                    switch(tolower(argv[i][j])) {
+                    case '-' :
+                        all_args = 1;
+                        break;
+                    case 'b':
+                        use_graycode = 0;
+                        break;
+                    case 'd':
+                        diagnose = 1;
+                        break;
+                    case 'x':
+                        if (++i >= argc)
+                            pm_error("-x needs a value");
+                        xmax = atol(argv[i]);
+                        j = -1;
+                        break;
+                    case 'y':
+                        if (++i >= argc)
+                            pm_error("-y needs a value");
+                        ymax = atol(argv[i]);
+                        j = -1;
+                        break;
+                    case 'p':
+                        if (++i >= argc)
+                            pm_error("-p needs a value");
+                        plane = atoi(argv[i]);
+                        j = -1;
+                        break;
+                    default:
+                        pm_error("Unrecognized option: %c", argv[i][j]);
+                    }
+                }
+            }
+        } else {
+            switch (files++) {
+            case 0:
+                if (argv[i][0] != '-' || argv[i][1] != '\0') {
+                    fnin = argv[i];
+                    fin = fopen(fnin, "rb");
+                    if (!fin)
+                        pm_error("Can't open input file '%s'", fnin);
+                }
+                if (diagnose) {
+                    diagnose_bie(fin);
+                    exit(0);
+                }
+                break;
+            case 1:
+                fnout = argv[i];
+                fout = fopen(fnout, "wb");
+                if (!fout)
+                    pm_error("Can't open output file '%s'", fnout);
+                break;
+            default:
+                pm_error("Too many non-option arguments");
+            }
+        }
+    }
+
+    /* send input file to decoder */
+    jbg_dec_init(&s);
+    jbg_dec_maxsize(&s, xmax, ymax);
+    result = JBG_EAGAIN;
+    do {
+        len = fread(buffer, 1, BUFSIZE, fin);
+        if (!len) break;
+        cnt = 0;
+        p = (unsigned char *) buffer;
+        while (len > 0 && (result == JBG_EAGAIN || result == JBG_EOK)) {
+            result = jbg_dec_in(&s, p, len, &cnt);
+            p += cnt;
+            len -= cnt;
+        }
+    } while (result == JBG_EAGAIN || result == JBG_EOK);
+    if (ferror(fin)) 
+        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));
+    if (plane >= 0 && jbg_dec_getplanes(&s) <= plane) 
+        pm_error("Image has only %d planes!\n", jbg_dec_getplanes(&s));
+
+    {
+        /* Write it out */
+
+        int rows, cols;
+        int maxval;
+        int bpp;
+        int plane_to_write;
+
+        cols = jbg_dec_getwidth(&s);
+        rows = jbg_dec_getheight(&s);
+        maxval = pm_bitstomaxval(jbg_dec_getplanes(&s));
+        bpp = (jbg_dec_getplanes(&s)+7)/8;
+
+        if (jbg_dec_getplanes(&s) == 1) 
+            plane_to_write = 0;
+        else 
+            plane_to_write = plane;
+
+        if (plane_to_write >= 0) {
+            /* Write just one plane */
+            unsigned char * binary_image;
+
+            pm_message("WRITING PBM FILE");
+
+            binary_image=jbg_dec_getimage(&s, plane_to_write);
+            write_raw_pbm(fout, binary_image, cols, rows);
+        } else {
+            unsigned char *image;
+            pm_message("WRITING PGM FILE");
+
+            /* Write out all the planes */
+            /* What jbig.doc doesn't tell you is that jbg_dec_merge_planes
+               delivers the image in chunks, in consecutive calls to 
+               the data-out callback function.  And a row can span two
+               chunks.
+            */
+            image = malloc(cols*rows*bpp);
+            jbg_dec_merge_planes(&s, use_graycode, collect_image, image);
+            write_pnm(fout, image, bpp, rows, cols, maxval, PGM_TYPE);
+            free(image);
+        }
+    }
+  
+    pm_close(fout);
+
+    jbg_dec_free(&s);
+
+    return 0;
+}
diff --git a/converter/other/jbig/pnmtojbig.c b/converter/other/jbig/pnmtojbig.c
new file mode 100644
index 00000000..9dbef3fa
--- /dev/null
+++ b/converter/other/jbig/pnmtojbig.c
@@ -0,0 +1,463 @@
+/*
+    pnmtojbig - PNM to JBIG converter
+  
+    This program was derived from pbmtojbg.c in Markus Kuhn's
+    JBIG-KIT package by Bryan Henderson on 2000.05.11
+
+    The main difference is that this version uses the Netpbm libraries.
+
+ */
+
+/*
+     The JBIG standard doesn't say which end of the scale is white and
+     which end is black in a BIE.  It has a recommendation in terms of
+     foreground and background (a concept which does not exist in the
+     Netpbm formats) for single-plane images, and is silent for
+     multi-plane images.
+
+     Kuhn's implementation of the JBIG standard says if the BIE has a
+     single plane, then in that plane a zero bit means white and a one
+     bit means black.  But if it has multiple planes, a composite zero
+     value means black and a composite maximal value means white.
+
+     Actually, Kuhn's pbmtojbg doesn't even implement this, but rather
+     bases the distinction on whether the input file was PBM or PGM.
+     This means that if you convert a PGM file with maxval 1 to a JBIG
+     file and then back, the result (which is a PBM file) is the
+     inverse of what you started with.  Same if the PGM file has
+     maxval > 1 but you use a -t option to write only one plane.  We
+     assume this is just a bug in pbmtojpg and that hardly anybody does
+     this.  So we adopt the implementation described above.
+
+     This means that after jbg_split_planes() hands us a set of bitmap
+     planes, if there is only one of them, we have to invert all the
+     bits in it.
+
+*/
+  
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <jbig.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "pnm.h"
+
+static unsigned long total_length = 0;  
+  /* used for determining output file length */
+
+/*
+ * malloc() with exception handler
+ */
+static void
+*checkedmalloc(size_t n)
+{
+  void *p;
+  
+  if ((p = malloc(n)) == NULL) {
+    fprintf(stderr, "Sorry, not enough memory available!\n");
+    exit(1);
+  }
+  
+  return p;
+}
+
+
+/*
+ * Callback procedure which is used by JBIG encoder to deliver the
+ * encoded data. It simply sends the bytes to the output file.
+ */
+static void data_out(unsigned char *start, size_t len, void *file)
+{
+  fwrite(start, len, 1, (FILE *) file);
+  total_length += len;
+  return;
+}
+
+
+
+static void
+readPbm(FILE *            const fin,
+        unsigned int      const cols,
+        unsigned int      const rows,
+        unsigned char *** const bitmapP) {
+
+    unsigned int const bytes_per_line = pbm_packed_bytes(cols);
+
+    unsigned char ** bitmap;
+
+    /* Read the input image into bitmap[] */
+    /* Shortcut for PBM */
+    int row;
+    bitmap = (unsigned char **) checkedmalloc(sizeof(unsigned char *));
+    bitmap[0] = (unsigned char *) checkedmalloc(bytes_per_line * rows);
+    
+    for (row = 0; row < rows; row++)
+        pbm_readpbmrow_packed(fin, &bitmap[0][row*bytes_per_line],
+                              cols, RPBM_FORMAT);
+
+    *bitmapP = bitmap;
+} 
+
+
+
+static void
+readImage(FILE * const fin,
+          unsigned int     const cols,
+          unsigned int     const rows,
+          xelval           const maxval,
+          int              const format,
+          unsigned int     const bpp,
+          unsigned char ** const imageP) {
+/*----------------------------------------------------------------------------
+  Read the input image and put it into *imageP;
+
+  Although the PBM case is separated, this logic works also for
+  PBM, bpp=1.
+-----------------------------------------------------------------------------*/
+    unsigned char *image;
+        /* This is a representation of the entire image with 'bpp' bytes per
+           pixel.  The 'bpp' bytes for each pixel are arranged MSB first
+           and its numerical value is the value from the PNM input.
+           The pixels are laid out in row-major format in this rectangle.
+           
+           The point of this data structure is it is what jbg_split_planes()
+           wants for input.
+        */
+    xel* pnm_row;
+    unsigned int row;
+
+    pnm_row = pnm_allocrow(cols);  /* row buffer */
+    MALLOCARRAY_NOFAIL(image, cols * rows * bpp);
+    
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        pnm_readpnmrow(fin, pnm_row, cols, maxval, format);
+        for (col = 0; col < cols; col++) {
+            unsigned int j;
+            /* Move each byte of the sample into image[], MSB first */
+            for (j = 0; j < bpp; ++j)
+                image[(((row*cols)+col) * bpp) + j] = (unsigned char)
+                    PNM_GET1(pnm_row[col]) >> ((bpp-1-j) * 8);
+        }
+    }
+    pnm_freerow(pnm_row);
+    *imageP = image;
+}
+      
+
+
+static void
+convertImageToBitmap(unsigned char *   const image,
+                     unsigned char *** const bitmapP,
+                     unsigned int      const encode_planes,
+                     unsigned int      const bytes_per_line,
+                     unsigned int      const lines) {
+    
+    /* Convert image[] into bitmap[]  */
+    
+    unsigned char ** bitmap;
+    unsigned int i;
+    
+    MALLOCARRAY_NOFAIL(bitmap, encode_planes);
+    for (i = 0; i < encode_planes; ++i)
+        MALLOCARRAY_NOFAIL(bitmap[i], bytes_per_line * lines);
+
+    *bitmapP = bitmap;
+}
+
+
+
+static void
+readPnm(FILE *            const fin,
+        unsigned int      const cols,
+        unsigned int      const rows,
+        xelval            const maxval,
+        int               const format,
+        unsigned int      const bpp,
+        unsigned int      const planes,
+        unsigned int      const encode_planes,
+        bool              const use_graycode,
+        unsigned char *** const bitmapP) {
+
+    unsigned int const bytes_per_line = pbm_packed_bytes(cols);
+
+    unsigned char * image;
+    unsigned char ** bitmap;
+
+    readImage(fin, cols, rows, maxval, format, bpp, &image);
+
+    convertImageToBitmap(image, &bitmap, encode_planes, bytes_per_line, rows);
+
+    jbg_split_planes(cols, rows, planes, encode_planes, image, bitmap,
+                     use_graycode);
+    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,
+       this is for exceptional PGM files.  
+    */
+
+    if (encode_planes == 1) {
+        unsigned int row;
+        for (row = 0; row < rows; ++row) {
+            unsigned int i;
+            for (i = 0; i < bytes_per_line; i++)
+                bitmap[0][(row*bytes_per_line) + i] ^= 0xff;
+
+            if (cols % 8 > 0) {   
+                bitmap[0][ (row+1)*bytes_per_line  -1] >>= 8-cols%8;
+                bitmap[0][ (row+1)*bytes_per_line  -1] <<= 8-cols%8;
+            }
+        }
+    }
+    *bitmapP = bitmap;
+}
+
+
+
+int
+main(int argc, char **argv) {
+    FILE *fin = stdin, *fout = stdout;
+    const char *fnin = "<stdin>", *fnout = "<stdout>";
+    int i;
+    int all_args = 0, files = 0;
+    int bpp, planes, encode_planes = -1;
+    int cols, rows;
+    xelval maxval;
+    int format;
+    unsigned char **bitmap;
+    /* This is an array of the planes of the image.  Each plane is a
+       two-dimensional array of pixels laid out in row-major format.
+       format with each pixel being one bit.  A byte in the array 
+       contains 8 pixels left to right, msb to lsb.
+    */
+
+    struct jbg_enc_state s;
+    int verbose = 0, delay_at = 0, use_graycode = 1;
+    long mwidth = 640, mheight = 480;
+    int dl = -1, dh = -1, d = -1, l0 = -1, mx = -1;
+    int options = JBG_TPDON | JBG_TPBON | JBG_DPON;
+    int order = JBG_ILEAVE | JBG_SMID;
+
+    pbm_init(&argc, argv);
+
+    /* parse command line arguments */
+    for (i = 1; i < argc; ++i) {
+        int j;
+        if (!all_args && argv[i][0] == '-') {
+            if (argv[i][1] == '\0' && files == 0)
+                ++files;
+            else {
+                for (j = 1; j > 0 && argv[i][j]; j++) {
+                    switch(tolower(argv[i][j])) {
+                    case '-' :
+                        all_args = 1;
+                        break;
+                    case 'v':
+                        verbose = 1;
+                        break;
+                    case 'b':
+                        use_graycode = 0;
+                        break;
+                    case 'c':
+                        delay_at = 1;
+                        break;
+                    case 'x':
+                        if (++i >= argc)
+                            pm_error("-x needs a value");
+                        j = -1;
+                        mwidth = atol(argv[i]);
+                        break;
+                    case 'y':
+                        if (++i >= argc)
+                            pm_error("-y needsa  value");
+                        j = -1;
+                        mheight = atol(argv[i]);
+                        break;
+                    case 'o':
+                        if (++i >= argc)
+                            pm_error("-o needs a value");
+                        j = -1;
+                        order = atoi(argv[i]);
+                        break;
+                    case 'p':
+                        if (++i >= argc)
+                            pm_error("-p needs a value");
+                        j = -1;
+                        options = atoi(argv[i]);
+                        break;
+                    case 'l':
+                        if (++i >= argc)
+                            pm_error("-l needs a value");
+                        j = -1;
+                        dl = atoi(argv[i]);
+                        break;
+                    case 'h':
+                        if (++i >= argc)
+                            pm_error("-h needs a value");
+                        j = -1;
+                        dh = atoi(argv[i]);
+                        break;
+                    case 'q':
+                        d = 0;
+                        break;
+                    case 'd':
+                        if (++i >= argc)
+                            pm_error("-d needs a value");
+                        j = -1;
+                        d = atoi(argv[i]);
+                        break;
+                    case 's':
+                        if (++i >= argc)
+                            pm_error("-s needs a value");
+                        j = -1;
+                        l0 = atoi(argv[i]);
+                        break;
+                    case 't':
+                        if (++i >= argc)
+                            pm_error("-t needs a value");
+                        j = -1;
+                        encode_planes = atoi(argv[i]);
+                        break;
+                    case 'm':
+                        if (++i >= argc)
+                            pm_error("-m needs a value");
+                        j = -1;
+                        mx = atoi(argv[i]);
+                        break;
+                    default:
+                        pm_error("Unrecognized option: %c", argv[i][j]);
+                    }
+                }
+            }
+        } else {
+            switch (files++) {
+            case 0:
+                if (argv[i][0] != '-' || argv[i][1] != '\0') {
+                    fnin = argv[i];
+                    fin = fopen(fnin, "rb");
+                    if (!fin) {
+                        fprintf(stderr, "Can't open input file '%s", fnin);
+                        perror("'");
+                        exit(1);
+                    }
+                }
+                break;
+            case 1:
+                fnout = argv[i];
+                fout = fopen(fnout, "wb");
+                if (!fout) {
+                    fprintf(stderr, "Can't open input file '%s", fnout);
+                    perror("'");
+                    exit(1);
+                }
+                break;
+            default:
+                pm_error("too many non-option arguments");
+            }
+        }
+    }
+
+    pnm_readpnminit(fin, &cols, &rows, &maxval, &format);
+
+    if (PNM_FORMAT_TYPE(format) != PGM_TYPE &&
+        PNM_FORMAT_TYPE(format) != PBM_TYPE)
+        pm_error("This program accepts PBM and PGM input only.  "
+                 "Try Ppmtopgm.");
+
+    planes = pm_maxvaltobits(maxval);
+
+    /* In a JBIG file, maxvals are determined only by the number of planes,
+       so must be a power of 2 minus 1
+    */
+  
+    if ((1UL << planes)-1 != maxval) 
+        pm_error("Input image has unacceptable maxval: %d.  JBIG files must "
+                 "have a maxval which is a power of 2 minus 1.  Use "
+                 "Ppmdepth to adjust the image's maxval", maxval);
+
+    bpp = (planes + 7) / 8;
+
+    if (encode_planes < 0 || encode_planes > planes)
+        encode_planes = planes;
+
+    if (bpp == 1 && PNM_FORMAT_TYPE(format) == PBM_TYPE)
+        readPbm(fin, cols, rows, &bitmap);
+    else
+        readPnm(fin, cols, rows, maxval, format, bpp, 
+                planes, encode_planes, use_graycode, 
+                &bitmap);
+
+    /* Apply JBIG algorithm and write BIE to output file */
+
+  /* initialize parameter struct for JBIG encoder*/
+    jbg_enc_init(&s, cols, rows, encode_planes, bitmap, data_out, fout);
+
+    /* Select number of resolution layers either directly or based
+   * on a given maximum size for the lowest resolution layer */
+    if (d >= 0)
+        jbg_enc_layers(&s, d);
+    else
+        jbg_enc_lrlmax(&s, mwidth, mheight);
+
+  /* Specify a few other options (each is ignored if negative) */
+    if (delay_at)
+        options |= JBG_DELAY_AT;
+    jbg_enc_lrange(&s, dl, dh);
+    jbg_enc_options(&s, order, options, l0, mx, -1);
+
+  /* now encode everything and send it to data_out() */
+    jbg_enc_out(&s);
+
+    /* give encoder a chance to free its temporary data structures */
+    jbg_enc_free(&s);
+
+    /* check for file errors and close fout */
+    if (ferror(fout) || fclose(fout)) {
+        fprintf(stderr, "Problem while writing output file '%s", fnout);
+        perror("'");
+        exit(1);
+    }
+
+    /* In case the user wants to know all the gory details ... */
+    if (verbose) {
+        fprintf(stderr, "Information about the created JBIG bi-level image entity "
+                "(BIE):\n\n");
+        fprintf(stderr, "              input image size: %ld x %ld pixel\n",
+                s.xd, s.yd);
+        fprintf(stderr, "                    bit planes: %d\n", s.planes);
+        if (s.planes > 1)
+            fprintf(stderr, "                      encoding: %s code, MSB first\n",
+                    use_graycode ? "Gray" : "binary");
+        fprintf(stderr, "                       stripes: %ld\n", s.stripes);
+        fprintf(stderr, "   lines per stripe in layer 0: %ld\n", s.l0);
+        fprintf(stderr, "  total number of diff. layers: %d\n", s.d);
+        fprintf(stderr, "           lowest layer in BIE: %d\n", s.dl);
+        fprintf(stderr, "          highest layer in BIE: %d\n", s.dh);
+        fprintf(stderr, "             lowest layer size: %lu x %lu pixel\n",
+                jbg_ceil_half(s.xd, s.d - s.dl), jbg_ceil_half(s.yd, s.d - s.dl));
+        fprintf(stderr, "            highest layer size: %lu x %lu pixel\n",
+                jbg_ceil_half(s.xd, s.d - s.dh), jbg_ceil_half(s.yd, s.d - s.dh));
+        fprintf(stderr, "                   option bits:%s%s%s%s%s%s%s\n",
+                s.options & JBG_LRLTWO  ? " LRLTWO" : "",
+                s.options & JBG_VLENGTH ? " VLENGTH" : "",
+                s.options & JBG_TPDON   ? " TPDON" : "",
+                s.options & JBG_TPBON   ? " TPBON" : "",
+                s.options & JBG_DPON    ? " DPON" : "",
+                s.options & JBG_DPPRIV  ? " DPPRIV" : "",
+                s.options & JBG_DPLAST  ? " DPLAST" : "");
+        fprintf(stderr, "                    order bits:%s%s%s%s\n",
+                s.order & JBG_HITOLO ? " HITOLO" : "",
+                s.order & JBG_SEQ    ? " SEQ" : "",
+                s.order & JBG_ILEAVE ? " ILEAVE" : "",
+                s.order & JBG_SMID   ? " SMID" : "");
+        fprintf(stderr, "           AT maximum x-offset: %d\n"
+                "           AT maximum y-offset: %d\n", s.mx, s.my);
+        fprintf(stderr, "         length of output file: %lu byte\n\n",
+                total_length);
+    }
+
+    return 0;
+}
diff --git a/converter/other/jpeg2000/Makefile b/converter/other/jpeg2000/Makefile
new file mode 100644
index 00000000..70cfafb7
--- /dev/null
+++ b/converter/other/jpeg2000/Makefile
@@ -0,0 +1,77 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/jpeg2000
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+SUBDIRS = libjasper
+
+include $(BUILDDIR)/Makefile.config
+
+INCLUDES =
+ifneq ($(JASPERHDR_DIR),NONE)
+  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 = libjasper/include
+
+ifeq ($(JASPERLIB),$(INTERNAL_JASPERLIB))
+  ifeq ($(HAVE_INT64),Y)
+    JASPERLIB_DEP = $(JASPERLIB)
+    JASPERLIB_USE = $(JASPERLIB)
+  else
+    # He wants the internal library, but doesn't have a 64 bit compiler,
+    # so we have no way to build it.  Ergo, he doesn't have a Jasper
+    # library.
+    JASPERLIB_USE = NONE
+  endif
+else
+  # It's not our internal version; user's on his own to make sure it's built
+  JASPERLIB_USE = $(JASPERLIB)
+endif
+
+
+ifneq ($(JASPERHDR_DIR),NONE)
+  ifneq ($(JASPERLIB_USE),NONE)
+    BINARIES = pamtojpeg2k jpeg2ktopam
+  endif
+endif
+
+
+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.
+  MERGE_OBJECTS += $(JASPERLIB)
+endif
+MERGEBINARIES = $(BINARIES)
+
+.PHONY: all
+all: $(BINARIES)
+
+include $(SRCDIR)/Makefile.common
+
+LIBOPTS = $(shell $(LIBOPT) $(NETPBMLIB) $(JASPERLIB_USE))
+
+$(BINARIES): %: %.o $(JASPERLIB_DEP) $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) $(MATHLIB) $(LDLIBS) -o $@ $< \
+	  $(LIBOPTS) $(JASPERDEPLIBS) -lm $(RPATH) $(LADD)
+
+$(INTERNAL_JASPERLIB): FORCE
+	$(MAKE) -f $(SRCDIR)/$(SUBDIR)/libjasper/Makefile \
+	   -C $(dir $@) $(notdir $@)
+
+clean: localclean
+
+.PHONY: localclean
+localclean:
+	$(MAKE) -f $(SRCDIR)/$(SUBDIR)/libjasper/Makefile -C libjasper clean
+
+.PHONY: FORCE
+FORCE:
diff --git a/converter/other/jpeg2000/jpeg2ktopam.c b/converter/other/jpeg2000/jpeg2ktopam.c
new file mode 100644
index 00000000..d6ea580c
--- /dev/null
+++ b/converter/other/jpeg2000/jpeg2ktopam.c
@@ -0,0 +1,498 @@
+/*****************************************************************************
+                              jpeg2kopam
+******************************************************************************
+
+  Convert a JPEG-2000 code stream image to a PNM or PAM
+
+  By Bryan Henderson, San Jose CA  2002.10.26
+
+*****************************************************************************/
+
+#define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+#include <string.h>
+
+#include "pam.h"
+#include "shhopt.h"
+#include "nstring.h"
+#include "mallocvar.h"
+
+#include <jasper/jasper.h>
+#include "libjasper_compat.h"
+
+enum compmode {COMPMODE_INTEGER, COMPMODE_REAL};
+
+enum progression {PROG_LRCP, PROG_RLCP, PROG_RPCL, PROG_PCRL, PROG_CPRL};
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    char * inputFilename;
+    unsigned int debuglevel;  /* Jasper library debug level */
+    unsigned int verbose;
+};
+
+
+static void
+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
+   sometimes, one of these strings is actually just a suffix of an entry
+   in argv!
+-----------------------------------------------------------------------------*/
+    optEntry *option_def;
+    optStruct3 opt;
+
+    unsigned int debuglevelSpec;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "verbose",      OPT_FLAG,   NULL, 
+            &cmdlineP->verbose,   0);
+    OPTENT3(0, "debuglevel",   OPT_UINT,   &cmdlineP->debuglevel,
+            &debuglevelSpec,      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);
+
+    if (!debuglevelSpec)
+        cmdlineP->debuglevel = 0;
+
+    if (argc - 1 == 0)
+        cmdlineP->inputFilename = strdup("-");  /* he wants stdin */
+    else if (argc - 1 == 1)
+        cmdlineP->inputFilename = strdup(argv[1]);
+    else 
+        pm_error("Too many arguments.  The only argument accepted\n"
+                 "is the input file specification");
+
+}
+
+
+
+static void
+readJpc(const char *   const inputFilename, 
+        jas_image_t ** const jasperPP) {
+
+    jas_image_t * jasperP;
+    jas_stream_t *instream;
+    const char * options;
+
+    if ( strcmp(inputFilename, "-") == 0) {
+        /* The input image is to be read from standard input. */
+        instream = jas_stream_fdopen(fileno(stdin), "rb");
+        if (instream == NULL)
+            pm_error("error: cannot reopen standard input");
+    } else {
+        instream = jas_stream_fopen(inputFilename, "rb");
+        if (instream == 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");
+
+    options = "";
+
+    jasperP = jas_image_decode(instream, jas_image_strtofmt((char*)"jpc"), 
+                               (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);
+
+    *jasperPP = jasperP;
+}
+
+
+
+static void
+getRgbComponents(int jasperCmpnt[], jas_image_t * const jasperP) {
+
+    {
+        int const rc = 
+            jas_image_getcmptbytype(jasperP,
+                                    JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
+        if (rc < 0)
+            pm_error("Input says it has RGB color space, but contains "
+                     "no red component");
+        else
+            jasperCmpnt[PAM_RED_PLANE] = rc;
+
+        if (jas_image_cmptsgnd(jasperP, rc)) 
+            pm_error("Input image says it is RGB, but has signed values "
+                     "for what should be the red intensities.");
+    }
+    {
+        int const rc = 
+            jas_image_getcmptbytype(jasperP,
+                                    JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
+        if (rc < 0)
+            pm_error("Input says it has RGB color space, but contains "
+                     "no green component");
+        else
+            jasperCmpnt[PAM_GRN_PLANE] = rc;
+
+        if (jas_image_cmptsgnd(jasperP, rc)) 
+            pm_error("Input image says it is RGB, but has signed values "
+                     "for what should be the green intensities.");
+    }
+    {
+        int const rc = 
+            jas_image_getcmptbytype(jasperP,
+                                    JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
+        if (rc < 0)
+            pm_error("Input says it has RGB color space, but contains "
+                     "no blue component");
+        else
+            jasperCmpnt[PAM_BLU_PLANE] = rc;
+
+        if (jas_image_cmptsgnd(jasperP, rc)) 
+            pm_error("Input image says it is RGB, but has signed values "
+                     "for what should be the blue intensities.");
+    }
+}            
+
+
+
+static void
+getGrayComponent(int * jasperCmptP, jas_image_t * const jasperP) {
+
+    int const rc = 
+        jas_image_getcmptbytype(jasperP,
+                                JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y));
+    if (rc < 0)
+        pm_error("Input says it has Grayscale color space, but contains "
+                 "no gray intensity component");
+    else
+        *jasperCmptP = rc;
+    if (jas_image_cmptsgnd(jasperP, 0)) 
+        pm_error("Input image says it is grayscale, but has signed values "
+                 "for what should be the gray levels.");
+}
+
+
+
+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
+   all the channels are the same, and abort the program if not.
+-----------------------------------------------------------------------------*/
+    int cmptNo;
+    
+    for (cmptNo = 0; cmptNo < jas_image_numcmpts(jasperP); ++cmptNo) {
+        if (jas_image_cmptwidth(jasperP, cmptNo) != 
+            jas_image_cmptwidth(jasperP, 0))
+            pm_message("Input image does not have components all the same "
+                       "width.");
+        if (jas_image_cmptheight(jasperP, cmptNo) != 
+            jas_image_cmptheight(jasperP, 0))
+            pm_message("Input image does not have components all the same "
+                       "height.");
+    }
+}
+
+
+
+static unsigned int
+maxJasperComponentPrecision(jas_image_t * const jasperP) {
+
+    int cmptNo;
+    unsigned int max;
+    
+    max = 1;
+
+    for (cmptNo = 0; cmptNo < jas_image_numcmpts(jasperP); ++cmptNo)
+        max = MAX(max, jas_image_cmptprec(jasperP, cmptNo));
+
+    return max;
+}
+
+
+
+static void
+computeOutputParm(jas_image_t * const jasperP,
+                  struct pam *  const outpamP,
+                  int **        const jasperCmptNoP) {
+
+    int * jasperCmptNo;
+       /* Malloc'ed array.  jaspercmptNo[P] is the component number for use
+          with the Jasper library that corresponds to Plane P of the PAM.
+       */
+
+	switch (jas_clrspc_fam(jas_image_clrspc(jasperP))) {
+	case JAS_CLRSPC_FAM_GRAY:
+        outpamP->depth = 1;
+        MALLOCARRAY_NOFAIL(jasperCmptNo, 1);
+        getGrayComponent(&jasperCmptNo[0], jasperP);
+        if (jas_image_cmptprec(jasperP, jasperCmptNo[0]) == 1) {
+            outpamP->format = RPBM_FORMAT;
+            strcpy(outpamP->tuple_type, PAM_PBM_TUPLETYPE);
+        } else {
+            outpamP->format = RPGM_FORMAT;
+            strcpy(outpamP->tuple_type, PAM_PGM_TUPLETYPE);
+        }
+        break;
+	case JAS_CLRSPC_FAM_RGB:
+        outpamP->depth = 3;
+        MALLOCARRAY_NOFAIL(jasperCmptNo, 3);
+        getRgbComponents(jasperCmptNo, jasperP);
+        outpamP->format = RPPM_FORMAT;
+        strcpy(outpamP->tuple_type, PAM_PPM_TUPLETYPE);
+        break;
+    default:
+        outpamP->format = PAM_FORMAT;
+        outpamP->depth = jas_image_numcmpts(jasperP);
+        {
+            unsigned int plane;
+
+            MALLOCARRAY_NOFAIL(jasperCmptNo, outpamP->depth);
+            for (plane = 0; plane < outpamP->depth; ++plane)
+                jasperCmptNo[plane] = plane;
+        }
+        strcpy(outpamP->tuple_type, "");
+        if (jas_image_cmptsgnd(jasperP, 0)) 
+            pm_message("Warning: Input image has signed sample values.  "
+                       "They will be represented in the PAM output in "
+                       "two's complement.");
+    }
+    outpamP->plainformat = FALSE;
+
+	outpamP->width = jas_image_cmptwidth(jasperP, 0);
+	outpamP->height = jas_image_cmptheight(jasperP, 0);
+
+    validateComponentsAlike(jasperP);
+
+    {
+        unsigned int const maxPrecision = maxJasperComponentPrecision(jasperP);
+
+        outpamP->maxval = pm_bitstomaxval(maxPrecision);
+        
+        outpamP->bytes_per_sample = (maxPrecision + 7)/8;
+    }
+    *jasperCmptNoP = jasperCmptNo;
+}
+
+
+
+static void
+createMatrices(struct pam * const outpamP, jas_matrix_t *** matrixP) {
+
+    jas_matrix_t ** matrix; 
+    unsigned int plane;
+
+    MALLOCARRAY_NOFAIL(matrix, outpamP->depth);
+
+    for (plane = 0; plane < outpamP->depth; ++plane) {
+        matrix[plane] = jas_matrix_create(1, outpamP->width);
+
+        if (matrix[plane] == NULL)
+            pm_error("Unable to create matrix for plane %u.  "
+                     "jas_matrix_create() failed.", plane);
+    }   
+    *matrixP = matrix;
+}
+
+
+
+static void
+destroyMatrices(struct pam *    const outpamP, 
+                jas_matrix_t ** const matrix ) {
+
+    unsigned int plane;
+
+    for (plane = 0; plane < outpamP->depth; ++plane)
+        jas_matrix_destroy(matrix[plane]);
+    free(matrix);
+}    
+
+
+
+static void
+computeComponentMaxval(struct pam *  const outpamP,
+                       jas_image_t * const jasperP,
+                       int           const jasperCmpt[],
+                       sample **     const jasperMaxvalP,
+                       bool *        const singleMaxvalP) {
+    
+    sample * jasperMaxval;
+    unsigned int plane;
+
+    MALLOCARRAY(jasperMaxval, outpamP->depth);
+
+    *singleMaxvalP = TRUE;  /* initial assumption */
+    for (plane = 0; plane < outpamP->depth; ++plane) {
+        jasperMaxval[plane] = 
+            pm_bitstomaxval(jas_image_cmptprec(jasperP, jasperCmpt[plane]));
+        if (jasperMaxval[plane] != jasperMaxval[0])
+            *singleMaxvalP = FALSE;
+    }
+    *jasperMaxvalP = jasperMaxval;
+}
+
+                       
+
+static void
+copyRowSingleMaxval(jas_seqent_t ** const jasperRow,
+                    tuple *         const tuplerow,
+                    struct pam *    const outpamP) {
+/*----------------------------------------------------------------------------
+   Copy row from Jasper library representation to Netpbm library
+   representation, assuming all Jasper components have the same precision,
+   which corresponds to the maxval of the output PAM, which means we don't
+   have to do any maxval scaling.
+
+   This is significantly faster than copyRowAnyMaxval().
+-----------------------------------------------------------------------------*/
+    unsigned int col;
+    
+    for (col = 0; col < outpamP->width; ++col) {
+        unsigned int plane;
+        for (plane = 0; plane < outpamP->depth; ++plane) 
+            tuplerow[col][plane] = jasperRow[plane][col];
+    }
+}
+
+
+
+static void
+copyRowAnyMaxval(jas_seqent_t ** const jasperRow,
+                 tuple *         const tuplerow,
+                 struct pam *    const outpamP,
+                 sample          const jasperMaxval[]) {
+/*----------------------------------------------------------------------------
+   Copy row from Jasper library representation to Netpbm library
+   representation, allowing for each Jasper library component to have a
+   different precision (number of bits) and for those precisions to be
+   unrelated to the PAM maxval.
+
+   This is significantly slower than copyRowSingleMaxval().
+-----------------------------------------------------------------------------*/
+    unsigned int col;
+            
+    for (col = 0; col < outpamP->width; ++col) {
+        unsigned int plane;
+        for (plane = 0; plane < outpamP->depth; ++plane) 
+            tuplerow[col][plane] = 
+                jasperRow[plane][col] * 
+                outpamP->maxval / jasperMaxval[plane];
+    }
+}
+
+
+
+static void
+convertToPamPnm(struct pam *  const outpamP,
+                jas_image_t * const jasperP,
+                int           const jasperCmptNo[]) {
+
+    jas_matrix_t ** matrix;  /* malloc'ed */
+        /* matrix[X] is the data for Plane X of the current row */
+    sample * jasperMaxval;
+    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.
+       */
+    bool singleMaxval;
+
+    createMatrices(outpamP, &matrix);
+
+    computeComponentMaxval(outpamP, jasperP, jasperCmptNo,
+                           &jasperMaxval, &singleMaxval);
+
+    MALLOCARRAY(jasperRow, outpamP->depth);
+    if (jasperRow == NULL)
+        pm_error("Out of memory");
+
+    tuplerow = pnm_allocpamrow(outpamP);
+
+    for (row = 0; row < outpamP->height; ++row) {
+        unsigned int plane;
+
+        for (plane = 0; plane < outpamP->depth; ++plane) {
+            int rc;
+            rc = jas_image_readcmpt(jasperP, jasperCmptNo[plane], 0, row,
+                                    outpamP->width, 1,
+                                    matrix[plane]);
+            if (rc != 0)
+                pm_error("jas_image_readcmpt() of row %u plane %u "
+                         "failed.", 
+                         row, plane);
+            jasperRow[plane] = jas_matrix_getref(matrix[plane], 0, 0);
+        }
+        if (singleMaxval) 
+            copyRowSingleMaxval(jasperRow, tuplerow, outpamP);
+        else
+            copyRowAnyMaxval(jasperRow, tuplerow, outpamP, jasperMaxval);
+
+        pnm_writepamrow(outpamP, tuplerow);
+    }
+    pnm_freepamrow(tuplerow);
+
+    destroyMatrices(outpamP, matrix);
+
+    free(jasperRow);
+    free(jasperMaxval);
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+    struct cmdlineInfo cmdline;
+    struct pam outpam;
+    int * jasperCmpt;  /* malloc'ed */
+       /* jaspercmpt[P] is the component number for use with the
+          Jasper library that corresponds to Plane P of the PAM.  
+       */
+    jas_image_t * jasperP;
+
+    pnm_init(&argc, argv);
+    
+    parseCommandLine(argc, argv, &cmdline);
+    
+    { 
+        int rc;
+        
+        rc = jas_init();
+        if ( rc != 0 )
+            pm_error("Failed to initialize Jasper library.  "
+                     "jas_init() returns rc %d", rc );
+    }
+    
+    jas_setdbglevel(cmdline.debuglevel);
+    
+    readJpc(cmdline.inputFilename, &jasperP);
+
+    outpam.file = stdout;
+    outpam.size = sizeof(outpam);
+    outpam.len  = PAM_STRUCT_SIZE(tuple_type);
+
+    computeOutputParm(jasperP, &outpam, &jasperCmpt);
+
+    pnm_writepaminit(&outpam);
+    
+    convertToPamPnm(&outpam, jasperP, jasperCmpt);
+    
+    free(jasperCmpt);
+	jas_image_destroy(jasperP);
+
+    pm_close(stdout);
+    
+    return 0;
+}
diff --git a/converter/other/jpeg2000/libjasper/Makefile b/converter/other/jpeg2000/libjasper/Makefile
new file mode 100644
index 00000000..73d263ec
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/Makefile
@@ -0,0 +1,28 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/jpeg2000/libjasper
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+SUBDIRS = base jp2 jpc
+
+# NOTE: The library source code uses 64 bit types, so you cannot
+# build it (compile will fail) if you don't have 64 bit types defined
+# by pm_config.h (normally by including <inttypes.h>)
+
+all: libjasper.a
+
+include $(SRCDIR)/$(SUBDIR)/Makefile.common
+
+# We cheat a bit here -- the real dependencies are all the .o files listed
+# in the part list, but since we don't know what those are, we just do a
+# 'make all' in each subdirectory to get them built.  That means it always
+# looks like dependencies were rebuilt and libjasper.a gets rebuilt every
+# time.
+libjasper.a: $(SUBDIRS:%=%/all) partlist 
+	ar rc $@ $(shell cat partlist)
+	$(RANLIB) $@
+
diff --git a/converter/other/jpeg2000/libjasper/Makefile.common b/converter/other/jpeg2000/libjasper/Makefile.common
new file mode 100644
index 00000000..71a11832
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/Makefile.common
@@ -0,0 +1,41 @@
+# -*-makefile-*-    <-- an Emacs control
+# This is common rules for the pnmtojpc subdirectories.
+#
+# Set the following variables before including this:
+#
+#  LIB_OBJECTS: List of object files from this directory that go into 
+#               libjasper.
+
+all: $(LIB_OBJECTS) partlist
+
+partlist: $(SUBDIRS:%=%/partlist)
+	cat /dev/null $(SUBDIRS:%=%/partlist) >$@
+	echo $(LIB_OBJECTS:%=$(CURDIR)/%) >>$@
+
+.PHONY: $(SUBDIRS:%=%/partlist)
+$(SUBDIRS:%=%/partlist): %/partlist: $(CURDIR)/%
+	$(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \
+	    SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) $(notdir $@) 
+
+INCLUDES = -I$(JASPERSRCDIR)/include -I$(JASPERSRCDIR)/importinc
+
+include $(SRCDIR)/Makefile.common
+
+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 $(CFLAGS) $(INCLUDES) $(DEFS) $(CADD) $<
+
+$(LIB_OBJECTS): $(JASPERSRCDIR)/importinc
+
+$(JASPERSRCDIR)/importinc:
+	$(MAKE) -C $(dir $@) $(notdir $@)
+
+clean: localclean
+
+.PHONY: localclean
+localclean:
+	rm -f partlist
+
+.PHONY: FORCE
+FORCE:
diff --git a/converter/other/jpeg2000/libjasper/README b/converter/other/jpeg2000/libjasper/README
new file mode 100644
index 00000000..ad3e019b
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/README
@@ -0,0 +1,17 @@
+The code in the directory 'libjasper' is taken from the Jasper package.
+In particular, from the 'src/libjasper' directory of Jasper Version
+1.600.0.
+
+The adaptation was done by Bryan Henderson on 2002.10.26.
+
+The adaptation involved:
+
+  - remove stuff for formats other than PNM.
+
+  - Replace build stuff (Jasper uses GNU Autoconf/Automake/Libtool).
+
+See <http://www.ece.uvic.ca/~mdadams/jasper/>.
+
+
+You cannot build this library without a 64 bit compiler (and 64 bit
+types such as int64_t defined).  It does a lot of 64 bit arithmetic.
diff --git a/converter/other/jpeg2000/libjasper/base/Makefile b/converter/other/jpeg2000/libjasper/base/Makefile
new file mode 100644
index 00000000..0ee65b5e
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/Makefile
@@ -0,0 +1,21 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/jpeg2000/libjasper/base
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+JASPERSRCDIR=$(SRCDIR)/$(SUBDIR)/..
+
+include $(BUILDDIR)/Makefile.config
+
+LIB_OBJECTS = jas_debug.o jas_getopt.o jas_image.o jas_init.o \
+	      jas_malloc.o jas_seq.o jas_stream.o jas_string.o \
+	      jas_tvp.o jas_version.o
+
+MERGE_OBJECTS =
+
+all: partlist $(LIB_OBJECTS)
+
+include $(JASPERSRCDIR)/Makefile.common
+
diff --git a/converter/other/jpeg2000/libjasper/base/jas_debug.c b/converter/other/jpeg2000/libjasper/base/jas_debug.c
new file mode 100644
index 00000000..4248178f
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/jas_debug.c
@@ -0,0 +1,186 @@
+/*
+ * 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__
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_debug.h"
+
+/******************************************************************************\
+* Local data.
+\******************************************************************************/
+
+static int jas_dbglevel = 0;
+/* The debug level. */
+
+/******************************************************************************\
+* Code for getting/setting the debug level.
+\******************************************************************************/
+
+/* Set the library debug level. */
+int jas_setdbglevel(int dbglevel)
+{
+	int olddbglevel;
+
+	/* Save the old debug level. */
+	olddbglevel = jas_dbglevel;
+
+	/* Change the debug level. */
+	jas_dbglevel = dbglevel;
+
+	/* Return the old debug level. */
+	return olddbglevel;
+}
+
+/* Get the library debug level. */
+int jas_getdbglevel()
+{
+	return jas_dbglevel;
+}
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+/* Perform formatted output to standard error. */
+int jas_eprintf(const char *fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	return ret;
+}
+
+/* Dump memory to a stream. */
+int jas_memdump(FILE *out, void *data, size_t len)
+{
+	int i;
+	int j;
+	unsigned char *dp;
+	dp = data;
+	for (i = 0; i < len; i += 16) {
+		fprintf(out, "%04x:", i);
+		for (j = 0; j < 16; ++j) {
+			if (i + j < len) {
+				fprintf(out, " %02x", dp[i + j]);
+			}
+		}
+		fprintf(out, "\n");
+	}
+	return 0;
+}
diff --git a/converter/other/jpeg2000/libjasper/base/jas_getopt.c b/converter/other/jpeg2000/libjasper/base/jas_getopt.c
new file mode 100644
index 00000000..7f579b3e
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/jas_getopt.c
@@ -0,0 +1,217 @@
+/*
+ * 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__
+ */
+
+/*
+ * Command Line Option Parsing Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "jasper/jas_getopt.h"
+#include "jasper/jas_math.h"
+
+/******************************************************************************\
+* Global data.
+\******************************************************************************/
+
+int jas_optind = 0;
+int jas_opterr = 1;
+char *jas_optarg = 0;
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+static jas_opt_t *jas_optlookup(jas_opt_t *opts, char *name)
+{
+	jas_opt_t *opt;
+
+	for (opt = opts; opt->id >= 0 && opt->name; ++opt) {
+		if (!strcmp(opt->name, name)) {
+			return opt;
+		}
+	}
+	return 0;
+}
+
+int jas_getopt(int argc, char **argv, jas_opt_t *opts)
+{
+	char *cp;
+	int id;
+	int hasarg;
+	jas_opt_t *opt;
+	char *s;
+
+	if (!jas_optind) {
+		jas_optind = JAS_MIN(1, argc);
+	}
+	while (jas_optind < argc) {
+		s = cp = argv[jas_optind];
+		if (*cp == '-') {
+			/* We are processing an option. */
+			++jas_optind;
+			if (*++cp == '-') {
+				/* We are processing a long option. */
+				++cp;
+				if (*cp == '\0') {
+					/* This is the end of the options. */
+					return JAS_GETOPT_EOF;
+				}
+				if (!(opt = jas_optlookup(opts, cp))) {
+					if (jas_opterr) {
+						fprintf(stderr, "unknown long option %s\n", s);
+					}
+					return JAS_GETOPT_ERR;
+				}
+				hasarg = (opt->flags & JAS_OPT_HASARG) != 0;
+				id = opt->id;
+			} else {
+				/* We are processing a short option. */
+				if (strlen(cp) != 1 ||
+				  !(opt = jas_optlookup(opts, cp))) {
+					if (jas_opterr) {
+						fprintf(stderr, "unknown short option %s\n", s);
+					}
+					return JAS_GETOPT_ERR;
+				}
+				hasarg = (opt->flags & JAS_OPT_HASARG) != 0;
+				id = opt->id;
+			}
+			if (hasarg) {
+				/* The option has an argument. */
+				if (jas_optind >= argc) {
+					if (jas_opterr) {
+						fprintf(stderr, "missing argument for option %s\n", s);
+					}
+					return JAS_GETOPT_ERR;
+				}
+				jas_optarg = argv[jas_optind];
+				++jas_optind;
+			} else {
+				/* The option does not have an argument. */
+				jas_optarg = 0;
+			}
+			return id;
+		} else {
+			/* We are not processing an option. */
+			return JAS_GETOPT_EOF;
+		}
+	}
+	return JAS_GETOPT_EOF;
+}
diff --git a/converter/other/jpeg2000/libjasper/base/jas_image.c b/converter/other/jpeg2000/libjasper/base/jas_image.c
new file mode 100644
index 00000000..e6439fcd
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/jas_image.c
@@ -0,0 +1,968 @@
+/*
+ * 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__
+ */
+
+/*
+ * Image Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "jasper/jas_math.h"
+#include "jasper/jas_image.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_string.h"
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/******************************************************************************\
+* Local prototypes.
+\******************************************************************************/
+
+static void jas_image_cmpt_destroy(jas_image_cmpt_t *cmpt);
+static jas_image_cmpt_t *jas_image_cmpt_create(uint_fast32_t tlx, uint_fast32_t tly,
+  uint_fast32_t hstep, uint_fast32_t vstep, uint_fast32_t width, uint_fast32_t
+  height, uint_fast16_t depth, bool sgnd, uint_fast32_t inmem);
+static void jas_image_setbbox(jas_image_t *image);
+static jas_image_cmpt_t *jas_image_cmpt_copy(jas_image_cmpt_t *cmpt);
+static jas_image_cmpt_t *jas_image_cmpt_create0();
+static int jas_image_growcmpts(jas_image_t *image, int maxcmpts);
+static uint_fast32_t inttobits(jas_seqent_t v, int prec, bool sgnd);
+static jas_seqent_t bitstoint(uint_fast32_t v, int prec, bool sgnd);
+
+/******************************************************************************\
+* Global data.
+\******************************************************************************/
+
+static int jas_image_numfmts = 0;
+static jas_image_fmtinfo_t jas_image_fmtinfos[JAS_IMAGE_MAXFMTS];
+
+/******************************************************************************\
+* Create and destroy operations.
+\******************************************************************************/
+
+jas_image_t *jas_image_create(uint_fast16_t numcmpts, jas_image_cmptparm_t *cmptparms,
+  int colorspace)
+{
+	jas_image_t *image;
+	uint_fast32_t rawsize;
+	uint_fast32_t inmem;
+	uint_fast16_t cmptno;
+	jas_image_cmptparm_t *cmptparm;
+
+	if (!(image = jas_image_create0())) {
+		return 0;
+	}
+
+	image->colorspace_ = colorspace;
+	image->maxcmpts_ = numcmpts;
+	image->inmem_ = true;
+
+	/* Allocate memory for the per-component information. */
+	if (!(image->cmpts_ = jas_malloc(image->maxcmpts_ *
+	  sizeof(jas_image_cmpt_t *)))) {
+		jas_image_destroy(image);
+		return 0;
+	}
+	/* Initialize in case of failure. */
+	for (cmptno = 0; cmptno < image->maxcmpts_; ++cmptno) {
+		image->cmpts_[cmptno] = 0;
+	}
+
+	/* Compute the approximate raw size of the image. */
+	rawsize = 0;
+	for (cmptno = 0, cmptparm = cmptparms; cmptno < numcmpts; ++cmptno,
+	  ++cmptparm) {
+		rawsize += cmptparm->width * cmptparm->height *
+		  (cmptparm->prec + 7) / 8;
+	}
+	/* Decide whether to buffer the image data in memory, based on the
+	  raw size of the image. */
+	inmem = (rawsize < JAS_IMAGE_INMEMTHRESH);
+
+	/* Create the individual image components. */
+	for (cmptno = 0, cmptparm = cmptparms; cmptno < numcmpts; ++cmptno,
+	  ++cmptparm) {
+		if (!(image->cmpts_[cmptno] = jas_image_cmpt_create(cmptparm->tlx,
+		  cmptparm->tly, cmptparm->hstep, cmptparm->vstep,
+		  cmptparm->width, cmptparm->height, cmptparm->prec,
+		  cmptparm->sgnd, inmem))) {
+			jas_image_destroy(image);
+			return 0;
+		}
+		++image->numcmpts_;
+	}
+
+	/* Determine the bounding box for all of the components on the
+	  reference grid (i.e., the image area) */
+	jas_image_setbbox(image);
+
+	return image;
+}
+
+jas_image_t *jas_image_create0()
+{
+	jas_image_t *image;
+
+	if (!(image = jas_malloc(sizeof(jas_image_t)))) {
+		return 0;
+	}
+
+	image->tlx_ = 0;
+	image->tly_ = 0;
+	image->brx_ = 0;
+	image->bry_ = 0;
+	image->colorspace_ = JAS_IMAGE_CS_UNKNOWN;
+	image->numcmpts_ = 0;
+	image->maxcmpts_ = 0;
+	image->cmpts_ = 0;
+	image->inmem_ = true;
+	image->iccp_ = 0;
+	image->iccplen_ = 0;
+
+	return image;
+}
+
+jas_image_t *jas_image_copy(jas_image_t *image)
+{
+	jas_image_t *newimage;
+	int cmptno;
+
+	newimage = jas_image_create0();
+	if (jas_image_growcmpts(newimage, image->numcmpts_)) {
+		goto error;
+	}
+	for (cmptno = 0; cmptno < image->numcmpts_; ++cmptno) {
+		if (!(newimage->cmpts_[cmptno] = jas_image_cmpt_copy(image->cmpts_[cmptno]))) {
+			goto error;
+		}
+		++newimage->numcmpts_;
+	}
+
+	jas_image_setbbox(newimage);
+
+	return newimage;
+error:
+	if (newimage) {
+		jas_image_destroy(newimage);
+	}
+	return 0;
+}
+
+static jas_image_cmpt_t *jas_image_cmpt_create0()
+{
+	jas_image_cmpt_t *cmpt;
+	if (!(cmpt = jas_malloc(sizeof(jas_image_cmpt_t)))) {
+		return 0;
+	}
+	memset(cmpt, 0, sizeof(jas_image_cmpt_t));
+	cmpt->type_ = JAS_IMAGE_CT_UNKNOWN;
+	return cmpt;
+}
+
+static jas_image_cmpt_t *jas_image_cmpt_copy(jas_image_cmpt_t *cmpt)
+{
+	jas_image_cmpt_t *newcmpt;
+
+	if (!(newcmpt = jas_image_cmpt_create0())) {
+		return 0;
+	}
+	newcmpt->tlx_ = cmpt->tlx_;
+	newcmpt->tly_ = cmpt->tly_;
+	newcmpt->hstep_ = cmpt->hstep_;
+	newcmpt->vstep_ = cmpt->vstep_;
+	newcmpt->width_ = cmpt->width_;
+	newcmpt->height_ = cmpt->height_;
+	newcmpt->prec_ = cmpt->prec_;
+	newcmpt->sgnd_ = cmpt->sgnd_;
+	newcmpt->cps_ = cmpt->cps_;
+	newcmpt->type_ = cmpt->type_;
+	if (!(newcmpt->stream_ = jas_stream_memopen(0, 0))) {
+		return 0;
+	}
+	if (jas_stream_seek(cmpt->stream_, 0, SEEK_SET)) {
+		return 0;
+	}
+	if (jas_stream_copy(newcmpt->stream_, cmpt->stream_, -1)) {
+		return 0;
+	}
+	if (jas_stream_seek(newcmpt->stream_, 0, SEEK_SET)) {
+		return 0;
+	}
+	return newcmpt;
+}
+
+void jas_image_destroy(jas_image_t *image)
+{
+	int i;
+
+	if (image->cmpts_) {
+		for (i = 0; i < image->numcmpts_; ++i) {
+			jas_image_cmpt_destroy(image->cmpts_[i]);
+			image->cmpts_[i] = 0;
+		}
+		jas_free(image->cmpts_);
+	}
+	jas_free(image);
+}
+
+static jas_image_cmpt_t *jas_image_cmpt_create(uint_fast32_t tlx, uint_fast32_t tly,
+  uint_fast32_t hstep, uint_fast32_t vstep, uint_fast32_t width, uint_fast32_t
+  height, uint_fast16_t depth, bool sgnd, uint_fast32_t inmem)
+{
+	jas_image_cmpt_t *cmpt;
+	long size;
+
+	if (!(cmpt = jas_malloc(sizeof(jas_image_cmpt_t)))) {
+		return 0;
+	}
+
+	cmpt->tlx_ = tlx;
+	cmpt->tly_ = tly;
+	cmpt->hstep_ = hstep;
+	cmpt->vstep_ = vstep;
+	cmpt->width_ = width;
+	cmpt->height_ = height;
+	cmpt->prec_ = depth;
+	cmpt->sgnd_ = sgnd;
+	cmpt->stream_ = 0;
+	cmpt->cps_ = (depth + 7) / 8;
+
+	size = cmpt->width_ * cmpt->height_ * cmpt->cps_;
+	cmpt->stream_ = (inmem) ? jas_stream_memopen(0, size) : jas_stream_tmpfile();
+	if (!cmpt->stream_) {
+		jas_image_cmpt_destroy(cmpt);
+		return 0;
+	}
+
+	/* Zero the component data.  This isn't necessary, but it is
+	convenient for debugging purposes. */
+	if (jas_stream_seek(cmpt->stream_, size - 1, SEEK_SET) < 0 ||
+	  jas_stream_putc(cmpt->stream_, 0) == EOF ||
+	  jas_stream_seek(cmpt->stream_, 0, SEEK_SET) < 0) {
+		jas_image_cmpt_destroy(cmpt);
+		return 0;
+	}
+
+	return cmpt;
+}
+
+static void jas_image_cmpt_destroy(jas_image_cmpt_t *cmpt)
+{
+	if (cmpt->stream_) {
+		jas_stream_close(cmpt->stream_);
+	}
+	jas_free(cmpt);
+}
+
+/******************************************************************************\
+* Load and save operations.
+\******************************************************************************/
+
+jas_image_t *jas_image_decode(jas_stream_t *in, int fmt, char *optstr)
+{
+	jas_image_fmtinfo_t *fmtinfo;
+
+	/* If possible, try to determine the format of the input data. */
+	if (fmt < 0) {
+		if ((fmt = jas_image_getfmt(in)) < 0) {
+			return 0;
+		}
+	}
+	if (!(fmtinfo = jas_image_lookupfmtbyid(fmt))) {
+		return 0;
+	}
+	return (fmtinfo->ops.decode) ? (*fmtinfo->ops.decode)(in, optstr) : 0;
+}
+
+int jas_image_encode(jas_image_t *image, jas_stream_t *out, int fmt, char *optstr)
+{
+	jas_image_fmtinfo_t *fmtinfo;
+	if (!(fmtinfo = jas_image_lookupfmtbyid(fmt))) {
+		return -1;
+	}
+	return (fmtinfo->ops.encode) ? (*fmtinfo->ops.encode)(image, out,
+	  optstr) : (-1);
+}
+
+/******************************************************************************\
+* Component read and write operations.
+\******************************************************************************/
+
+int jas_image_readcmpt(jas_image_t *image, uint_fast16_t cmptno, uint_fast32_t x, uint_fast32_t y, uint_fast32_t width,
+  uint_fast32_t height, jas_matrix_t *data)
+{
+	jas_image_cmpt_t *cmpt;
+	uint_fast32_t i;
+	uint_fast32_t j;
+	int k;
+	jas_seqent_t v;
+	int c;
+	jas_seqent_t *dr;
+	jas_seqent_t *d;
+	int drs;
+
+	if (cmptno >= image->numcmpts_) {
+		return -1;
+	}
+
+	cmpt = image->cmpts_[cmptno];
+	if (x >= cmpt->width_ || y >= cmpt->height_ ||
+	  x + width > cmpt->width_ ||
+	  y + height > cmpt->height_) {
+		return -1;
+	}
+
+	if (jas_matrix_numrows(data) != height || jas_matrix_numcols(data) != width) {
+		if (jas_matrix_resize(data, height, width)) {
+			return -1;
+		}
+	}
+
+	dr = jas_matrix_getref(data, 0, 0);
+	drs = jas_matrix_rowstep(data);
+	for (i = 0; i < height; ++i, dr += drs) {
+		d = dr;
+		if (jas_stream_seek(cmpt->stream_, (cmpt->width_ * (y + i) + x)
+		  * cmpt->cps_, SEEK_SET) < 0) {
+			return -1;
+		}
+		for (j = width; j > 0; --j, ++d) {
+			v = 0;
+			for (k = cmpt->cps_; k > 0; --k) {
+				if ((c = jas_stream_getc(cmpt->stream_)) == EOF) {
+					return -1;
+				}
+				v = (v << 8) | (c & 0xff);
+			}
+			*d = bitstoint(v, cmpt->prec_, cmpt->sgnd_);
+		}
+	}
+
+	return 0;
+}
+
+#if 0
+int_fast64_t jas_image_readcmpt1(jas_image_t *image, uint_fast16_t cmptno,
+  uint_fast32_t x, uint_fast32_t y)
+{
+	jas_image_cmpt_t *cmpt;
+	int k;
+	int c;
+	int_fast64_t v;
+	cmpt = image->cmpts_[cmptno];
+	if (jas_stream_seek(cmpt->stream_, (cmpt->width_ * y + x) * cmpt->cps_,
+	  SEEK_SET) < 0) {
+		goto error;
+	}
+	v = 0;
+	for (k = cmpt->cps_; k > 0; --k) {
+		if ((c = jas_stream_getc(cmpt->stream_)) == EOF) {
+			goto error;
+		}
+		v = (v << 8) | (c & 0xff);
+	}
+if (cmpt->sgnd_) {
+	abort();
+}
+
+	return v;
+
+error:
+	return 0;
+}
+#endif
+
+int jas_image_writecmpt(jas_image_t *image, uint_fast16_t cmptno, uint_fast32_t x, uint_fast32_t y, uint_fast32_t width,
+  uint_fast32_t height, jas_matrix_t *data)
+{
+	jas_image_cmpt_t *cmpt;
+	uint_fast32_t i;
+	uint_fast32_t j;
+	jas_seqent_t *d;
+	jas_seqent_t *dr;
+	int drs;
+	jas_seqent_t v;
+	int k;
+	int c;
+
+	if (cmptno >= image->numcmpts_) {
+		return -1;
+	}
+
+	cmpt = image->cmpts_[cmptno];
+	if (x >= cmpt->width_ || y >= cmpt->height_ ||
+	  x + width > cmpt->width_ ||
+	  y + height > cmpt->height_) {
+		return -1;
+	}
+
+	if (jas_matrix_numrows(data) != height || jas_matrix_numcols(data) != width) {
+		return -1;
+	}
+
+	dr = jas_matrix_getref(data, 0, 0);
+	drs = jas_matrix_rowstep(data);
+	for (i = 0; i < height; ++i, dr += drs) {
+		d = dr;
+		if (jas_stream_seek(cmpt->stream_, (cmpt->width_ * (y + i) + x)
+		  * cmpt->cps_, SEEK_SET) < 0) {
+			return -1;
+		}
+		for (j = width; j > 0; --j, ++d) {
+			v = inttobits(*d, cmpt->prec_, cmpt->sgnd_);
+			for (k = cmpt->cps_; k > 0; --k) {
+				c = (v >> (8 * (cmpt->cps_ - 1))) & 0xff;
+				if (jas_stream_putc(cmpt->stream_,
+				  (unsigned char) c) == EOF) {
+					return -1;
+				}
+				v <<= 8;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/******************************************************************************\
+* File format operations.
+\******************************************************************************/
+
+void jas_image_clearfmts()
+{
+	int i;
+	jas_image_fmtinfo_t *fmtinfo;
+	for (i = 0; i < jas_image_numfmts; ++i) {
+		fmtinfo = &jas_image_fmtinfos[i];
+		if (fmtinfo->name) {
+			jas_free(fmtinfo->name);
+			fmtinfo->name = 0;
+		}
+		if (fmtinfo->ext) {
+			jas_free(fmtinfo->ext);
+			fmtinfo->ext = 0;
+		}
+		if (fmtinfo->desc) {
+			jas_free(fmtinfo->desc);
+			fmtinfo->desc = 0;
+		}
+	}
+	jas_image_numfmts = 0;
+}
+
+int jas_image_addfmt(int id, const char *name, const char *ext, 
+  const char *desc,
+  jas_image_fmtops_t *ops)
+{
+	jas_image_fmtinfo_t *fmtinfo;
+	assert(id >= 0 && name && ext && ops);
+	if (jas_image_numfmts >= JAS_IMAGE_MAXFMTS) {
+		return -1;
+	}
+	fmtinfo = &jas_image_fmtinfos[jas_image_numfmts];
+	fmtinfo->id = id;
+	if (!(fmtinfo->name = jas_strdup(name))) {
+		return -1;
+	}
+	if (!(fmtinfo->ext = jas_strdup(ext))) {
+		jas_free(fmtinfo->name);
+		return -1;
+	}
+	if (!(fmtinfo->desc = jas_strdup(desc))) {
+		jas_free(fmtinfo->name);
+		jas_free(fmtinfo->ext);
+		return -1;
+	}
+	fmtinfo->ops = *ops;
+	++jas_image_numfmts;
+	return 0;
+}
+
+int jas_image_strtofmt(char *name)
+{
+	jas_image_fmtinfo_t *fmtinfo;
+	if (!(fmtinfo = jas_image_lookupfmtbyname(name))) {
+		return -1;
+	}
+	return fmtinfo->id;
+}
+
+char *jas_image_fmttostr(int fmt)
+{
+	jas_image_fmtinfo_t *fmtinfo;
+	if (!(fmtinfo = jas_image_lookupfmtbyid(fmt))) {
+		return 0;
+	}
+	return fmtinfo->name;
+}
+
+int jas_image_getfmt(jas_stream_t *in)
+{
+	jas_image_fmtinfo_t *fmtinfo;
+	int found;
+	int i;
+
+	/* Check for data in each of the supported formats. */
+	found = 0;
+	for (i = 0, fmtinfo = jas_image_fmtinfos; i < jas_image_numfmts; ++i,
+	  ++fmtinfo) {
+		if (fmtinfo->ops.validate) {
+			/* Is the input data valid for this format? */
+			if (!(*fmtinfo->ops.validate)(in)) {
+				found = 1;
+				break;
+			}
+		}
+	}
+	return found ? fmtinfo->id : (-1);
+}
+
+int jas_image_fmtfromname(char *name)
+{
+	int i;
+	char *ext;
+	jas_image_fmtinfo_t *fmtinfo;
+	/* Get the file name extension. */
+	if (!(ext = strrchr(name, '.'))) {
+		return -1;
+	}
+	++ext;
+	/* Try to find a format that uses this extension. */	
+	for (i = 0, fmtinfo = jas_image_fmtinfos; i < jas_image_numfmts; ++i,
+	  ++fmtinfo) {
+		/* Do we have a match? */
+		if (!strcmp(ext, fmtinfo->ext)) {
+			return fmtinfo->id;
+		}
+	}
+	return -1;
+}
+
+/******************************************************************************\
+* Miscellaneous operations.
+\******************************************************************************/
+
+uint_fast32_t jas_image_rawsize(jas_image_t *image)
+{
+	uint_fast32_t rawsize;
+	uint_fast32_t cmptno;
+	jas_image_cmpt_t *cmpt;
+
+	rawsize = 0;
+	for (cmptno = 0; cmptno < image->numcmpts_; ++cmptno) {
+		cmpt = image->cmpts_[cmptno];
+		rawsize += (cmpt->width_ * cmpt->height_ * cmpt->prec_ +
+		  7) / 8;
+	}
+	return rawsize;
+}
+
+void jas_image_delcmpt(jas_image_t *image, uint_fast16_t cmptno)
+{
+	if (cmptno >= image->numcmpts_) {
+		return;
+	}
+	jas_image_cmpt_destroy(image->cmpts_[cmptno]);
+	if (cmptno < image->numcmpts_) {
+		memmove(&image->cmpts_[cmptno], &image->cmpts_[cmptno + 1],
+		  (image->numcmpts_ - 1 - cmptno) * sizeof(jas_image_cmpt_t *));
+	}
+	--image->numcmpts_;
+
+	jas_image_setbbox(image);
+}
+
+int jas_image_addcmpt(jas_image_t *image, uint_fast16_t cmptno,
+  jas_image_cmptparm_t *cmptparm)
+{
+	jas_image_cmpt_t *newcmpt;
+	assert(cmptno <= image->numcmpts_);
+	if (image->numcmpts_ >= image->maxcmpts_) {
+		if (jas_image_growcmpts(image, image->maxcmpts_ + 128)) {
+			return -1;
+		}
+	}
+	if (!(newcmpt = jas_image_cmpt_create(cmptparm->tlx,
+	  cmptparm->tly, cmptparm->hstep, cmptparm->vstep,
+	  cmptparm->width, cmptparm->height, cmptparm->prec,
+	  cmptparm->sgnd, 1))) {
+		return -1;
+	}
+	if (cmptno < image->numcmpts_) {
+		memmove(&image->cmpts_[cmptno + 1], &image->cmpts_[cmptno],
+		  (image->numcmpts_ - cmptno) * sizeof(jas_image_cmpt_t *));
+	}
+	image->cmpts_[cmptno] = newcmpt;
+	++image->numcmpts_;
+
+	jas_image_setbbox(image);
+
+	return 0;
+}
+
+jas_image_fmtinfo_t *jas_image_lookupfmtbyid(int id)
+{
+	int i;
+	jas_image_fmtinfo_t *fmtinfo;
+
+	for (i = 0, fmtinfo = jas_image_fmtinfos; i < jas_image_numfmts; ++i, ++fmtinfo) {
+		if (fmtinfo->id == id) {
+			return fmtinfo;
+		}
+	}
+	return 0;
+}
+
+jas_image_fmtinfo_t *jas_image_lookupfmtbyname(const char *name)
+{
+	int i;
+	jas_image_fmtinfo_t *fmtinfo;
+
+	for (i = 0, fmtinfo = jas_image_fmtinfos; i < jas_image_numfmts; ++i, ++fmtinfo) {
+		if (!strcmp(fmtinfo->name, name)) {
+			return fmtinfo;
+		}
+	}
+	return 0;
+}
+
+
+
+
+
+static uint_fast32_t inttobits(jas_seqent_t v, int prec, bool sgnd)
+{
+	uint_fast32_t ret;
+	ret = ((sgnd && v < 0) ? ((1 << prec) + v) : v) & JAS_ONES(prec);
+	return ret;
+}
+
+static jas_seqent_t bitstoint(uint_fast32_t v, int prec, bool sgnd)
+{
+	jas_seqent_t ret;
+	v &= JAS_ONES(prec);
+	ret = (sgnd && (v & (1 << (prec - 1)))) ? (v - (1 << prec)) : v;
+	return ret;
+}
+
+static void jas_image_setbbox(jas_image_t *image)
+{
+	jas_image_cmpt_t *cmpt;
+	int cmptno;
+	int_fast32_t x;
+	int_fast32_t y;
+
+	if (image->numcmpts_ > 0) {
+		/* Determine the bounding box for all of the components on the
+		  reference grid (i.e., the image area) */
+		cmpt = image->cmpts_[0];
+		image->tlx_ = cmpt->tlx_;
+		image->tly_ = cmpt->tly_;
+		image->brx_ = cmpt->tlx_ + cmpt->hstep_ * (cmpt->width_ - 1) + 1;
+		image->bry_ = cmpt->tly_ + cmpt->vstep_ * (cmpt->height_ - 1) + 1;
+		for (cmptno = 1; cmptno < image->numcmpts_; ++cmptno) {
+			cmpt = image->cmpts_[cmptno];
+			if (image->tlx_ > cmpt->tlx_) {
+				image->tlx_ = cmpt->tlx_;
+			}
+			if (image->tly_ > cmpt->tly_) {
+				image->tly_ = cmpt->tly_;
+			}
+			x = cmpt->tlx_ + cmpt->hstep_ * (cmpt->width_ - 1) + 1;
+			if (image->brx_ < x) {
+				image->brx_ = x;
+			}
+			y = cmpt->tly_ + cmpt->vstep_ * (cmpt->height_ - 1) + 1;
+			if (image->bry_ < y) {
+				image->bry_ = y;
+			}
+		}
+	} else {
+		image->tlx_ = 0;
+		image->tly_ = 0;
+		image->brx_ = 0;
+		image->bry_ = 0;
+	}
+}
+
+static int jas_image_growcmpts(jas_image_t *image, int maxcmpts)
+{
+	jas_image_cmpt_t **newcmpts;
+	int cmptno;
+
+	newcmpts = (!image->cmpts_) ? jas_malloc(maxcmpts * sizeof(jas_image_cmpt_t *)) :
+	  jas_realloc(image->cmpts_, maxcmpts * sizeof(jas_image_cmpt_t *));
+	if (!newcmpts) {
+		return -1;
+	}
+	image->cmpts_ = newcmpts;
+	image->maxcmpts_ = maxcmpts;
+	for (cmptno = image->numcmpts_; cmptno < image->maxcmpts_; ++cmptno) {
+		image->cmpts_[cmptno] = 0;
+	}
+	return 0;
+}
+
+int jas_image_copycmpt(jas_image_t *dstimage, int dstcmptno, jas_image_t *srcimage,
+  int srccmptno)
+{
+	jas_image_cmpt_t *newcmpt;
+	if (dstimage->numcmpts_ >= dstimage->maxcmpts_) {
+		if (jas_image_growcmpts(dstimage, dstimage->maxcmpts_ + 128)) {
+			return -1;
+		}
+	}
+	if (!(newcmpt = jas_image_cmpt_copy(srcimage->cmpts_[srccmptno]))) {
+		return -1;
+	}
+	if (dstcmptno < dstimage->numcmpts_) {
+		memmove(&dstimage->cmpts_[dstcmptno + 1], &dstimage->cmpts_[dstcmptno],
+		  (dstimage->numcmpts_ - dstcmptno) * sizeof(jas_image_cmpt_t *));
+	}
+	dstimage->cmpts_[dstcmptno] = newcmpt;
+	++dstimage->numcmpts_;
+
+	jas_image_setbbox(dstimage);
+	return 0;
+}
+
+void jas_image_dump(jas_image_t *image, FILE *out)
+{
+	int cmptno;
+	jas_seq2d_t *data;
+	jas_image_cmpt_t *cmpt;
+	if (!(data = jas_seq2d_create(0, 0, 1, 1))) {
+		abort();
+	}
+	for (cmptno = 0; cmptno < image->numcmpts_; ++cmptno) {
+		cmpt = image->cmpts_[cmptno];
+		fprintf(out, "prec=%d sgnd=%d\n", cmpt->prec_, cmpt->sgnd_);
+		if (jas_image_readcmpt(image, cmptno, 0, 0, 1, 1, data)) {
+			abort();
+		}
+		fprintf(out, "tlsample %ld\n", (long) jas_seq2d_get(data, 0, 0));
+	}
+	jas_seq2d_destroy(data);
+}
+
+int jas_image_depalettize(jas_image_t *image, int cmptno, int numlutents,
+  int_fast32_t *lutents, int dtype, int newcmptno)
+{
+	jas_image_cmptparm_t cmptparms;
+	int_fast32_t v;
+	int i;
+	int j;
+	jas_image_cmpt_t *cmpt;
+
+	cmpt = image->cmpts_[cmptno];
+	cmptparms.tlx = cmpt->tlx_;
+	cmptparms.tly = cmpt->tly_;
+	cmptparms.hstep = cmpt->hstep_;
+	cmptparms.vstep = cmpt->vstep_;
+	cmptparms.width = cmpt->width_;
+	cmptparms.height = cmpt->height_;
+	cmptparms.prec = JAS_IMAGE_CDT_GETPREC(dtype);
+	cmptparms.sgnd = JAS_IMAGE_CDT_GETSGND(dtype);
+
+	if (jas_image_addcmpt(image, newcmptno, &cmptparms)) {
+		return -1;
+	}
+	if (newcmptno <= cmptno) {
+		++cmptno;
+		cmpt = image->cmpts_[cmptno];
+	}
+
+	for (j = 0; j < cmpt->height_; ++j) {
+		for (i = 0; i < cmpt->width_; ++i) {
+			v = jas_image_readcmptsample(image, cmptno, i, j);
+			if (v < 0) {
+				v = 0;
+			} else if (v >= numlutents) {
+				v = numlutents - 1;
+			}
+			jas_image_writecmptsample(image, newcmptno, i, j,
+			  lutents[v]);
+		}
+	}
+	return 0;
+}
+
+int jas_image_readcmptsample(jas_image_t *image, int cmptno, int x, int y)
+{
+	jas_image_cmpt_t *cmpt;
+	uint_fast32_t v;
+	int k;
+	int c;
+
+	cmpt = image->cmpts_[cmptno];
+
+	if (jas_stream_seek(cmpt->stream_, (cmpt->width_ * y + x) * cmpt->cps_,
+	  SEEK_SET) < 0) {
+		return -1;
+	}
+	v = 0;
+	for (k = cmpt->cps_; k > 0; --k) {
+		if ((c = jas_stream_getc(cmpt->stream_)) == EOF) {
+			return -1;
+		}
+		v = (v << 8) | (c & 0xff);
+	}
+	return bitstoint(v, cmpt->prec_, cmpt->sgnd_);
+}
+
+void jas_image_writecmptsample(jas_image_t *image, int cmptno, int x, int y,
+  int_fast32_t v)
+{
+	jas_image_cmpt_t *cmpt;
+	uint_fast32_t t;
+	int k;
+	int c;
+
+	cmpt = image->cmpts_[cmptno];
+
+	if (jas_stream_seek(cmpt->stream_, (cmpt->width_ * y + x) * cmpt->cps_,
+	  SEEK_SET) < 0) {
+		return;
+	}
+	t = inttobits(v, cmpt->prec_, cmpt->sgnd_);
+	for (k = cmpt->cps_; k > 0; --k) {
+		c = (t >> (8 * (cmpt->cps_ - 1))) & 0xff;
+		if (jas_stream_putc(cmpt->stream_, (unsigned char) c) == EOF) {
+			return;
+		}
+		t <<= 8;
+	}
+}
+
+int jas_image_getcmptbytype(jas_image_t *image, int ctype)
+{
+	int cmptno;
+
+	for (cmptno = 0; cmptno < image->numcmpts_; ++cmptno) {
+		if (image->cmpts_[cmptno]->type_ == ctype) {
+			return cmptno;
+		}
+	}
+    return -1;
+}
diff --git a/converter/other/jpeg2000/libjasper/base/jas_init.c b/converter/other/jpeg2000/libjasper/base/jas_init.c
new file mode 100644
index 00000000..c1114bf7
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/jas_init.c
@@ -0,0 +1,200 @@
+/*
+ * 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__
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_image.h"
+#include "jasper/jas_init.h"
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+/* Initialize the image format table. */
+int jas_init()
+{
+	jas_image_fmtops_t fmtops;
+	int fmtid;
+
+	fmtid = 0;
+
+#if !defined(EXCLUDE_MIF_SUPPORT)
+	fmtops.decode = mif_decode;
+	fmtops.encode = mif_encode;
+	fmtops.validate = mif_validate;
+	jas_image_addfmt(fmtid, "mif", "mif", "My Image Format (MIF)", &fmtops);
+	++fmtid;
+#endif
+
+#if !defined(EXCLUDE_PNM_SUPPORT)
+	fmtops.decode = pnm_decode;
+	fmtops.encode = pnm_encode;
+	fmtops.validate = pnm_validate;
+	jas_image_addfmt(fmtid, "pnm", "pnm", "Portable Graymap/Pixmap (PNM)",
+	  &fmtops);
+	jas_image_addfmt(fmtid, "pnm", "pgm", "Portable Graymap/Pixmap (PNM)",
+	  &fmtops);
+	jas_image_addfmt(fmtid, "pnm", "ppm", "Portable Graymap/Pixmap (PNM)",
+	  &fmtops);
+	++fmtid;
+#endif
+
+#if !defined(EXCLUDE_BMP_SUPPORT)
+	fmtops.decode = bmp_decode;
+	fmtops.encode = bmp_encode;
+	fmtops.validate = bmp_validate;
+	jas_image_addfmt(fmtid, "bmp", "bmp", "Microsoft Bitmap (BMP)", &fmtops);
+	++fmtid;
+#endif
+
+#if !defined(EXCLUDE_RAS_SUPPORT)
+	fmtops.decode = ras_decode;
+	fmtops.encode = ras_encode;
+	fmtops.validate = ras_validate;
+	jas_image_addfmt(fmtid, "ras", "ras", "Sun Rasterfile (RAS)", &fmtops);
+	++fmtid;
+#endif
+
+#if !defined(EXCLUDE_JP2_SUPPORT)
+	fmtops.decode = jp2_decode;
+	fmtops.encode = jp2_encode;
+	fmtops.validate = jp2_validate;
+	jas_image_addfmt(fmtid, "jp2", "jp2",
+	  "JPEG-2000 JP2 File Format Syntax (ISO/IEC 15444-1)", &fmtops);
+	++fmtid;
+	fmtops.decode = jpc_decode;
+	fmtops.encode = jpc_encode;
+	fmtops.validate = jpc_validate;
+	jas_image_addfmt(fmtid, "jpc", "jpc",
+	  "JPEG-2000 Code Stream Syntax (ISO/IEC 15444-1)", &fmtops);
+	++fmtid;
+#endif
+
+#if !defined(EXCLUDE_JPG_SUPPORT)
+	fmtops.decode = jpg_decode;
+	fmtops.encode = jpg_encode;
+	fmtops.validate = jpg_validate;
+	jas_image_addfmt(fmtid, "jpg", "jpg", "JPEG (ISO/IEC 10918-1)", &fmtops);
+	++fmtid;
+#endif
+
+#if !defined(EXCLUDE_PGX_SUPPORT)
+	fmtops.decode = pgx_decode;
+	fmtops.encode = pgx_encode;
+	fmtops.validate = pgx_validate;
+	jas_image_addfmt(fmtid, "pgx", "pgx", "JPEG-2000 VM Format (PGX)", &fmtops);
+	++fmtid;
+#endif
+
+	return 0;
+}
diff --git a/converter/other/jpeg2000/libjasper/base/jas_malloc.c b/converter/other/jpeg2000/libjasper/base/jas_malloc.c
new file mode 100644
index 00000000..43c4d3cd
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/jas_malloc.c
@@ -0,0 +1,167 @@
+/*
+ * 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__
+ */
+
+/*
+ * Memory Allocator
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+
+/* We need the prototype for memset. */
+#include <string.h>
+
+#include "jasper/jas_malloc.h"
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+#if defined(DEBUG_MEMALLOC)
+#include "../../../local/src/memalloc.c"
+#endif
+
+#if !defined(DEBUG_MEMALLOC)
+
+void *jas_malloc(size_t size)
+{
+	return malloc(size);
+}
+
+void jas_free(void *ptr)
+{
+	free(ptr);
+}
+
+void *jas_realloc(void *ptr, size_t size)
+{
+	return realloc(ptr, size);
+}
+
+void *jas_calloc(size_t nmemb, size_t size)
+{
+	void *ptr;
+	size_t n;
+	n = nmemb * size;
+	if (!(ptr = jas_malloc(n * sizeof(char)))) {
+		return 0;
+	}
+	memset(ptr, 0, n);
+	return ptr;
+}
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/base/jas_seq.c b/converter/other/jpeg2000/libjasper/base/jas_seq.c
new file mode 100644
index 00000000..b8e3c94b
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/jas_seq.c
@@ -0,0 +1,475 @@
+/*
+ * 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__
+ */
+
+/*
+ * Sequence/Matrix Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+
+#include "jasper/jas_seq.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_math.h"
+
+/******************************************************************************\
+* Constructors and destructors.
+\******************************************************************************/
+
+jas_matrix_t *jas_seq2d_create(int xstart, int ystart, int xend, int yend)
+{
+	jas_matrix_t *matrix;
+	assert(xstart <= xend && ystart <= yend);
+	if (!(matrix = jas_matrix_create(yend - ystart, xend - xstart))) {
+		return 0;
+	}
+	matrix->xstart_ = xstart;
+	matrix->ystart_ = ystart;
+	matrix->xend_ = xend;
+	matrix->yend_ = yend;
+	return matrix;
+}
+
+jas_matrix_t *jas_matrix_create(int numrows, int numcols)
+{
+	jas_matrix_t *matrix;
+	int i;
+
+	if (!(matrix = jas_malloc(sizeof(jas_matrix_t)))) {
+		return 0;
+	}
+	matrix->flags_ = 0;
+	matrix->numrows_ = numrows;
+	matrix->numcols_ = numcols;
+	matrix->rows_ = 0;
+	matrix->maxrows_ = numrows;
+	matrix->data_ = 0;
+	matrix->datasize_ = numrows * numcols;
+
+	if (matrix->maxrows_ > 0) {
+		if (!(matrix->rows_ = jas_malloc(matrix->maxrows_ *
+		  sizeof(jas_seqent_t *)))) {
+			jas_matrix_destroy(matrix);
+			return 0;
+		}
+	}
+
+	if (matrix->datasize_ > 0) {
+		if (!(matrix->data_ = jas_malloc(matrix->datasize_ *
+		  sizeof(jas_seqent_t)))) {
+			jas_matrix_destroy(matrix);
+			return 0;
+		}
+	}
+
+	for (i = 0; i < numrows; ++i) {
+		matrix->rows_[i] = &matrix->data_[i * matrix->numcols_];
+	}
+
+	for (i = 0; i < matrix->datasize_; ++i) {
+		matrix->data_[i] = 0;
+	}
+
+	matrix->xstart_ = 0;
+	matrix->ystart_ = 0;
+	matrix->xend_ = matrix->numcols_;
+	matrix->yend_ = matrix->numrows_;
+
+	return matrix;
+}
+
+void jas_matrix_destroy(jas_matrix_t *matrix)
+{
+	if (matrix->data_) {
+		assert(!(matrix->flags_ & JAS_MATRIX_REF));
+		jas_free(matrix->data_);
+		matrix->data_ = 0;
+	}
+	if (matrix->rows_) {
+		jas_free(matrix->rows_);
+		matrix->rows_ = 0;
+	}
+	jas_free(matrix);
+}
+
+jas_seq2d_t *jas_seq2d_copy(jas_seq2d_t *x)
+{
+	jas_matrix_t *y;
+	int i;
+	int j;
+	y = jas_seq2d_create(jas_seq2d_xstart(x), jas_seq2d_ystart(x), jas_seq2d_xend(x),
+	  jas_seq2d_yend(x));
+	assert(y);
+	for (i = 0; i < x->numrows_; ++i) {
+		for (j = 0; j < x->numcols_; ++j) {
+			*jas_matrix_getref(y, i, j) = jas_matrix_get(x, i, j);
+		}
+	}
+	return y;
+}
+
+jas_matrix_t *jas_matrix_copy(jas_matrix_t *x)
+{
+	jas_matrix_t *y;
+	int i;
+	int j;
+	y = jas_matrix_create(x->numrows_, x->numcols_);
+	for (i = 0; i < x->numrows_; ++i) {
+		for (j = 0; j < x->numcols_; ++j) {
+			*jas_matrix_getref(y, i, j) = jas_matrix_get(x, i, j);
+		}
+	}
+	return y;
+}
+
+/******************************************************************************\
+* Bind operations.
+\******************************************************************************/
+
+void jas_seq2d_bindsub(jas_matrix_t *s, jas_matrix_t *s1, int xstart, int ystart,
+  int xend, int yend)
+{
+	jas_matrix_bindsub(s, s1, ystart - s1->ystart_, xstart - s1->xstart_,
+	  yend - s1->ystart_ - 1, xend - s1->xstart_ - 1);
+}
+
+void jas_matrix_bindsub(jas_matrix_t *mat0, jas_matrix_t *mat1, int r0, int c0,
+  int r1, int c1)
+{
+	int i;
+
+	if (mat0->data_) {
+		if (!(mat0->flags_ & JAS_MATRIX_REF)) {
+			jas_free(mat0->data_);
+		}
+		mat0->data_ = 0;
+		mat0->datasize_ = 0;
+	}
+	if (mat0->rows_) {
+		jas_free(mat0->rows_);
+		mat0->rows_ = 0;
+	}
+	mat0->flags_ |= JAS_MATRIX_REF;
+	mat0->numrows_ = r1 - r0 + 1;
+	mat0->numcols_ = c1 - c0 + 1;
+	mat0->maxrows_ = mat0->numrows_;
+	mat0->rows_ = jas_malloc(mat0->maxrows_ * sizeof(jas_seqent_t *));
+	for (i = 0; i < mat0->numrows_; ++i) {
+		mat0->rows_[i] = mat1->rows_[r0 + i] + c0;
+	}
+
+	mat0->xstart_ = mat1->xstart_ + c0;
+	mat0->ystart_ = mat1->ystart_ + r0;
+	mat0->xend_ = mat0->xstart_ + mat0->numcols_;
+	mat0->yend_ = mat0->ystart_ + mat0->numrows_;
+}
+
+/******************************************************************************\
+* Arithmetic operations.
+\******************************************************************************/
+
+int jas_matrix_cmp(jas_matrix_t *mat0, jas_matrix_t *mat1)
+{
+	int i;
+	int j;
+
+	if (mat0->numrows_ != mat1->numrows_ || mat0->numcols_ !=
+	  mat1->numcols_) {
+		return 1;
+	}
+	for (i = 0; i < mat0->numrows_; i++) {
+		for (j = 0; j < mat0->numcols_; j++) {
+			if (jas_matrix_get(mat0, i, j) != jas_matrix_get(mat1, i, j)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+void jas_matrix_divpow2(jas_matrix_t *matrix, int n)
+{
+	int i;
+	int j;
+	jas_seqent_t *rowstart;
+	int rowstep;
+	jas_seqent_t *data;
+
+	rowstep = jas_matrix_rowstep(matrix);
+	for (i = matrix->numrows_, rowstart = matrix->rows_[0]; i > 0; --i,
+	  rowstart += rowstep) {
+		for (j = matrix->numcols_, data = rowstart; j > 0; --j,
+		  ++data) {
+			*data = (*data >= 0) ? ((*data) >> n) :
+			  (-((-(*data)) >> n));
+		}
+	}
+}
+
+void jas_matrix_clip(jas_matrix_t *matrix, jas_seqent_t minval, jas_seqent_t maxval)
+{
+	int i;
+	int j;
+	jas_seqent_t v;
+	jas_seqent_t *rowstart;
+	jas_seqent_t *data;
+	int rowstep;
+
+	rowstep = jas_matrix_rowstep(matrix);
+	for (i = matrix->numrows_, rowstart = matrix->rows_[0]; i > 0; --i,
+	  rowstart += rowstep) {
+		data = rowstart;
+		for (j = matrix->numcols_, data = rowstart; j > 0; --j,
+		  ++data) {
+			v = *data;
+			if (v < minval) {
+				*data = minval;
+			} else if (v > maxval) {
+				*data = maxval;
+			}
+		}
+	}
+}
+
+void jas_matrix_asr(jas_matrix_t *matrix, int n)
+{
+	int i;
+	int j;
+	jas_seqent_t *rowstart;
+	int rowstep;
+	jas_seqent_t *data;
+
+	assert(n >= 0);
+	rowstep = jas_matrix_rowstep(matrix);
+	for (i = matrix->numrows_, rowstart = matrix->rows_[0]; i > 0; --i,
+	  rowstart += rowstep) {
+		for (j = matrix->numcols_, data = rowstart; j > 0; --j,
+		  ++data) {
+			*data >>= n;
+		}
+	}
+}
+
+void jas_matrix_asl(jas_matrix_t *matrix, int n)
+{
+	int i;
+	int j;
+	jas_seqent_t *rowstart;
+	int rowstep;
+	jas_seqent_t *data;
+
+	rowstep = jas_matrix_rowstep(matrix);
+	for (i = matrix->numrows_, rowstart = matrix->rows_[0]; i > 0; --i,
+	  rowstart += rowstep) {
+		for (j = matrix->numcols_, data = rowstart; j > 0; --j,
+		  ++data) {
+			*data <<= n;
+		}
+	}
+}
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+int jas_matrix_resize(jas_matrix_t *matrix, int numrows, int numcols)
+{
+	int size;
+	int i;
+
+	size = numrows * numcols;
+	if (size > matrix->datasize_ || numrows > matrix->maxrows_) {
+		return -1;
+	}
+
+	matrix->numrows_ = numrows;
+	matrix->numcols_ = numcols;
+
+	for (i = 0; i < numrows; ++i) {
+		matrix->rows_[i] = &matrix->data_[numcols * i];
+	}
+
+	return 0;
+}
+
+int jas_matrix_output(jas_matrix_t *matrix, FILE *out)
+{
+	int i;
+	int j;
+	jas_seqent_t x;
+
+	fprintf(out, "%d %d\n", jas_matrix_numrows(matrix), 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);
+			fprintf(out, "%ld", JAS_CAST(long, x));
+			if (j < jas_matrix_numcols(matrix) - 1) {
+				fprintf(out, " ");
+			}
+		}
+		fprintf(out, "\n");
+	}
+	return 0;
+}
+
+void jas_matrix_setall(jas_matrix_t *matrix, jas_seqent_t val)
+{
+	int i;
+	int j;
+	jas_seqent_t *rowstart;
+	int rowstep;
+	jas_seqent_t *data;
+
+	rowstep = jas_matrix_rowstep(matrix);
+	for (i = matrix->numrows_, rowstart = matrix->rows_[0]; i > 0; --i,
+	  rowstart += rowstep) {
+		for (j = matrix->numcols_, data = rowstart; j > 0; --j,
+		  ++data) {
+			*data = val;
+		}
+	}
+}
+
+jas_matrix_t *jas_matrix_input(FILE *in)
+{
+	jas_matrix_t *matrix;
+	int i;
+	int j;
+	long x;
+	int numrows;
+	int numcols;
+
+	if (fscanf(in, "%d %d", &numrows, &numcols) != 2)
+		return 0;
+	if (!(matrix = jas_matrix_create(numrows, numcols)))
+		return 0;
+
+	/* Get matrix data. */
+	for (i = 0; i < jas_matrix_numrows(matrix); i++) {
+		for (j = 0; j < jas_matrix_numcols(matrix); j++) {
+			if (fscanf(in, "%ld", &x) != 1) {
+				jas_matrix_destroy(matrix);
+				return 0;
+			}
+			jas_matrix_set(matrix, i, j, JAS_CAST(jas_seqent_t, x));
+		}
+	}
+
+	return matrix;
+}
diff --git a/converter/other/jpeg2000/libjasper/base/jas_stream.c b/converter/other/jpeg2000/libjasper/base/jas_stream.c
new file mode 100644
index 00000000..f450aabf
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/jas_stream.c
@@ -0,0 +1,1204 @@
+/*
+ * 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__
+ */
+
+#define _SVID_SOURCE
+    /* Make sure P_tmpdir is defined in GNU libc 2.0.7 (_XOPEN_SOURCE 500
+       does it in other libc's).  pm_config.h defines TMPDIR as P_tmpdir
+       in some environments.
+    */
+#define _XOPEN_SOURCE 500    /* Make sure P_tmpdir is defined */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <ctype.h>
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#if defined(WIN32) || defined(HAVE_IO_H)
+#include <io.h>
+#endif
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_stream.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_math.h"
+
+/****************************************************************************\
+* Local function prototypes.
+\****************************************************************************/
+
+static int jas_strtoopenmode(const char *s);
+static void jas_stream_destroy(jas_stream_t *stream);
+static jas_stream_t *jas_stream_create(void);
+static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
+  int bufsize);
+
+static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt);
+static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt);
+static long mem_seek(jas_stream_obj_t *obj, long offset, int origin);
+static int mem_close(jas_stream_obj_t *obj);
+
+static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt);
+static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt);
+static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin);
+static int sfile_close(jas_stream_obj_t *obj);
+
+static int file_read(jas_stream_obj_t *obj, char *buf, int cnt);
+static int file_write(jas_stream_obj_t *obj, char *buf, int cnt);
+static long file_seek(jas_stream_obj_t *obj, long offset, int origin);
+static int file_close(jas_stream_obj_t *obj);
+
+/******************************************************************************\
+* Local data.
+\******************************************************************************/
+
+static jas_stream_ops_t jas_stream_fileops = {
+	file_read,
+	file_write,
+	file_seek,
+	file_close
+};
+
+static jas_stream_ops_t jas_stream_sfileops = {
+	sfile_read,
+	sfile_write,
+	sfile_seek,
+	sfile_close
+};
+
+static jas_stream_ops_t jas_stream_memops = {
+	mem_read,
+	mem_write,
+	mem_seek,
+	mem_close
+};
+
+/******************************************************************************\
+* Code for opening and closing streams.
+\******************************************************************************/
+
+static jas_stream_t *jas_stream_create()
+{
+	jas_stream_t *stream;
+
+	if (!(stream = jas_malloc(sizeof(jas_stream_t)))) {
+		return 0;
+	}
+	stream->openmode_ = 0;
+	stream->bufmode_ = 0;
+	stream->flags_ = 0;
+	stream->bufbase_ = 0;
+	stream->bufstart_ = 0;
+	stream->bufsize_ = 0;
+	stream->ptr_ = 0;
+	stream->cnt_ = 0;
+	stream->ops_ = 0;
+	stream->obj_ = 0;
+	stream->rwcnt_ = 0;
+	stream->rwlimit_ = -1;
+
+	return stream;
+}
+
+jas_stream_t *jas_stream_memopen(char *buf, int bufsize)
+{
+	jas_stream_t *stream;
+	jas_stream_memobj_t *obj;
+
+	if (!(stream = jas_stream_create())) {
+		return 0;
+	}
+
+	/* A stream associated with a memory buffer is always opened
+	for both reading and writing in binary mode. */
+	stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
+
+	/* Since the stream data is already resident in memory, buffering
+	is not necessary. */
+	/* But... It still may be faster to use buffering anyways. */
+	jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
+
+	/* Select the operations for a memory stream. */
+	stream->ops_ = &jas_stream_memops;
+
+	/* Allocate memory for the underlying memory stream object. */
+	if (!(obj = jas_malloc(sizeof(jas_stream_memobj_t)))) {
+		jas_stream_destroy(stream);
+		return 0;
+	}
+	stream->obj_ = (void *) obj;
+
+	/* Initialize a few important members of the memory stream object. */
+	obj->myalloc_ = 0;
+	obj->buf_ = 0;
+
+	/* If the buffer size specified is nonpositive, then the buffer
+	is allocated internally and automatically grown as needed. */
+	if (bufsize <= 0) {
+		obj->bufsize_ = 1024;
+		obj->growable_ = 1;
+	} else {
+		obj->bufsize_ = bufsize;
+		obj->growable_ = 0;
+	}
+	if (buf) {
+		obj->buf_ = (unsigned char *) buf;
+	} else {
+		obj->buf_ = jas_malloc(obj->bufsize_ * sizeof(char));
+		obj->myalloc_ = 1;
+	}
+	if (!obj->buf_) {
+		jas_stream_close(stream);
+		return 0;
+	}
+
+	if (bufsize > 0 && buf) {
+		/* If a buffer was supplied by the caller and its length is positive,
+		  make the associated buffer data appear in the stream initially. */
+		obj->len_ = bufsize;
+	} else {
+		/* The stream is initially empty. */
+		obj->len_ = 0;
+	}
+	obj->pos_ = 0;
+	
+	return stream;
+}
+
+jas_stream_t *jas_stream_fopen(const char *filename, const char *mode)
+{
+	jas_stream_t *stream;
+	int *obj;
+	int openflags;
+
+	/* Allocate a stream object. */
+	if (!(stream = jas_stream_create())) {
+		return 0;
+	}
+
+	/* Parse the mode string. */
+	stream->openmode_ = jas_strtoopenmode(mode);
+
+	/* Determine the correct flags to use for opening the file. */
+	if ((stream->openmode_ & JAS_STREAM_READ) &&
+	  (stream->openmode_ & JAS_STREAM_WRITE)) {
+		openflags = O_RDWR;
+	} else if (stream->openmode_ & JAS_STREAM_READ) {
+		openflags = O_RDONLY;
+	} else if (stream->openmode_ & JAS_STREAM_WRITE) {
+		openflags = O_WRONLY;
+	} else {
+		openflags = 0;
+	}
+	if (stream->openmode_ & JAS_STREAM_APPEND) {
+		openflags |= O_APPEND;
+	}
+	if (stream->openmode_ & JAS_STREAM_BINARY) {
+		openflags |= O_BINARY;
+	}
+	if (stream->openmode_ & JAS_STREAM_CREATE) {
+		openflags |= O_CREAT | O_TRUNC;
+	}
+
+	/* Allocate space for the underlying file stream object. */
+	if (!(obj = jas_malloc(sizeof(int)))) {
+		jas_stream_destroy(stream);
+		return 0;
+	}
+	stream->obj_ = (void *) obj;
+
+	/* Select the operations for a file stream object. */
+	stream->ops_ = &jas_stream_fileops;
+
+	/* Open the underlying file. */
+	if ((*obj = open(filename, openflags, JAS_STREAM_PERMS)) < 0) {
+		jas_stream_destroy(stream);
+		return 0;
+	}
+
+	/* By default, use full buffering for this type of stream. */
+	jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
+
+	return stream;
+}
+
+jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp)
+{
+	jas_stream_t *stream;
+	int openflags;
+
+	/* Allocate a stream object. */
+	if (!(stream = jas_stream_create())) {
+		return 0;
+	}
+
+	/* Parse the mode string. */
+	stream->openmode_ = jas_strtoopenmode(mode);
+
+	/* Determine the correct flags to use for opening the file. */
+	if ((stream->openmode_ & JAS_STREAM_READ) &&
+	  (stream->openmode_ & JAS_STREAM_WRITE)) {
+		openflags = O_RDWR;
+	} else if (stream->openmode_ & JAS_STREAM_READ) {
+		openflags = O_RDONLY;
+	} else if (stream->openmode_ & JAS_STREAM_WRITE) {
+		openflags = O_WRONLY;
+	} else {
+		openflags = 0;
+	}
+	if (stream->openmode_ & JAS_STREAM_APPEND) {
+		openflags |= O_APPEND;
+	}
+	if (stream->openmode_ & JAS_STREAM_BINARY) {
+		openflags |= O_BINARY;
+	}
+	if (stream->openmode_ & JAS_STREAM_CREATE) {
+		openflags |= O_CREAT | O_TRUNC;
+	}
+
+	stream->obj_ = JAS_CAST(void *, fp);
+
+	/* Select the operations for a file stream object. */
+	stream->ops_ = &jas_stream_sfileops;
+
+	/* By default, use full buffering for this type of stream. */
+	jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
+
+	return stream;
+}
+
+
+static int
+tmpfilex(void) {
+/*----------------------------------------------------------------------------
+   This is a copy of pm_tmpfile() without the libnetpbm dependencies
+   and returning a file descriptor instead of stream.
+-----------------------------------------------------------------------------*/
+    const char libname[] = "jasper";
+
+    int fd;
+    char buf[FILENAME_MAX];
+    const char * tbuf;
+    unsigned int fnamelen;
+
+    fnamelen = strlen(libname) + 10; /* "/" + "_XXXXXX\0" */
+
+    tbuf = getenv("TMPDIR");
+
+    if ((tbuf != NULL) && (strlen(tbuf) > FILENAME_MAX - fnamelen))
+        /* length of TMPDIR value too big for buf */
+        tbuf = NULL;
+
+    buf[FILENAME_MAX - fnamelen -1] = 0;
+
+    if ((tbuf == NULL) || (strlen(tbuf) == 0))
+        /* environment variable not suitable to construct file name.
+           Use default.
+        */
+        strncpy(buf, TMPDIR, sizeof(buf) - fnamelen);
+    else
+        strncpy(buf, tbuf, sizeof(buf) - fnamelen);
+
+    if (buf[strlen(buf) - 1] != '/')
+        strcat (buf, "/");
+    
+    strcat(buf, libname);
+    strcat(buf, "_XXXXXX");
+
+    fd = mkstemp(buf);
+
+    if (fd >= 0)
+        unlink(buf);
+
+    return fd;
+}
+
+jas_stream_t *jas_stream_tmpfile()
+{
+	jas_stream_t *stream;
+	int *obj;
+
+	if (!(stream = jas_stream_create())) {
+		return 0;
+	}
+
+	/* A temporary file stream is always opened for both reading and
+	writing in binary mode. */
+	stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
+
+	/* Allocate memory for the underlying temporary file object. */
+	if (!(obj = jas_malloc(sizeof(int)))) {
+		jas_stream_destroy(stream);
+		return 0;
+	}
+	stream->obj_ = obj;
+    
+    /* This is a Netpbm enhancement.  Original Jasper library uses
+       tmpnam(), which is unsafe.
+    */
+    if ((*obj = tmpfilex()) < 0) {
+		jas_stream_destroy(stream);
+		return 0;
+    }
+	/* Use full buffering. */
+	jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
+
+	stream->ops_ = &jas_stream_fileops;
+
+	return stream;
+}
+
+jas_stream_t *jas_stream_fdopen(int fd, const char *mode)
+{
+	jas_stream_t *stream;
+	int *obj;
+
+	/* Allocate a stream object. */
+	if (!(stream = jas_stream_create())) {
+		return 0;
+	}
+
+	/* Parse the mode string. */
+	stream->openmode_ = jas_strtoopenmode(mode);
+
+#if defined(WIN32)
+	/* 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
+	  has specified the binary mode flag.  Arguably, the caller ought to
+	  take care of this, but text mode is a ugly wart anyways, so we save
+	  the caller some grief by handling this within the stream library. */
+	/* This ugliness is mainly for the benefit of those who run the
+	  JasPer software under Windows from shells that insist on opening
+	  files in text mode.  For example, in the Cygwin environment,
+	  shells often open files in text mode when I/O redirection is
+	  used.  Grr... */
+	if (stream->openmode_ & JAS_STREAM_BINARY) {
+		setmode(fd, O_BINARY);
+	}
+#endif
+
+	/* Allocate space for the underlying file stream object. */
+	if (!(obj = jas_malloc(sizeof(int)))) {
+		jas_stream_destroy(stream);
+		return 0;
+	}
+	stream->obj_ = (void *) obj;
+	*obj = fd;
+
+	/* By default, use full buffering for this type of stream. */
+	jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
+
+	/* Select the operations for a file stream object. */
+	stream->ops_ = &jas_stream_fileops;
+
+/* Do not close the underlying file descriptor when the stream is closed. */
+	stream->openmode_ |= JAS_STREAM_NOCLOSE;
+
+	return stream;
+}
+
+static void jas_stream_destroy(jas_stream_t *stream)
+{
+	/* If the memory for the buffer was allocated with malloc, free
+	this memory. */
+	if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
+		jas_free(stream->bufbase_);
+		stream->bufbase_ = 0;
+	}
+	jas_free(stream);
+}
+
+int jas_stream_close(jas_stream_t *stream)
+{
+	/* Flush buffer if necessary. */
+	jas_stream_flush(stream);
+
+	/* Close the underlying stream object. */
+	if (!(stream->openmode_ & JAS_STREAM_NOCLOSE)) {
+		(*stream->ops_->close_)(stream->obj_);
+	}
+
+	jas_stream_destroy(stream);
+
+	return 0;
+}
+
+/******************************************************************************\
+* Code for reading and writing streams.
+\******************************************************************************/
+
+int jas_stream_getc_func(jas_stream_t *stream)
+{
+	assert(stream->ptr_ - stream->bufbase_ <= stream->bufsize_ +
+	  JAS_STREAM_MAXPUTBACK);
+	return jas_stream_getc_macro(stream);
+}
+
+int jas_stream_putc_func(jas_stream_t *stream, int c)
+{
+	assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
+	return jas_stream_putc_macro(stream, c);
+}
+
+int jas_stream_ungetc(jas_stream_t *stream, int c)
+{
+	if (!stream->ptr_ || stream->ptr_ == stream->bufbase_) {
+		return -1;
+	}
+
+	/* Reset the EOF indicator (since we now have at least one character
+	  to read). */
+	stream->flags_ &= ~JAS_STREAM_EOF;
+
+	--stream->rwcnt_;
+	--stream->ptr_;
+	++stream->cnt_;
+	*stream->ptr_ = c;
+	return 0;
+}
+
+int jas_stream_read(jas_stream_t *stream, void *buf, int cnt)
+{
+	int n;
+	int c;
+	char *bufptr;
+
+	bufptr = buf;
+
+	n = 0;
+	while (n < cnt) {
+		if ((c = jas_stream_getc(stream)) == EOF) {
+			return n;
+		}
+		*bufptr++ = c;
+		++n;
+	}
+
+	return n;
+}
+
+int jas_stream_write(jas_stream_t *stream, const void *buf, int cnt)
+{
+	int n;
+	const char *bufptr;
+
+	bufptr = buf;
+
+	n = 0;
+	while (n < cnt) {
+		if (jas_stream_putc(stream, *bufptr) == EOF) {
+			return n;
+		}
+		++bufptr;
+		++n;
+	}
+
+	return n;
+}
+
+/* Note: This function uses a fixed size buffer.  Therefore, it cannot
+  handle invocations that will produce more output than can be held
+  by the buffer. */
+int jas_stream_printf(jas_stream_t *stream, const char *fmt, ...)
+{
+	va_list ap;
+	char buf[4096];
+	int ret;
+
+	va_start(ap, fmt);
+	ret = vsprintf(buf, fmt, ap);
+	jas_stream_puts(stream, buf);
+	va_end(ap);
+	return ret;
+}
+
+int jas_stream_puts(jas_stream_t *stream, const char *s)
+{
+	while (*s != '\0') {
+		if (jas_stream_putc_macro(stream, *s) == EOF) {
+			return -1;
+		}
+		++s;
+	}
+	return 0;
+}
+
+char *jas_stream_gets(jas_stream_t *stream, char *buf, int bufsize)
+{
+	int c;
+	char *bufptr;
+	assert(bufsize > 0);
+
+	bufptr = buf;
+	while (bufsize > 1) {
+		if ((c = jas_stream_getc(stream)) == EOF) {
+			break;
+		}
+		*bufptr++ = c;
+		--bufsize;
+		if (c == '\n') {
+			break;
+		}
+	}
+	*bufptr = '\0';
+	return buf;
+}
+
+int jas_stream_gobble(jas_stream_t *stream, int n)
+{
+	int m;
+	m = n;
+	for (m = n; m > 0; --m) {
+		if (jas_stream_getc(stream) == EOF) {
+			return n - m;
+		}
+	}
+	return n;
+}
+
+/******************************************************************************\
+* Code for getting and setting the stream position.
+\******************************************************************************/
+
+int jas_stream_isseekable(jas_stream_t *stream)
+{
+	if (stream->ops_ == &jas_stream_memops) {
+		return 1;
+	} else if (stream->ops_ == &jas_stream_fileops) {
+		if ((*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR) < 0) {
+			return 0;
+		}
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+int jas_stream_rewind(jas_stream_t *stream)
+{
+	return jas_stream_seek(stream, 0, SEEK_SET);
+}
+
+long jas_stream_seek(jas_stream_t *stream, long offset, int origin)
+{
+	long newpos;
+
+	/* The buffer cannot be in use for both reading and writing. */
+	assert(!((stream->bufmode_ & JAS_STREAM_RDBUF) && (stream->bufmode_ &
+	  JAS_STREAM_WRBUF)));
+
+	/* Reset the EOF indicator (since we may not be at the EOF anymore). */
+	stream->flags_ &= ~JAS_STREAM_EOF;
+
+	if (stream->bufmode_ & JAS_STREAM_RDBUF) {
+		if (origin == SEEK_CUR) {
+			offset -= stream->cnt_;
+		}
+	} else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
+		if (jas_stream_flush(stream)) {
+			return -1;
+		}
+	}
+	stream->cnt_ = 0;
+	stream->ptr_ = stream->bufstart_;
+	stream->bufmode_ &= ~(JAS_STREAM_RDBUF | JAS_STREAM_WRBUF);
+
+	if ((newpos = (*stream->ops_->seek_)(stream->obj_, offset, origin))
+	  < 0) {
+		return -1;
+	}
+
+	return newpos;
+}
+
+long jas_stream_tell(jas_stream_t *stream)
+{
+	int adjust;
+	int offset;
+
+	if (stream->bufmode_ & JAS_STREAM_RDBUF) {
+		adjust = -stream->cnt_;
+	} else if (stream->bufmode_ & JAS_STREAM_WRBUF) {
+		adjust = stream->ptr_ - stream->bufstart_;
+	} else {
+		adjust = 0;
+	}
+
+	if ((offset = (*stream->ops_->seek_)(stream->obj_, 0, SEEK_CUR)) < 0) {
+		return -1;
+	}
+
+	return offset + adjust;
+}
+
+/******************************************************************************\
+* Buffer initialization code.
+\******************************************************************************/
+
+static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
+  int bufsize)
+{
+	/* If this function is being called, the buffer should not have been
+	  initialized yet. */
+	assert(!stream->bufbase_);
+
+	if (bufmode != JAS_STREAM_UNBUF) {
+		/* The full- or line-buffered mode is being employed. */
+		if (!buf) {
+			/* The caller has not specified a buffer to employ, so allocate
+			  one. */
+			if ((stream->bufbase_ = jas_malloc(JAS_STREAM_BUFSIZE +
+			  JAS_STREAM_MAXPUTBACK))) {
+				stream->bufmode_ |= JAS_STREAM_FREEBUF;
+				stream->bufsize_ = JAS_STREAM_BUFSIZE;
+			} else {
+				/* The buffer allocation has failed.  Resort to unbuffered
+				  operation. */
+				stream->bufbase_ = stream->tinybuf_;
+				stream->bufsize_ = 1;
+			}
+		} else {
+			/* The caller has specified a buffer to employ. */
+			/* The buffer must be large enough to accommodate maximum
+			  putback. */
+			assert(bufsize > JAS_STREAM_MAXPUTBACK);
+			stream->bufbase_ = JAS_CAST(unsigned char *, buf);
+			stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
+		}
+	} else {
+		/* The unbuffered mode is being employed. */
+		/* A buffer should not have been supplied by the caller. */
+		assert(!buf);
+		/* Use a trivial one-character buffer. */
+		stream->bufbase_ = stream->tinybuf_;
+		stream->bufsize_ = 1;
+	}
+	stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
+	stream->ptr_ = stream->bufstart_;
+	stream->cnt_ = 0;
+	stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
+}
+
+/******************************************************************************\
+* Buffer filling and flushing code.
+\******************************************************************************/
+
+int jas_stream_flush(jas_stream_t *stream)
+{
+	if (stream->bufmode_ & JAS_STREAM_RDBUF) {
+		return 0;
+	}
+	return jas_stream_flushbuf(stream, EOF);
+}
+
+int jas_stream_fillbuf(jas_stream_t *stream, int getflag)
+{
+	int c;
+
+	/* The stream must not be in an error or EOF state. */
+	if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
+		return EOF;
+	}
+
+	/* The stream must be open for reading. */
+	if ((stream->openmode_ & JAS_STREAM_READ) == 0) {
+		return EOF;
+	}
+
+	/* Make a half-hearted attempt to confirm that the buffer is not
+	currently being used for writing.  This check is not intended
+	to be foolproof! */
+	assert((stream->bufmode_ & JAS_STREAM_WRBUF) == 0);
+
+	assert(stream->ptr_ - stream->bufstart_ <= stream->bufsize_);
+
+	/* Mark the buffer as being used for reading. */
+	stream->bufmode_ |= JAS_STREAM_RDBUF;
+
+	/* Read new data into the buffer. */
+	stream->ptr_ = stream->bufstart_;
+	if ((stream->cnt_ = (*stream->ops_->read_)(stream->obj_,
+	  (char *) stream->bufstart_, stream->bufsize_)) <= 0) {
+		if (stream->cnt_ < 0) {
+			stream->flags_ |= JAS_STREAM_ERR;
+		} else {
+			stream->flags_ |= JAS_STREAM_EOF;
+		}
+		stream->cnt_ = 0;
+		return EOF;
+	}
+
+	assert(stream->cnt_ > 0);
+	/* Get or peek at the first character in the buffer. */
+	c = (getflag) ? jas_stream_getc2(stream) : (*stream->ptr_);
+
+	return c;
+}
+
+int jas_stream_flushbuf(jas_stream_t *stream, int c)
+{
+	int len;
+	int n;
+
+	/* The stream should not be in an error or EOF state. */
+	if ((stream->flags_ & (JAS_STREAM_ERRMASK)) != 0) {
+		return EOF;
+	}
+
+	/* The stream must be open for writing. */
+	if ((stream->openmode_ & (JAS_STREAM_WRITE | JAS_STREAM_APPEND)) == 0) {
+		return EOF;
+	}
+
+	/* The buffer should not currently be in use for reading. */
+	assert(!(stream->bufmode_ & JAS_STREAM_RDBUF));
+
+	/* Note: Do not use the quantity stream->cnt to determine the number
+	of characters in the buffer!  Depending on how this function was
+	called, the stream->cnt value may be "off-by-one". */
+	len = stream->ptr_ - stream->bufstart_;
+	if (len > 0) {
+		n = (*stream->ops_->write_)(stream->obj_, (char *)
+		  stream->bufstart_, len);
+		if (n != len) {
+			stream->flags_ |= JAS_STREAM_ERR;
+			return EOF;
+		}
+	}
+	stream->cnt_ = stream->bufsize_;
+	stream->ptr_ = stream->bufstart_;
+
+	stream->bufmode_ |= JAS_STREAM_WRBUF;
+
+	if (c != EOF) {
+		assert(stream->cnt_ > 0);
+		jas_stream_putc2(stream, c);
+	}
+
+	return 0;
+}
+
+/******************************************************************************\
+* Miscellaneous code.
+\******************************************************************************/
+
+static int jas_strtoopenmode(const char *s)
+{
+	int openmode = 0;
+	while (*s != '\0') {
+		switch (*s) {
+		case 'r':
+			openmode |= JAS_STREAM_READ;
+			break;
+		case 'w':
+			openmode |= JAS_STREAM_WRITE | JAS_STREAM_CREATE;
+			break;
+		case 'b':
+			openmode |= JAS_STREAM_BINARY;
+			break;
+		case 'a':
+			openmode |= JAS_STREAM_APPEND;
+			break;
+		case '+':
+			openmode |= JAS_STREAM_READ | JAS_STREAM_WRITE;
+			break;
+		default:
+			break;
+		}
+		++s;
+	}
+	return openmode;
+}
+
+int jas_stream_copy(jas_stream_t *out, jas_stream_t *in, int n)
+{
+	int all;
+	int c;
+	int m;
+
+	all = (n < 0) ? 1 : 0;
+
+	m = 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
+			  (not including EOF) or if an explicit copy count
+			  was specified. */
+			return (!all || jas_stream_error(in)) ? (-1) : 0;
+		}
+		if (jas_stream_putc_macro(out, c) == EOF) {
+			return -1;
+		}
+		--m;
+	}
+	return 0;
+}
+
+long jas_stream_setrwcount(jas_stream_t *stream, long rwcnt)
+{
+	int old;
+
+	old = stream->rwcnt_;
+	stream->rwcnt_ = rwcnt;
+	return old;
+}
+
+int jas_stream_display(jas_stream_t *stream, FILE *fp, int n)
+{
+	unsigned char buf[16];
+	int i;
+	int j;
+	int m;
+	int c;
+	int display;
+	int cnt;
+
+	cnt = n - (n % 16);
+	display = 1;
+
+	for (i = 0; i < n; i += 16) {
+		if (n > 16 && i > 0) {
+			display = (i >= cnt) ? 1 : 0;
+		}
+		if (display) {
+			fprintf(fp, "%08x:", i);
+		}
+		m = JAS_MIN(n - i, 16);
+		for (j = 0; j < m; ++j) {
+			if ((c = jas_stream_getc(stream)) == EOF) {
+				abort();
+				return -1;
+			}
+			buf[j] = c;
+		}
+		if (display) {
+			for (j = 0; j < m; ++j) {
+				fprintf(fp, " %02x", buf[j]);
+			}
+			fputc(' ', fp);
+			for (; j < 16; ++j) {
+				fprintf(fp, "   ");
+			}
+			for (j = 0; j < m; ++j) {
+				if (isprint(buf[j])) {
+					fputc(buf[j], fp);
+				} else {
+					fputc(' ', fp);
+				}
+			}
+			fprintf(fp, "\n");
+		}
+
+
+	}
+	return 0;
+}
+
+long jas_stream_length(jas_stream_t *stream)
+{
+	long oldpos;
+	long pos;
+	if ((oldpos = jas_stream_tell(stream)) < 0) {
+		return -1;
+	}
+	if (jas_stream_seek(stream, 0, SEEK_END) < 0) {
+		return -1;
+	}
+	if ((pos = jas_stream_tell(stream)) < 0) {
+		return -1;
+	}
+	if (jas_stream_seek(stream, oldpos, SEEK_SET) < 0) {
+		return -1;
+	}
+	return pos;
+}
+
+/******************************************************************************\
+* Memory stream object.
+\******************************************************************************/
+
+static int mem_read(jas_stream_obj_t *obj, char *buf, int cnt)
+{
+	int n;
+	jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
+	n = m->len_ - m->pos_;
+	cnt = JAS_MIN(n, cnt);
+	memcpy(buf, &m->buf_[m->pos_], cnt);
+	m->pos_ += cnt;
+	return cnt;
+}
+
+static int mem_resize(jas_stream_memobj_t *m, int bufsize)
+{
+	unsigned char *buf;
+
+	assert(m->buf_);
+	if (!(buf = jas_realloc(m->buf_, bufsize * sizeof(unsigned char)))) {
+		return -1;
+	}
+	m->buf_ = buf;
+	m->bufsize_ = bufsize;
+	return 0;
+}
+
+static int mem_write(jas_stream_obj_t *obj, char *buf, int cnt)
+{
+	int n;
+	int ret;
+	jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
+	long newbufsize;
+	long newpos;
+
+	newpos = m->pos_ + cnt;
+	if (newpos > m->bufsize_ && m->growable_) {
+		newbufsize = m->bufsize_;
+		while (newbufsize < newpos) {
+			newbufsize <<= 1;
+			assert(newbufsize >= 0);
+		}
+		if (mem_resize(m, newbufsize)) {
+			return -1;
+		}
+	}
+	if (m->pos_ > m->len_) {
+		/* The current position is beyond the end of the file, so
+		  pad the file to the current position with zeros. */
+		n = JAS_MIN(m->pos_, m->bufsize_) - m->len_;
+		if (n > 0) {
+			memset(&m->buf_[m->len_], 0, n);
+			m->len_ += n;
+		}
+		if (m->pos_ != m->len_) {
+			/* The buffer is not big enough. */
+			return 0;
+		}
+	}
+	n = m->bufsize_ - m->pos_;
+	ret = JAS_MIN(n, cnt);
+	if (ret > 0) {
+		memcpy(&m->buf_[m->pos_], buf, ret);
+		m->pos_ += ret;
+	}
+	if (m->pos_ > m->len_) {
+		m->len_ = m->pos_;
+	}
+assert(ret == cnt);
+	return ret;
+}
+
+static long mem_seek(jas_stream_obj_t *obj, long offset, int origin)
+{
+	jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
+	long newpos;
+
+	switch (origin) {
+	case SEEK_SET:
+		newpos = offset;
+		break;
+	case SEEK_END:
+		newpos = m->len_ - offset;
+		break;
+	case SEEK_CUR:
+		newpos = m->pos_ + offset;
+		break;
+	default:
+		abort();
+		break;
+	}
+	if (newpos < 0) {
+		return -1;
+	}
+	m->pos_ = newpos;
+
+	return m->pos_;
+}
+
+static int mem_close(jas_stream_obj_t *obj)
+{
+	jas_stream_memobj_t *m = (jas_stream_memobj_t *)obj;
+	if (m->myalloc_ && m->buf_) {
+		jas_free(m->buf_);
+		m->buf_ = 0;
+	}
+	jas_free(obj);
+	return 0;
+}
+
+/******************************************************************************\
+* File stream object.
+\******************************************************************************/
+
+static int file_read(jas_stream_obj_t *obj, char *buf, int cnt)
+{
+	int fd;
+	fd = *((int *)obj);
+	return read(fd, buf, cnt);
+}
+
+static int file_write(jas_stream_obj_t *obj, char *buf, int cnt)
+{
+	int fd;
+	fd = *((int *)obj);
+	return write(fd, buf, cnt);
+}
+
+static long file_seek(jas_stream_obj_t *obj, long offset, int origin)
+{
+	int fd;
+	fd = *((int *)obj);
+	return lseek(fd, offset, origin);
+}
+
+static int file_close(jas_stream_obj_t *obj)
+{
+	int fd;
+	fd = *((int *)obj);
+	jas_free(obj);
+	return close(fd);
+}
+
+/******************************************************************************\
+* Stdio file stream object.
+\******************************************************************************/
+
+static int sfile_read(jas_stream_obj_t *obj, char *buf, int cnt)
+{
+	FILE *fp;
+	fp = JAS_CAST(FILE *, obj);
+	return fread(buf, 1, cnt, fp);
+}
+
+static int sfile_write(jas_stream_obj_t *obj, char *buf, int cnt)
+{
+	FILE *fp;
+	fp = JAS_CAST(FILE *, obj);
+	return fwrite(buf, 1, cnt, fp);
+}
+
+static long sfile_seek(jas_stream_obj_t *obj, long offset, int origin)
+{
+	FILE *fp;
+	fp = JAS_CAST(FILE *, obj);
+	return fseek(fp, offset, origin);
+}
+
+static int sfile_close(jas_stream_obj_t *obj)
+{
+	FILE *fp;
+	fp = JAS_CAST(FILE *, obj);
+	return fclose(fp);
+}
diff --git a/converter/other/jpeg2000/libjasper/base/jas_string.c b/converter/other/jpeg2000/libjasper/base/jas_string.c
new file mode 100644
index 00000000..945731a1
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/jas_string.c
@@ -0,0 +1,145 @@
+/*
+ * 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__
+ */
+
+/*
+ * String Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes
+\******************************************************************************/
+
+#include <string.h>
+
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_string.h"
+
+/******************************************************************************\
+* Miscellaneous Functions
+\******************************************************************************/
+
+/* This function is equivalent to the popular but non-standard (and
+  not-always-available) strdup function. */
+
+char *jas_strdup(const char *s)
+{
+	int n;
+	char *p;
+	n = strlen(s) + 1;
+	if (!(p = jas_malloc(n * sizeof(char)))) {
+		return 0;
+	}
+	strcpy(p, s);
+	return p;
+}
diff --git a/converter/other/jpeg2000/libjasper/base/jas_tvp.c b/converter/other/jpeg2000/libjasper/base/jas_tvp.c
new file mode 100644
index 00000000..aab12703
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/jas_tvp.c
@@ -0,0 +1,286 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tag-Value Parser Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <assert.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_string.h"
+#include "jasper/jas_tvp.h"
+
+/******************************************************************************\
+* Macros.
+\******************************************************************************/
+
+/* Is the specified character valid for a tag name? */
+#define	JAS_TVP_ISTAG(x) \
+	(isalpha(x) || (x) == '_' || isdigit(x))
+
+/******************************************************************************\
+* Code for creating and destroying a tag-value parser.
+\******************************************************************************/
+
+jas_tvparser_t *jas_tvparser_create(const char *s)
+{
+	jas_tvparser_t *tvp;
+	if (!(tvp = jas_malloc(sizeof(jas_tvparser_t)))) {
+		return 0;
+	}
+	if (!(tvp->buf = jas_strdup(s))) {
+		jas_tvparser_destroy(tvp);
+		return 0;
+	}
+	tvp->pos = tvp->buf;
+	tvp->tag = 0;
+	tvp->val = 0;
+	return tvp;
+}
+
+void jas_tvparser_destroy(jas_tvparser_t *tvp)
+{
+	if (tvp->buf) {
+		jas_free(tvp->buf);
+	}
+	jas_free(tvp);
+}
+
+/******************************************************************************\
+* Main parsing code.
+\******************************************************************************/
+
+/* Get the next tag-value pair. */
+int jas_tvparser_next(jas_tvparser_t *tvp)
+{
+	char *p;
+	char *tag;
+	const char *val;
+
+	/* Skip any leading whitespace. */
+	p = tvp->pos;
+	while (*p != '\0' && isspace(*p)) {
+		++p;
+	}
+
+	/* Has the end of the input data been reached? */
+	if (*p == '\0') {
+		/* No more tags are present. */
+		tvp->pos = p;
+		return 1;
+	}
+
+	/* Does the tag name begin with a valid character? */
+	if (!JAS_TVP_ISTAG(*p)) {
+		return -1;
+	}
+
+	/* Remember where the tag name begins. */
+	tag = p;
+
+	/* Find the end of the tag name. */
+	while (*p != '\0' && JAS_TVP_ISTAG(*p)) {
+		++p;
+	}
+
+	/* Has the end of the input data been reached? */
+	if (*p == '\0') {
+		/* The value field is empty. */
+		tvp->tag = tag;
+		tvp->val = "";
+		tvp->pos = p;
+		return 0;
+	}
+
+	/* Is a value field not present? */
+	if (*p != '=') {
+		if (*p != '\0' && !isspace(*p)) {
+			return -1;
+		}
+		*p++ = '\0';
+		tvp->tag = tag;
+		tvp->val = "";
+		tvp->pos = p;
+		return 0;
+	}
+
+	*p++ = '\0';
+
+	val = p;
+	while (*p != '\0' && !isspace(*p)) {
+		++p;
+	}
+
+	if (*p != '\0') {
+		*p++ = '\0';
+	}
+
+	tvp->pos = p;
+	tvp->tag = tag;
+	tvp->val = val;
+
+	return 0;
+}
+
+/******************************************************************************\
+* Code for querying the current tag/value.
+\******************************************************************************/
+
+/* Get the current tag. */
+char *jas_tvparser_gettag(jas_tvparser_t *tvp)
+{
+	return tvp->tag;
+}
+
+/* Get the current value. */
+const char *jas_tvparser_getval(jas_tvparser_t *tvp)
+{
+	return tvp->val;
+}
+
+/******************************************************************************\
+* Miscellaneous code.
+\******************************************************************************/
+
+/* Lookup a tag by name. */
+jas_taginfo_t *jas_taginfos_lookup(jas_taginfo_t *taginfos, const char *name)
+{
+	jas_taginfo_t *taginfo;
+	taginfo = taginfos;
+	while (taginfo->id >= 0) {
+		if (!strcmp(taginfo->name, name)) {
+			return taginfo;
+		}
+		++taginfo;
+	}
+	return 0;
+}
+
+/* This function is simply for convenience. */
+/* One can avoid testing for the special case of a null pointer, by
+  using this function.   This function never returns a null pointer.  */
+jas_taginfo_t *jas_taginfo_nonull(jas_taginfo_t *taginfo)
+{
+	static jas_taginfo_t invalidtaginfo = {
+		-1, 0
+	};
+	
+	return taginfo ? taginfo : &invalidtaginfo;
+}
diff --git a/converter/other/jpeg2000/libjasper/base/jas_version.c b/converter/other/jpeg2000/libjasper/base/jas_version.c
new file mode 100644
index 00000000..5608c4d4
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/jas_version.c
@@ -0,0 +1,116 @@
+/*
+ * 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__
+ */
+
+#include "jasper/jas_version.h"
+
+const char *jas_getversion()
+{
+	return JAS_VERSION;
+}
diff --git a/converter/other/jpeg2000/libjasper/base/partlist b/converter/other/jpeg2000/libjasper/base/partlist
new file mode 100644
index 00000000..cd244275
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/base/partlist
@@ -0,0 +1 @@
+/mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_debug.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_getopt.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_image.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_init.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_malloc.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_seq.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_stream.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_string.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_tvp.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_version.o
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_debug.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_debug.h
new file mode 100644
index 00000000..6c597c59
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_debug.h
@@ -0,0 +1,161 @@
+/*
+ * 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__
+ */
+
+/*
+ * Debugging-Related Code
+ *
+ * $Id$
+ */
+
+#ifndef JAS_DEBUG_H
+#define JAS_DEBUG_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+
+#include "jasper/jas_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Macros and functions.
+\******************************************************************************/
+
+/* Output debugging information to standard error provided that the debug
+  level is set sufficiently high. */
+#if defined(DEBUG)
+#define	JAS_DBGLOG(n, x) \
+	((jas_getdbglevel() >= (n)) ? (jas_eprintf x) : 0)
+#else
+#define	JAS_DBGLOG(n, x)
+#endif
+
+/* Get the library debug level. */
+int jas_getdbglevel(void);
+
+/* Set the library debug level. */
+int jas_setdbglevel(int dbglevel);
+
+/* Perform formatted output to standard error. */
+int jas_eprintf(const char *fmt, ...);
+
+/* Dump memory to a stream. */
+int jas_memdump(FILE *out, void *data, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_fix.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_fix.h
new file mode 100644
index 00000000..9599eb1c
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_fix.h
@@ -0,0 +1,406 @@
+/*
+ * 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__
+ */
+
+/*
+ * Fixed-Point Number Class
+ *
+ * $Id$
+ */
+
+#ifndef JAS_FIX_H
+#define JAS_FIX_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <jasper/jas_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/* The representation of the value zero. */
+#define	JAS_FIX_ZERO(fix_t, fracbits) \
+	JAS_CAST(fix_t, 0)
+
+/* The representation of the value one. */
+#define	JAS_FIX_ONE(fix_t, fracbits) \
+	(JAS_CAST(fix_t, 1) << (fracbits))
+
+/* The representation of the value one half. */
+#define	JAS_FIX_HALF(fix_t, fracbits) \
+	(JAS_CAST(fix_t, 1) << ((fracbits) - 1))
+
+/******************************************************************************\
+* Conversion operations.
+\******************************************************************************/
+
+/* Convert an int to a fixed-point number. */
+#define JAS_INTTOFIX(fix_t, fracbits, x) \
+	JAS_CAST(fix_t, (x) << (fracbits))
+
+/* Convert a fixed-point number to an int. */
+#define JAS_FIXTOINT(fix_t, fracbits, x) \
+	JAS_CAST(int, (x) >> (fracbits))
+
+/* Convert a fixed-point number to a double. */
+#define JAS_FIXTODBL(fix_t, fracbits, x) \
+	(JAS_CAST(double, x) / (JAS_CAST(fix_t, 1) << (fracbits)))
+
+/* Convert a double to a fixed-point number. */
+#define JAS_DBLTOFIX(fix_t, fracbits, x) \
+	JAS_CAST(fix_t, ((x) * JAS_CAST(double, JAS_CAST(fix_t, 1) << (fracbits))))
+
+/******************************************************************************\
+* Basic arithmetic operations.
+* All other arithmetic operations are synthesized from these basic operations.
+* There are three macros for each type of arithmetic operation.
+* One macro always performs overflow/underflow checking, one never performs
+* overflow/underflow checking, and one is generic with its behavior
+* depending on compile-time flags.
+* Only the generic macros should be invoked directly by application code.
+\******************************************************************************/
+
+/* Calculate the sum of two fixed-point numbers. */
+#if !defined(DEBUG_OVERFLOW)
+#define JAS_FIX_ADD			JAS_FIX_ADD_FAST
+#else
+#define JAS_FIX_ADD			JAS_FIX_ADD_OFLOW
+#endif
+
+/* Calculate the sum of two fixed-point numbers without overflow checking. */
+#define	JAS_FIX_ADD_FAST(fix_t, fracbits, x, y)	((x) + (y))
+
+/* Calculate the sum of two fixed-point numbers with overflow checking. */
+#define	JAS_FIX_ADD_OFLOW(fix_t, fracbits, x, y) \
+	((x) >= 0) ? \
+	  (((y) >= 0) ? ((x) + (y) >= 0 || JAS_FIX_OFLOW(), (x) + (y)) : \
+	  ((x) + (y))) : \
+	  (((y) >= 0) ? ((x) + (y)) : ((x) + (y) < 0 || JAS_FIX_OFLOW(), \
+	  (x) + (y)))
+
+/* Calculate the product of two fixed-point numbers. */
+#if !defined(DEBUG_OVERFLOW)
+#define JAS_FIX_MUL			JAS_FIX_MUL_FAST
+#else
+#define JAS_FIX_MUL			JAS_FIX_MUL_OFLOW
+#endif
+
+/* Calculate the product of two fixed-point numbers without overflow
+  checking. */
+#define	JAS_FIX_MUL_FAST(fix_t, fracbits, bigfix_t, x, y) \
+	JAS_CAST(fix_t, (JAS_CAST(bigfix_t, x) * JAS_CAST(bigfix_t, y)) >> \
+	  (fracbits))
+
+/* Calculate the product of two fixed-point numbers with overflow
+  checking. */
+#define JAS_FIX_MUL_OFLOW(fix_t, fracbits, bigfix_t, x, y) \
+	((JAS_CAST(bigfix_t, x) * JAS_CAST(bigfix_t, y) >> (fracbits)) == \
+	  JAS_CAST(fix_t, (JAS_CAST(bigfix_t, x) * JAS_CAST(bigfix_t, y) >> \
+	  (fracbits))) ? \
+	  JAS_CAST(fix_t, (JAS_CAST(bigfix_t, x) * JAS_CAST(bigfix_t, y) >> \
+	  (fracbits))) : JAS_FIX_OFLOW())
+
+/* Calculate the product of a fixed-point number and an int. */
+#if !defined(DEBUG_OVERFLOW)
+#define	JAS_FIX_MULBYINT	JAS_FIX_MULBYINT_FAST
+#else
+#define	JAS_FIX_MULBYINT	JAS_FIX_MULBYINT_OFLOW
+#endif
+
+/* Calculate the product of a fixed-point number and an int without overflow
+  checking. */
+#define	JAS_FIX_MULBYINT_FAST(fix_t, fracbits, x, y) \
+	JAS_CAST(fix_t, ((x) * (y)))
+
+/* Calculate the product of a fixed-point number and an int with overflow
+  checking. */
+#define	JAS_FIX_MULBYINT_OFLOW(fix_t, fracbits, x, y) \
+	JAS_FIX_MULBYINT_FAST(fix_t, fracbits, x, y)
+
+/* Calculate the quotient of two fixed-point numbers. */
+#if !defined(DEBUG_OVERFLOW)
+#define JAS_FIX_DIV			JAS_FIX_DIV_FAST
+#else
+#define JAS_FIX_DIV			JAS_FIX_DIV_UFLOW
+#endif
+
+/* Calculate the quotient of two fixed-point numbers without underflow
+  checking. */
+#define	JAS_FIX_DIV_FAST(fix_t, fracbits, bigfix_t, x, y) \
+	JAS_CAST(fix_t, (JAS_CAST(bigfix_t, x) << (fracbits)) / (y))
+
+/* Calculate the quotient of two fixed-point numbers with underflow
+  checking. */
+#define JAS_FIX_DIV_UFLOW(fix_t, fracbits, bigfix_t, x, y) \
+	JAS_FIX_DIV_FAST(fix_t, fracbits, bigfix_t, x, y)
+
+/* Negate a fixed-point number. */
+#if !defined(DEBUG_OVERFLOW)
+#define	JAS_FIX_NEG			JAS_FIX_NEG_FAST
+#else
+#define	JAS_FIX_NEG			JAS_FIX_NEG_OFLOW
+#endif
+
+/* Negate a fixed-point number without overflow checking. */
+#define	JAS_FIX_NEG_FAST(fix_t, fracbits, x) \
+	(-(x))
+
+/* Negate a fixed-point number with overflow checking. */
+/* Yes, overflow is actually possible for two's complement representations,
+  although highly unlikely to occur. */
+#define	JAS_FIX_NEG_OFLOW(fix_t, fracbits, x) \
+	(((x) < 0) ? (-(x) > 0 || JAS_FIX_OFLOW(), -(x)) : (-(x)))
+
+/* Perform an arithmetic shift left of a fixed-point number. */
+#if !defined(DEBUG_OVERFLOW)
+#define	JAS_FIX_ASL			JAS_FIX_ASL_FAST
+#else
+#define	JAS_FIX_ASL			JAS_FIX_ASL_OFLOW
+#endif
+
+/* Perform an arithmetic shift left of a fixed-point number without overflow
+  checking. */
+#define	JAS_FIX_ASL_FAST(fix_t, fracbits, x, n) \
+	((x) << (n))
+
+/* Perform an arithmetic shift left of a fixed-point number with overflow
+  checking. */
+#define	JAS_FIX_ASL_OFLOW(fix_t, fracbits, x, n) \
+	((((x) << (n)) >> (n)) == (x) || JAS_FIX_OFLOW(), (x) << (n))
+
+/* Perform an arithmetic shift right of a fixed-point number. */
+#if !defined(DEBUG_OVERFLOW)
+#define	JAS_FIX_ASR			JAS_FIX_ASR_FAST
+#else
+#define	JAS_FIX_ASR			JAS_FIX_ASR_UFLOW
+#endif
+
+/* Perform an arithmetic shift right of a fixed-point number without underflow
+  checking. */
+#define	JAS_FIX_ASR_FAST(fix_t, fracbits, x, n) \
+	((x) >> (n))
+
+/* Perform an arithmetic shift right of a fixed-point number with underflow
+  checking. */
+#define	JAS_FIX_ASR_UFLOW(fix_t, fracbits, x, n) \
+	JAS_FIX_ASR_FAST(fix_t, fracbits, x, n)
+
+/******************************************************************************\
+* Other basic arithmetic operations.
+\******************************************************************************/
+
+/* Calculate the difference between two fixed-point numbers. */
+#define JAS_FIX_SUB(fix_t, fracbits, x, y) \
+	JAS_FIX_ADD(fix_t, fracbits, x, JAS_FIX_NEG(fix_t, fracbits, y))
+
+/* Add one fixed-point number to another. */
+#define JAS_FIX_PLUSEQ(fix_t, fracbits, x, y) \
+	((x) = JAS_FIX_ADD(fix_t, fracbits, x, y))
+
+/* Subtract one fixed-point number from another. */
+#define JAS_FIX_MINUSEQ(fix_t, fracbits, x, y) \
+	((x) = JAS_FIX_SUB(fix_t, fracbits, x, y))
+
+/* Multiply one fixed-point number by another. */
+#define	JAS_FIX_MULEQ(fix_t, fracbits, bigfix_t, x, y) \
+	((x) = JAS_FIX_MUL(fix_t, fracbits, bigfix_t, x, y))
+
+/******************************************************************************\
+* Miscellaneous operations.
+\******************************************************************************/
+
+/* Calculate the absolute value of a fixed-point number. */
+#define	JAS_FIX_ABS(fix_t, fracbits, x) \
+	(((x) >= 0) ? (x) : (JAS_FIX_NEG(fix_t, fracbits, x)))
+
+/* Is a fixed-point number an integer? */
+#define	JAS_FIX_ISINT(fix_t, fracbits, x) \
+	(JAS_FIX_FLOOR(fix_t, fracbits, x) == (x))
+
+/* Get the sign of a fixed-point number. */
+#define JAS_FIX_SGN(fix_t, fracbits, x) \
+	((x) >= 0 ? 1 : (-1))
+
+/******************************************************************************\
+* Relational operations.
+\******************************************************************************/
+
+/* Compare two fixed-point numbers. */
+#define JAS_FIX_CMP(fix_t, fracbits, x, y) \
+	((x) > (y) ? 1 : (((x) == (y)) ? 0 : (-1)))
+
+/* Less than. */
+#define	JAS_FIX_LT(fix_t, fracbits, x, y) \
+	((x) < (y))
+
+/* Less than or equal. */
+#define	JAS_FIX_LTE(fix_t, fracbits, x, y) \
+	((x) <= (y))
+
+/* Greater than. */
+#define	JAS_FIX_GT(fix_t, fracbits, x, y) \
+	((x) > (y))
+
+/* Greater than or equal. */
+#define	JAS_FIX_GTE(fix_t, fracbits, x, y) \
+	((x) >= (y))
+
+/******************************************************************************\
+* Rounding functions.
+\******************************************************************************/
+
+/* Round a fixed-point number to the nearest integer. */
+#define	JAS_FIX_ROUND(fix_t, fracbits, x) \
+	(((x) < 0) ? JAS_FIX_FLOOR(fix_t, fracbits, JAS_FIX_ADD(fix_t, fracbits, \
+	  (x), JAS_FIX_HALF(fix_t, fracbits))) : \
+	  JAS_FIX_NEG(fix_t, fracbits, JAS_FIX_FLOOR(fix_t, fracbits, \
+	  JAS_FIX_ADD(fix_t, fracbits, (-(x)), JAS_FIX_HALF(fix_t, fracbits)))))
+
+/* Round a fixed-point number to the nearest integer in the direction of
+  negative infinity (i.e., the floor function). */
+#define	JAS_FIX_FLOOR(fix_t, fracbits, x) \
+	((x) & (~((JAS_CAST(fix_t, 1) << (fracbits)) - 1)))
+
+/* Round a fixed-point number to the nearest integer in the direction
+  of zero. */
+#define JAS_FIX_TRUNC(fix_t, fracbits, x) \
+	(((x) >= 0) ? JAS_FIX_FLOOR(fix_t, fracbits, x) : \
+	  JAS_FIX_CEIL(fix_t, fracbits, x))
+
+/******************************************************************************\
+* The below macros are for internal library use only.  Do not invoke them
+* directly in application code.
+\******************************************************************************/
+
+/* Handle overflow. */
+#define	JAS_FIX_OFLOW() \
+	fprintf(stderr, "overflow error: file %s, line %d\n", __FILE__, __LINE__)
+
+/* Handle underflow. */
+#define	JAS_FIX_UFLOW() \
+	fprintf(stderr, "underflow error: file %s, line %d\n", __FILE__, __LINE__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_getopt.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_getopt.h
new file mode 100644
index 00000000..4f272dc9
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_getopt.h
@@ -0,0 +1,178 @@
+/*
+ * 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__
+ */
+
+/*
+ * Command Line Option Parsing Code
+ *
+ * $Id$
+ */
+
+#ifndef JAS_GETOPT_H
+#define JAS_GETOPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+#define	JAS_GETOPT_EOF	(-1)
+#define	JAS_GETOPT_ERR	'?'
+
+/* option flags. */
+#define	JAS_OPT_HASARG	0x01	/* option has argument */
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/* Command line option type. */
+typedef struct {
+
+	int id;
+	/* The unique identifier for this option. */
+
+	char *name;
+	/* The name of this option. */
+
+	int flags;
+	/* option flags. */
+
+} jas_opt_t;
+
+/******************************************************************************\
+* External data.
+\******************************************************************************/
+
+/* The current option index. */
+extern int jas_optind;
+
+/* The current option argument. */
+extern char *jas_optarg;
+
+/* The debug level. */
+extern int jas_opterr;
+
+/******************************************************************************\
+* Prototypes.
+\******************************************************************************/
+
+/* Get the next option. */
+int jas_getopt(int argc, char **argv, jas_opt_t *opts);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
new file mode 100644
index 00000000..d6456f7c
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_image.h
@@ -0,0 +1,593 @@
+/*
+ * 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__
+ */
+
+/*
+ * Image Class
+ *
+ * $Id$
+ */
+
+#ifndef JAS_IMAGE_H
+#define JAS_IMAGE_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "pm_c_util.h"
+#include <jasper/jas_stream.h>
+#include <jasper/jas_seq.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/*
+ * Miscellaneous constants.
+ */
+
+/* The threshold at which image data is no longer stored in memory. */
+#define JAS_IMAGE_INMEMTHRESH	(16 * 1024 * 1024)
+
+/*
+ * Color models.
+ */
+
+#define JAS_IMAGE_CS_UNKNOWN	0	/* Unknown */
+#define	JAS_IMAGE_CS_GRAY	1	/* Standard Gray */
+#define	JAS_IMAGE_CS_RGB	2	/* Standard RGB */
+#define	JAS_IMAGE_CS_YCBCR	3	/* Standard YCC */
+#if 0
+#define	JAS_IMAGE_CM_ICC	4	/* ICC Profile */
+#endif
+/*
+ * Component types
+ */
+
+#define	JAS_IMAGE_CT_UNKNOWN	0x10000
+#define	JAS_IMAGE_CT_COLOR(n)	((n) & 0x7fff)
+#define	JAS_IMAGE_CT_OPACITY	0x08000
+
+#define	JAS_IMAGE_CT_RGB_R	0
+#define	JAS_IMAGE_CT_RGB_G	1
+#define	JAS_IMAGE_CT_RGB_B	2
+
+#define	JAS_IMAGE_CT_YCBCR_Y	0
+#define	JAS_IMAGE_CT_YCBCR_CB	1
+#define	JAS_IMAGE_CT_YCBCR_CR	2
+
+#define	JAS_IMAGE_CT_GRAY_Y	0
+
+/******************************************************************************\
+* Image class and supporting classes.
+\******************************************************************************/
+
+/* Image component class. */
+
+typedef struct {
+
+	uint_fast32_t tlx_;
+	/* The x-coordinate of the top-left corner of the component. */
+
+	uint_fast32_t tly_;
+	/* The y-coordinate of the top-left corner of the component. */
+
+	uint_fast32_t hstep_;
+	/* The horizontal sampling period in units of the reference grid. */
+
+	uint_fast32_t vstep_;
+	/* The vertical sampling period in units of the reference grid. */
+
+	uint_fast32_t width_;
+	/* The component width in samples. */
+
+	uint_fast32_t height_;
+	/* The component height in samples. */
+
+	uint_fast16_t prec_;
+	/* The precision of the sample data (i.e., the number of bits per
+	sample).  If the samples are signed values, this quantity
+	includes the sign bit. */
+
+	uint_fast8_t sgnd_;
+	/* The signedness of the sample data. */
+
+	jas_stream_t *stream_;
+	/* The stream containing the component data. */
+
+	int cps_;
+	/* The number of characters per sample in the stream. */
+
+	uint_fast32_t type_;
+	/* The type of component (e.g., opacity, red, green, blue, luma). */
+
+} jas_image_cmpt_t;
+
+/* Image class. */
+
+typedef struct {
+
+	uint_fast32_t tlx_;
+	/* The x-coordinate of the top-left corner of the image bounding box. */
+
+	uint_fast32_t tly_;
+	/* The y-coordinate of the top-left corner of the image bounding box. */
+
+	uint_fast32_t brx_;
+	/* The x-coordinate of the bottom-right corner of the image bounding
+	  box (plus one). */
+
+	uint_fast32_t bry_;
+	/* The y-coordinate of the bottom-right corner of the image bounding
+	  box (plus one). */
+
+	uint_fast16_t numcmpts_;
+	/* The number of components. */
+
+	uint_fast16_t maxcmpts_;
+	/* The maximum number of components that this image can have (i.e., the
+	  allocated size of the components array). */
+
+	jas_image_cmpt_t **cmpts_;
+	/* Per-component information. */
+
+	int colorspace_;
+	/* The color space used (e.g., RGB, YCbCr, gray).  This field is only
+	of particular relevance in the case of a multi-component image. */
+
+	unsigned char *iccp_;
+	/* ICC profile information. */
+
+	int iccplen_;
+
+	bool inmem_;
+
+} jas_image_t;
+
+/* Component parameters class. */
+/* This data type exists solely/mainly for the purposes of the
+  jas_image_create function. */
+
+typedef struct {
+
+	uint_fast32_t tlx;
+	/* The x-coordinate of the top-left corner of the component. */
+
+	uint_fast32_t tly;
+	/* The y-coordinate of the top-left corner of the component. */
+
+	uint_fast32_t hstep;
+	/* The horizontal sampling period in units of the reference grid. */
+
+	uint_fast32_t vstep;
+	/* The vertical sampling period in units of the reference grid. */
+
+	uint_fast32_t width;
+	/* The width of the component in samples. */
+
+	uint_fast32_t height;
+	/* The height of the component in samples. */
+
+	uint_fast16_t prec;
+	/* The precision of the component sample data. */
+
+	bool sgnd;
+	/* The signedness of the component sample data. */
+
+} jas_image_cmptparm_t;
+
+/******************************************************************************\
+* File format related classes.
+\******************************************************************************/
+
+#define	JAS_IMAGE_MAXFMTS	32
+/* The maximum number of image data formats supported. */
+
+/* Image format-dependent operations. */
+
+typedef struct {
+
+	jas_image_t *(*decode)(jas_stream_t *in, char *opts);
+	/* Decode image data from a stream. */
+
+	int (*encode)(jas_image_t *image, jas_stream_t *out, char *opts);
+	/* Encode image data to a stream. */
+
+	int (*validate)(jas_stream_t *in);
+	/* Determine if stream data is in a particular format. */
+
+} jas_image_fmtops_t;
+
+/* Image format information. */
+
+typedef struct {
+
+	int id;
+	/* The ID for this format. */
+
+	char *name;
+	/* The name by which this format is identified. */
+
+	char *ext;
+	/* The file name extension associated with this format. */
+
+	char *desc;
+	/* A brief description of the format. */
+
+	jas_image_fmtops_t ops;
+	/* The operations for this format. */
+
+} jas_image_fmtinfo_t;
+
+/******************************************************************************\
+* Image operations.
+\******************************************************************************/
+
+/* Create an image. */
+jas_image_t *jas_image_create(uint_fast16_t numcmpts,
+  jas_image_cmptparm_t *cmptparms, int colorspace);
+
+/* Create an "empty" image. */
+jas_image_t *jas_image_create0(void);
+
+/* Clone an image. */
+jas_image_t *jas_image_copy(jas_image_t *image);
+
+/* Deallocate any resources associated with an image. */
+void jas_image_destroy(jas_image_t *image);
+
+/* Get the width of the image in units of the image reference grid. */
+#define jas_image_width(image) \
+	((image)->brx_ - (image)->tlx_)
+
+/* Get the height of the image in units of the image reference grid. */
+#define	jas_image_height(image) \
+	((image)->bry_ - (image)->tly_)
+
+/* Get the x-coordinate of the top-left corner of the image bounding box
+  on the reference grid. */
+#define jas_image_tlx(image) \
+	((image)->tlx_)
+
+/* Get the y-coordinate of the top-left corner of the image bounding box
+  on the reference grid. */
+#define jas_image_tly(image) \
+	((image)->tly_)
+
+/* Get the x-coordinate of the bottom-right corner of the image bounding box
+  on the reference grid (plus one). */
+#define jas_image_brx(image) \
+	((image)->brx_)
+
+/* Get the y-coordinate of the bottom-right corner of the image bounding box
+  on the reference grid (plus one). */
+#define jas_image_bry(image) \
+	((image)->bry_)
+
+/* Get the number of image components. */
+#define	jas_image_numcmpts(image) \
+	((image)->numcmpts_)
+
+/* Get the color model used by the image. */
+#define	jas_image_colorspace(image) \
+	((image)->colorspace_)
+
+/* Set the color model for an image. */
+#define jas_image_setcolorspace(image, colorspace) \
+	((image)->colorspace_ = (colorspace))
+
+#define jas_image_cmpttype(image, cmptno) \
+	((image)->cmpts_[(cmptno)]->type_)
+#define jas_image_setcmpttype(image, cmptno, type) \
+	((image)->cmpts_[(cmptno)]->type_ = (type))
+
+/* Get the width of a component. */
+#define	jas_image_cmptwidth(image, cmptno) \
+	((image)->cmpts_[cmptno]->width_)
+
+/* Get the height of a component. */
+#define	jas_image_cmptheight(image, cmptno) \
+	((image)->cmpts_[cmptno]->height_)
+
+/* Get the signedness of the sample data for a component. */
+#define	jas_image_cmptsgnd(image, cmptno) \
+	((image)->cmpts_[cmptno]->sgnd_)
+
+/* Get the precision of the sample data for a component. */
+#define	jas_image_cmptprec(image, cmptno) \
+	((image)->cmpts_[cmptno]->prec_)
+
+/* Get the horizontal subsampling factor for a component. */
+#define	jas_image_cmpthstep(image, cmptno) \
+	((image)->cmpts_[cmptno]->hstep_)
+
+/* Get the vertical subsampling factor for a component. */
+#define	jas_image_cmptvstep(image, cmptno) \
+	((image)->cmpts_[cmptno]->vstep_)
+
+/* Get the x-coordinate of the top-left corner of a component. */
+#define	jas_image_cmpttlx(image, cmptno) \
+	((image)->cmpts_[cmptno]->tlx_)
+
+/* Get the y-coordinate of the top-left corner of a component. */
+#define	jas_image_cmpttly(image, cmptno) \
+	((image)->cmpts_[cmptno]->tly_)
+
+/* Get the x-coordinate of the bottom-right corner of a component
+  (plus "one"). */
+#define	jas_image_cmptbrx(image, cmptno) \
+	((image)->cmpts_[cmptno]->tlx_ + (image)->cmpts_[cmptno]->width_ * \
+	  (image)->cmpts_[cmptno]->hstep_)
+
+/* Get the y-coordinate of the bottom-right corner of a component
+  (plus "one"). */
+#define	jas_image_cmptbry(image, cmptno) \
+	((image)->cmpts_[cmptno]->tly_ + (image)->cmpts_[cmptno]->height_ * \
+	  (image)->cmpts_[cmptno]->vstep_)
+
+/* Get the raw size of an image (i.e., the nominal size of the image without
+  any compression. */
+uint_fast32_t jas_image_rawsize(jas_image_t *image);
+
+/* Create an image from a stream in some specified format. */
+jas_image_t *jas_image_decode(jas_stream_t *in, int fmt, char *optstr);
+
+/* Write an image to a stream in a specified format. */
+int jas_image_encode(jas_image_t *image, jas_stream_t *out, int fmt,
+  char *optstr);
+
+/* Read a rectangular region of an image component. */
+/* The position and size of the rectangular region to be read is specified
+relative to the component's coordinate system. */
+int jas_image_readcmpt(jas_image_t *image, uint_fast16_t cmptno,
+  uint_fast32_t x, uint_fast32_t y, uint_fast32_t width, uint_fast32_t height,
+  jas_matrix_t *data);
+
+/* Write a rectangular region of an image component. */
+int jas_image_writecmpt(jas_image_t *image, uint_fast16_t cmptno,
+  uint_fast32_t x, uint_fast32_t y, uint_fast32_t width, uint_fast32_t height,
+  jas_matrix_t *data);
+
+/* Delete a component from an image. */
+void jas_image_delcmpt(jas_image_t *image, uint_fast16_t cmptno);
+
+/* Add a component to an image. */
+int jas_image_addcmpt(jas_image_t *image, uint_fast16_t cmptno,
+  jas_image_cmptparm_t *cmptparm);
+
+/* Copy a component from one image to another. */
+int jas_image_copycmpt(jas_image_t *dstimage, int dstcmptno,
+  jas_image_t *srcimage, int srccmptno);
+
+#if 0
+int_fast64_t jas_image_readcmpt1(jas_image_t *image, uint_fast16_t cmptno,
+  uint_fast32_t x, uint_fast32_t y);
+#endif
+
+#define	JAS_IMAGE_CDT_GETSGND(dtype) (((dtype) >> 7) & 1)
+#define	JAS_IMAGE_CDT_SETSGND(dtype) (((dtype) & 1) << 7)
+#define	JAS_IMAGE_CDT_GETPREC(dtype) ((dtype) & 0x7f)
+#define	JAS_IMAGE_CDT_SETPREC(dtype) ((dtype) & 0x7f)
+
+#define	jas_image_cmptdtype(image, cmptno) \
+	(JAS_IMAGE_CDT_SETSGND((image)->cmpts_[cmptno]->sgnd_) | JAS_IMAGE_CDT_SETPREC((image)->cmpts_[cmptno]->prec_))
+
+void jas_image_dump(jas_image_t *image, FILE *out);
+
+int jas_image_depalettize(jas_image_t *image, int cmptno, int numlutents,
+  int_fast32_t *lutents, int dtype, int newcmptno);
+
+int jas_image_readcmptsample(jas_image_t *image, int cmptno, int x, int y);
+void jas_image_writecmptsample(jas_image_t *image, int cmptno, int x, int y,
+  int_fast32_t v);
+
+int jas_image_getcmptbytype(jas_image_t *image, int ctype);
+
+/******************************************************************************\
+* Image format-related operations.
+\******************************************************************************/
+
+/* Clear the table of image formats. */
+void jas_image_clearfmts(void);
+
+/* Add entry to table of image formats. */
+int jas_image_addfmt(int id, const char *name, const char *ext, 
+  const char *desc,
+  jas_image_fmtops_t *ops);
+
+/* Get the ID for the image format with the specified name. */
+int jas_image_strtofmt(char *s);
+
+/* Get the name of the image format with the specified ID. */
+char *jas_image_fmttostr(int fmt);
+
+/* Lookup image format information by the format ID. */
+jas_image_fmtinfo_t *jas_image_lookupfmtbyid(int id);
+
+/* Lookup image format information by the format name. */
+jas_image_fmtinfo_t *jas_image_lookupfmtbyname(const char *name);
+
+/* Guess the format of an image file based on its name. */
+int jas_image_fmtfromname(char *filename);
+
+/* Get the format of image data in a stream. */
+int jas_image_getfmt(jas_stream_t *in);
+
+/******************************************************************************\
+* Image format-dependent operations.
+\******************************************************************************/
+
+#if !defined(EXCLUDE_JPG_SUPPORT)
+/* Format-dependent operations for JPG support. */
+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. */
+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. */
+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. */
+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. */
+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. */
+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. */
+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. */
+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);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_init.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_init.h
new file mode 100644
index 00000000..4ebeaa87
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_init.h
@@ -0,0 +1,128 @@
+/*
+ * 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__
+ */
+
+#ifndef JAS_INIT_H
+#define JAS_INIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+int jas_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_malloc.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_malloc.h
new file mode 100644
index 00000000..fe5b6172
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_malloc.h
@@ -0,0 +1,171 @@
+/*
+ * 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__
+ */
+
+/*
+ * Memory Allocator
+ *
+ * $Id$
+ */
+
+#ifndef JAS_MALLOC_H
+#define JAS_MALLOC_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Hack follows...
+\******************************************************************************/
+
+#if defined(DEBUG_MEMALLOC)
+/* This is somewhat of a hack, but it's a useful hack. :-) */
+/* Use my own custom memory allocator for debugging. */
+#include "../../../../local/src/memalloc.h"
+#define jas_malloc	MEMALLOC
+#define	jas_free	MEMFREE
+#define	jas_realloc	MEMREALLOC
+#define	jas_calloc	MEMCALLOC
+#endif
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+#if !defined(DEBUG_MEMALLOC)
+
+/* Allocate memory. */
+void *jas_malloc(size_t size);
+
+/* Free memory. */
+void jas_free(void *ptr);
+
+/* Resize a block of allocated memory. */
+void *jas_realloc(void *ptr, size_t size);
+
+/* Allocate a block of memory and initialize the contents to zero. */
+void *jas_calloc(size_t nmemb, size_t size);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_math.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_math.h
new file mode 100644
index 00000000..a43051e5
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_math.h
@@ -0,0 +1,164 @@
+/*
+ * 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__
+ */
+
+/*
+ * Math-Related Code
+ *
+ * $Id$
+ */
+
+#ifndef	JAS_MATH_H
+#define	JAS_MATH_H
+
+/******************************************************************************\
+* Includes
+\******************************************************************************/
+
+#include	<assert.h>
+#include	<stdio.h>
+#include	<string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Macros
+\******************************************************************************/
+
+/* Compute the absolute value. */
+#define	JAS_ABS(x) \
+	(((x) >= 0) ? (x) : (-(x)))
+
+/* Compute the minimum of two values. */
+#define	JAS_MIN(x, y) \
+	(((x) < (y)) ? (x) : (y))
+
+/* Compute the maximum of two values. */
+#define	JAS_MAX(x, y) \
+	(((x) > (y)) ? (x) : (y))
+
+/* Compute the remainder from division (where division is defined such
+  that the remainder is always nonnegative). */
+#define	JAS_MOD(x, y) \
+	(((x) < 0) ? (((-x) % (y)) ? ((y) - ((-(x)) % (y))) : (0)) : ((x) % (y)))
+
+/* Compute the integer with the specified number of least significant bits
+  set to one. */
+#define	JAS_ONES(n) \
+  ((1 << (n)) - 1)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_seq.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_seq.h
new file mode 100644
index 00000000..4599f50c
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_seq.h
@@ -0,0 +1,348 @@
+/*
+ * 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__
+ */
+
+/*
+ * Sequence/Matrix Library
+ *
+ * $Id$
+ */
+
+#ifndef JAS_SEQ_H
+#define JAS_SEQ_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <jasper/jas_stream.h>
+#include <jasper/jas_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/* This matrix is a reference to another matrix. */
+#define JAS_MATRIX_REF	0x0001
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/* An element in a sequence. */
+typedef int_fast32_t jas_seqent_t;
+
+/* An element in a matrix. */
+typedef int_fast32_t jas_matent_t;
+
+/* Matrix. */
+
+typedef struct {
+
+	/* Additional state information. */
+	int flags_;
+
+	/* The starting horizontal index. */
+	int_fast32_t xstart_;
+
+	/* The starting vertical index. */
+	int_fast32_t ystart_;
+
+	/* The ending horizontal index. */
+	int_fast32_t xend_;
+
+	/* The ending vertical index. */
+	int_fast32_t yend_;
+
+	/* The number of rows in the matrix. */
+	int_fast32_t numrows_;
+
+	/* The number of columns in the matrix. */
+	int_fast32_t numcols_;
+
+	/* Pointers to the start of each row. */
+	jas_seqent_t **rows_;
+
+	/* The allocated size of the rows array. */
+	int_fast32_t maxrows_;
+
+	/* The matrix data buffer. */
+	jas_seqent_t *data_;
+
+	/* The allocated size of the data array. */
+	int_fast32_t datasize_;
+
+} jas_matrix_t;
+
+typedef jas_matrix_t jas_seq2d_t;
+typedef jas_matrix_t jas_seq_t;
+
+/******************************************************************************\
+* Functions/macros for matrix class.
+\******************************************************************************/
+
+/* Get the number of rows. */
+#define jas_matrix_numrows(matrix) \
+	((matrix)->numrows_)
+
+/* Get the number of columns. */
+#define jas_matrix_numcols(matrix) \
+	((matrix)->numcols_)
+
+/* Get a matrix element. */
+#define jas_matrix_get(matrix, i, j) \
+	((matrix)->rows_[i][j])
+
+/* Set a matrix element. */
+#define jas_matrix_set(matrix, i, j, v) \
+	((matrix)->rows_[i][j] = (v))
+
+/* Get an element from a matrix that is known to be a row or column vector. */
+#define jas_matrix_getv(matrix, i) \
+	(((matrix)->numrows_ == 1) ? ((matrix)->rows_[0][i]) : \
+	  ((matrix)->rows_[i][0]))
+
+/* Set an element in a matrix that is known to be a row or column vector. */
+#define jas_matrix_setv(matrix, i, v) \
+	(((matrix)->numrows_ == 1) ? ((matrix)->rows_[0][i] = (v)) : \
+	  ((matrix)->rows_[i][0] = (v)))
+
+/* Get the address of an element in a matrix. */
+#define	jas_matrix_getref(matrix, i, j) \
+	(&(matrix)->rows_[i][j])
+
+#define	jas_matrix_getvref(matrix, i) \
+	(((matrix)->numrows_ > 1) ? jas_matrix_getref(matrix, i, 0) : jas_matrix_getref(matrix, 0, i))
+
+#define jas_matrix_length(matrix) \
+	(max((matrix)->numrows_, (matrix)->numcols_))
+
+/* Create a matrix with the specified dimensions. */
+jas_matrix_t *jas_matrix_create(int numrows, int numcols);
+
+/* Destroy a matrix. */
+void jas_matrix_destroy(jas_matrix_t *matrix);
+
+jas_matrix_t *jas_matrix_copy(jas_matrix_t *x);
+
+/* Resize a matrix.  The previous contents of the matrix are lost. */
+int jas_matrix_resize(jas_matrix_t *matrix, int numrows, int numcols);
+
+int jas_matrix_output(jas_matrix_t *matrix, FILE *out);
+
+jas_matrix_t *jas_matrix_input(FILE *in);
+
+/* Create a matrix that references part of another matrix. */
+void jas_matrix_bindsub(jas_matrix_t *mat0, jas_matrix_t *mat1, int r0, int c0,
+  int r1, int c1);
+
+/* Create a matrix that is a reference to a row of another matrix. */
+#define jas_matrix_bindrow(mat0, mat1, r) \
+  (jas_matrix_bindsub((mat0), (mat1), (r), 0, (r), (mat1)->numcols_ - 1))
+
+/* Create a matrix that is a reference to a column of another matrix. */
+#define jas_matrix_bindcol(mat0, mat1, c) \
+  (jas_matrix_bindsub((mat0), (mat1), 0, (c), (mat1)->numrows_ - 1, (c)))
+
+/* Clip the values of matrix elements to the specified range. */
+void jas_matrix_clip(jas_matrix_t *matrix, jas_seqent_t minval,
+  jas_seqent_t maxval);
+
+/* Arithmetic shift left of all elements in a matrix. */
+void jas_matrix_asl(jas_matrix_t *matrix, int n);
+
+/* Arithmetic shift right of all elements in a matrix. */
+void jas_matrix_asr(jas_matrix_t *matrix, int n);
+
+/* Almost-but-not-quite arithmetic shift right of all elements in a matrix. */
+void jas_matrix_divpow2(jas_matrix_t *matrix, int n);
+
+/* Set all elements of a matrix to the specified value. */
+void jas_matrix_setall(jas_matrix_t *matrix, jas_seqent_t val);
+
+/* The spacing between rows of a matrix. */
+#define	jas_matrix_rowstep(matrix) \
+	(((matrix)->numrows_ > 1) ? ((matrix)->rows_[1] - (matrix)->rows_[0]) : (0))
+
+/* The spacing between columns of a matrix. */
+#define	jas_matrix_step(matrix) \
+	(((matrix)->numrows_ > 1) ? (jas_matrix_rowstep(matrix)) : (1))
+
+/* Compare two matrices for equality. */
+int jas_matrix_cmp(jas_matrix_t *mat0, jas_matrix_t *mat1);
+
+/******************************************************************************\
+* Functions/macros for 2-D sequence class.
+\******************************************************************************/
+
+jas_seq2d_t *jas_seq2d_copy(jas_seq2d_t *x);
+
+jas_matrix_t *jas_seq2d_create(int xstart, int ystart, int xend, int yend);
+
+#define	jas_seq2d_destroy(s) \
+	jas_matrix_destroy(s)
+
+#define	jas_seq2d_xstart(s) \
+	((s)->xstart_)
+#define	jas_seq2d_ystart(s) \
+	((s)->ystart_)
+#define	jas_seq2d_xend(s) \
+	((s)->xend_)
+#define	jas_seq2d_yend(s) \
+	((s)->yend_)
+#define	jas_seq2d_getref(s, x, y) \
+	(jas_matrix_getref(s, (y) - (s)->ystart_, (x) - (s)->xstart_))
+#define	jas_seq2d_get(s, x, y) \
+	(jas_matrix_get(s, (y) - (s)->ystart_, (x) - (s)->xstart_))
+#define	jas_seq2d_rowstep(s) \
+	jas_matrix_rowstep(s)
+#define	jas_seq2d_width(s) \
+	((s)->xend_ - (s)->xstart_)
+#define	jas_seq2d_height(s) \
+	((s)->yend_ - (s)->ystart_)
+#define	jas_seq2d_setshift(s, x, y) \
+	((s)->xstart_ = (x), (s)->ystart_ = (y), \
+	  (s)->xend_ = (s)->xstart_ + (s)->numcols_, \
+	  (s)->yend_ = (s)->ystart_ + (s)->numrows_)
+
+void jas_seq2d_bindsub(jas_matrix_t *s, jas_matrix_t *s1, int xstart,
+  int ystart, int xend, int yend);
+
+/******************************************************************************\
+* Functions/macros for 1-D sequence class.
+\******************************************************************************/
+
+#define	jas_seq_create(start, end) \
+	(jas_seq2d_create(start, 0, end, 1))
+
+#define	jas_seq_destroy(seq) \
+	(jas_seq2d_destroy(seq))
+
+#define jas_seq_set(seq, i, v) \
+	((seq)->rows_[0][(i) - (seq)->xstart_] = (v))
+#define	jas_seq_getref(seq, i) \
+	(&(seq)->rows_[0][(i) - (seq)->xstart_])
+#define	jas_seq_get(seq, i) \
+	((seq)->rows_[0][(i) - (seq)->xstart_])
+#define	jas_seq_start(seq) \
+	((seq)->xstart_)
+#define	jas_seq_end(seq) \
+	((seq)->xend_)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_stream.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_stream.h
new file mode 100644
index 00000000..1062fe1d
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_stream.h
@@ -0,0 +1,498 @@
+/*
+ * 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__
+ */
+
+/*
+ * I/O Stream Class
+ *
+ * $Id$
+ */
+
+#ifndef JAS_STREAM_H
+#define JAS_STREAM_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <jasper/jas_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/* On most UNIX systems, we probably need to define O_BINARY ourselves. */
+#ifndef O_BINARY
+#define O_BINARY	0
+#endif
+
+/*
+ * Stream open flags.
+ */
+
+/* The stream was opened for reading. */
+#define JAS_STREAM_READ	0x0001
+/* The stream was opened for writing. */
+#define JAS_STREAM_WRITE	0x0002
+/* The stream was opened for appending. */
+#define JAS_STREAM_APPEND	0x0004
+/* The stream was opened in binary mode. */
+#define JAS_STREAM_BINARY	0x0008
+/* The stream should be created/truncated. */
+#define JAS_STREAM_CREATE	0x0010
+
+#define JAS_STREAM_NOCLOSE	0x0020
+
+/*
+ * Stream buffering flags.
+ */
+
+/* The stream is unbuffered. */
+#define JAS_STREAM_UNBUF	0x0000
+/* The stream is line buffered. */
+#define JAS_STREAM_LINEBUF	0x0001
+/* The stream is fully buffered. */
+#define JAS_STREAM_FULLBUF	0x0002
+/* The buffering mode mask. */
+#define	JAS_STREAM_BUFMODEMASK	0x000f
+
+/* The memory associated with the buffer needs to be deallocated when the
+  stream is destroyed. */
+#define JAS_STREAM_FREEBUF	0x0008
+/* The buffer is currently being used for reading. */
+#define JAS_STREAM_RDBUF	0x0010
+/* The buffer is currently being used for writing. */
+#define JAS_STREAM_WRBUF	0x0020
+
+/*
+ * Stream error flags.
+ */
+
+/* The end-of-file has been encountered (on reading). */
+#define JAS_STREAM_EOF	0x0001
+/* An I/O error has been encountered on the stream. */
+#define JAS_STREAM_ERR	0x0002
+/* The read/write limit has been exceeded. */
+#define	JAS_STREAM_RWLIMIT	0x0004
+/* The error mask. */
+#define JAS_STREAM_ERRMASK \
+	(JAS_STREAM_EOF | JAS_STREAM_ERR | JAS_STREAM_RWLIMIT)
+
+/*
+ * Other miscellaneous constants.
+ */
+
+/* The default buffer size (for fully-buffered operation). */
+#define JAS_STREAM_BUFSIZE	8192
+/* The default permission mask for file creation. */
+#define JAS_STREAM_PERMS	0666
+
+/* The maximum number of characters that can always be put back on a stream. */
+#define	JAS_STREAM_MAXPUTBACK	16
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/*
+ * Generic file object.
+ */
+
+typedef void jas_stream_obj_t;
+
+/*
+ * Generic file object operations.
+ */
+
+typedef struct {
+
+	/* Read characters from a file object. */
+	int (*read_)(jas_stream_obj_t *obj, char *buf, int cnt);
+
+	/* Write characters to a file object. */
+	int (*write_)(jas_stream_obj_t *obj, char *buf, int cnt);
+
+	/* Set the position for a file object. */
+	long (*seek_)(jas_stream_obj_t *obj, long offset, int origin);
+
+	/* Close a file object. */
+	int (*close_)(jas_stream_obj_t *obj);
+
+} jas_stream_ops_t;
+
+/*
+ * Stream object.
+ */
+
+typedef struct {
+
+	/* The mode in which the stream was opened. */
+	int openmode_;
+
+	/* The buffering mode. */
+	int bufmode_;
+
+	/* The stream status. */
+	int flags_;
+
+	/* The start of the buffer area to use for reading/writing. */
+	unsigned char *bufbase_;
+
+	/* The start of the buffer area excluding the extra initial space for
+	  character putback. */
+	unsigned char *bufstart_;
+
+	/* The buffer size. */
+	int bufsize_;
+
+	/* The current position in the buffer. */
+	unsigned char *ptr_;
+
+	/* The number of characters that must be read/written before
+	the buffer needs to be filled/flushed. */
+	int cnt_;
+
+	/* A trivial buffer to be used for unbuffered operation. */
+	unsigned char tinybuf_[JAS_STREAM_MAXPUTBACK + 1];
+
+	/* The operations for the underlying stream file object. */
+	jas_stream_ops_t *ops_;
+
+	/* The underlying stream file object. */
+	jas_stream_obj_t *obj_;
+
+	/* The number of characters read/written. */
+	long rwcnt_;
+
+	/* The maximum number of characters that may be read/written. */
+	long rwlimit_;
+
+} jas_stream_t;
+
+/*
+ * Regular file object.
+ */
+
+/* Note: This is simply a file descriptor. */
+typedef int jas_stream_fileobj_t;
+
+/*
+ * Memory file object.
+ */
+
+typedef struct {
+
+	/* The data associated with this file. */
+	unsigned char *buf_;
+
+	/* The allocated size of the buffer for holding file data. */
+	int bufsize_;
+
+	/* The length of the file. */
+	int_fast32_t len_;
+
+	/* The seek position. */
+	int_fast32_t pos_;
+
+	/* Is the buffer growable? */
+	int growable_;
+
+	/* Was the buffer allocated internally? */
+	int myalloc_;
+
+} jas_stream_memobj_t;
+
+/******************************************************************************\
+* Macros/functions for opening and closing streams.
+\******************************************************************************/
+
+/* Open a file as a stream. */
+jas_stream_t *jas_stream_fopen(const char *filename, const char *mode);
+
+/* Open a memory buffer as a stream. */
+jas_stream_t *jas_stream_memopen(char *buf, int bufsize);
+
+/* Open a file descriptor as a stream. */
+jas_stream_t *jas_stream_fdopen(int fd, const char *mode);
+
+/* Open a stdio stream as a stream. */
+jas_stream_t *jas_stream_freopen(const char *path, const char *mode, FILE *fp);
+
+/* Open a temporary file as a stream. */
+jas_stream_t *jas_stream_tmpfile(void);
+
+/* Close a stream. */
+int jas_stream_close(jas_stream_t *stream);
+
+/******************************************************************************\
+* Macros/functions for getting/setting the stream state.
+\******************************************************************************/
+
+/* Get the EOF indicator for a stream. */
+#define jas_stream_eof(stream) \
+	(((stream)->flags_ & JAS_STREAM_EOF) != 0)
+
+/* Get the error indicator for a stream. */
+#define jas_stream_error(stream) \
+	(((stream)->flags_ & JAS_STREAM_ERR) != 0)
+
+/* Clear the error indicator for a stream. */
+#define jas_stream_clearerr(stream) \
+	((stream)->flags_ &= ~(JAS_STREAM_ERR | JAS_STREAM_EOF))
+
+/* Get the read/write limit for a stream. */
+#define	jas_stream_getrwlimit(stream) \
+	(((const jas_stream_t *)(stream))->rwlimit_)
+
+/* Set the read/write limit for a stream. */
+int jas_stream_setrwlimit(jas_stream_t *stream, long rwlimit);
+
+/* Get the read/write count for a stream. */
+#define	jas_stream_getrwcount(stream) \
+	(((const jas_stream_t *)(stream))->rwcnt_)
+
+/* Set the read/write count for a stream. */
+long jas_stream_setrwcount(jas_stream_t *stream, long rwcnt);
+
+/******************************************************************************\
+* Macros/functions for I/O.
+\******************************************************************************/
+
+/* Read a character from a stream. */
+#if defined(DEBUG)
+#define	jas_stream_getc(stream)	jas_stream_getc_func(stream)
+#else
+#define jas_stream_getc(stream)	jas_stream_getc_macro(stream)
+#endif
+
+/* Write a character to a stream. */
+#if defined(DEBUG)
+#define jas_stream_putc(stream, c)	jas_stream_putc_func(stream, c)
+#else
+#define jas_stream_putc(stream, c)	jas_stream_putc_macro(stream, c)
+#endif
+
+/* Read characters from a stream into a buffer. */
+int jas_stream_read(jas_stream_t *stream, void *buf, int cnt);
+
+/* Write characters from a buffer to a stream. */
+int jas_stream_write(jas_stream_t *stream, const void *buf, int cnt);
+
+/* Write formatted output to a stream. */
+int jas_stream_printf(jas_stream_t *stream, const char *fmt, ...);
+
+/* Write a string to a stream. */
+int jas_stream_puts(jas_stream_t *stream, const char *s);
+
+/* Read a line of input from a stream. */
+char *jas_stream_gets(jas_stream_t *stream, char *buf, int bufsize);
+
+/* Look at the next character to be read from a stream without actually
+  removing it from the stream. */
+#define	jas_stream_peekc(stream) \
+	(((stream)->cnt_ <= 0) ? jas_stream_fillbuf(stream, 0) : \
+	  ((int)(*(stream)->ptr_)))
+
+/* Put a character back on a stream. */
+int jas_stream_ungetc(jas_stream_t *stream, int c);
+
+/******************************************************************************\
+* Macros/functions for getting/setting the stream position.
+\******************************************************************************/
+
+/* Is it possible to seek on this stream? */
+int jas_stream_isseekable(jas_stream_t *stream);
+
+/* Set the current position within the stream. */
+long jas_stream_seek(jas_stream_t *stream, long offset, int origin);
+
+/* Get the current position within the stream. */
+long jas_stream_tell(jas_stream_t *stream);
+
+/* Seek to the beginning of a stream. */
+int jas_stream_rewind(jas_stream_t *stream);
+
+/******************************************************************************\
+* Macros/functions for flushing.
+\******************************************************************************/
+
+/* Flush any pending output to a stream. */
+int jas_stream_flush(jas_stream_t *stream);
+
+/******************************************************************************\
+* Miscellaneous macros/functions.
+\******************************************************************************/
+
+/* Copy data from one stream to another. */
+int jas_stream_copy(jas_stream_t *dst, jas_stream_t *src, int n);
+
+/* Display stream contents (for debugging purposes). */
+int jas_stream_display(jas_stream_t *stream, FILE *fp, int n);
+
+/* Consume (i.e., discard) characters from stream. */
+int jas_stream_gobble(jas_stream_t *stream, int n);
+
+/* Get the size of the file associated with the specified stream.
+  The specified stream must be seekable. */
+long jas_stream_length(jas_stream_t *stream);
+
+/******************************************************************************\
+* Internal functions.
+\******************************************************************************/
+
+/* The following functions are for internal use only!  If you call them
+directly, you will die a horrible, miserable, and painful death! */
+
+/* Read a character from a stream. */
+#define jas_stream_getc_macro(stream) \
+	((!((stream)->flags_ & (JAS_STREAM_ERR | JAS_STREAM_EOF | \
+	  JAS_STREAM_RWLIMIT))) ? \
+	  (((stream)->rwlimit_ >= 0 && (stream)->rwcnt_ >= (stream)->rwlimit_) ? \
+	  (stream->flags_ |= JAS_STREAM_RWLIMIT, EOF) : \
+	  jas_stream_getc2(stream)) : EOF)
+#define jas_stream_getc2(stream) \
+	((--(stream)->cnt_ < 0) ? jas_stream_fillbuf(stream, 1) : \
+	  (++(stream)->rwcnt_, (int)(*(stream)->ptr_++)))
+
+/* Write a character to a stream. */
+#define jas_stream_putc_macro(stream, c) \
+	((!((stream)->flags_ & (JAS_STREAM_ERR | JAS_STREAM_EOF | \
+	  JAS_STREAM_RWLIMIT))) ? \
+	  (((stream)->rwlimit_ >= 0 && (stream)->rwcnt_ >= (stream)->rwlimit_) ? \
+	  (stream->flags_ |= JAS_STREAM_RWLIMIT, EOF) : \
+	  jas_stream_putc2(stream, c)) : EOF)
+#define jas_stream_putc2(stream, c) \
+	(((stream)->bufmode_ |= JAS_STREAM_WRBUF, --(stream)->cnt_ < 0) ? \
+	  jas_stream_flushbuf((stream), (unsigned char)(c)) : \
+	  (++(stream)->rwcnt_, (int)(*(stream)->ptr_++ = (c))))
+
+/* These prototypes need to be here for the sake of the stream_getc and
+stream_putc macros. */
+int jas_stream_fillbuf(jas_stream_t *stream, int getflag);
+int jas_stream_flushbuf(jas_stream_t *stream, int c);
+int jas_stream_getc_func(jas_stream_t *stream);
+int jas_stream_putc_func(jas_stream_t *stream, int c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_string.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_string.h
new file mode 100644
index 00000000..55b611ba
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_string.h
@@ -0,0 +1,143 @@
+/*
+ * 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__
+ */
+
+/*
+ * String Library
+ *
+ * $Id$
+ */
+
+#ifndef	JAS_STRING_H
+#define	JAS_STRING_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Copy a string (a la strdup). */
+char *jas_strdup(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_tvp.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_tvp.h
new file mode 100644
index 00000000..9ac50dbd
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_tvp.h
@@ -0,0 +1,198 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tag/Value Parser
+ *
+ * $Id$
+ */
+
+#ifndef JAS_TVP_H
+#define JAS_TVP_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/* Tag information type. */
+
+typedef struct {
+
+	int id;
+	/* The ID for the tag. */
+
+	const char *name;
+	/* The name of the tag. */
+
+} jas_taginfo_t;
+
+/* Tag-value parser type. */
+
+typedef struct {
+
+	char *buf;
+	/* The parsing buffer. */
+
+	char *tag;
+	/* The current tag name. */
+
+	const char *val;
+	/* The current value. */
+
+	char *pos;
+	/* The current position in the parsing buffer. */
+
+} jas_tvparser_t;
+
+/******************************************************************************\
+* Tag information functions.
+\******************************************************************************/
+
+/* Lookup a tag by name. */
+jas_taginfo_t *jas_taginfos_lookup(jas_taginfo_t *taginfos, const char *name);
+
+/* This function returns a pointer to the specified taginfo object if it
+  exists (i.e., the pointer is nonnull); otherwise, a pointer to a dummy
+  object is returned.  This is useful in some situations to avoid checking
+  for a null pointer. */
+jas_taginfo_t *jas_taginfo_nonull(jas_taginfo_t *taginfo);
+
+/******************************************************************************\
+* Tag-value parser functions.
+\******************************************************************************/
+
+/* Create a tag-value parser for the specified string. */
+jas_tvparser_t *jas_tvparser_create(const char *s);
+
+/* Destroy a tag-value parser. */
+void jas_tvparser_destroy(jas_tvparser_t *tvparser);
+
+/* Get the next tag-value pair. */
+int jas_tvparser_next(jas_tvparser_t *tvparser);
+
+/* Get the tag name for the current tag-value pair. */
+char *jas_tvparser_gettag(jas_tvparser_t *tvparser);
+
+/* Get the value for the current tag-value pair. */
+const char *jas_tvparser_getval(jas_tvparser_t *tvparser);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h
new file mode 100644
index 00000000..4d3a4988
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h
@@ -0,0 +1,14 @@
+/* In the original Jasper library, this contains definitions of the int_fast32,
+   etc. types and bool.
+
+   In Netpbm, we do that with pm_config.h, and the original Jasper
+   method doesn't work.
+*/
+#include "pm_config.h"
+
+
+/* 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))
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig
new file mode 100644
index 00000000..10c1152d
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_types.h.orig
@@ -0,0 +1,228 @@
+/*
+ * 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 <stdlib.h>
+#endif
+#if defined(HAVE_STDDEF_H)
+#include <stddef.h>
+#endif
+#if defined(HAVE_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
+#if defined(HAVE_STDBOOL_H)
+/*
+ * The C language implementation does correctly provide the standard header
+ * file "stdbool.h".
+ */
+#include <stdbool.h>
+#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 <inttypes.h>.  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/include/jasper/jas_version.h b/converter/other/jpeg2000/libjasper/include/jasper/jas_version.h
new file mode 100644
index 00000000..2178257c
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jas_version.h
@@ -0,0 +1,167 @@
+/*
+ * 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$
+ */
+
+#ifndef JAS_VERSION_H
+#define JAS_VERSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+* Constants and types.
+\******************************************************************************/
+
+#if !defined(JAS_VERSION)
+/* The version information below should match that specified in
+  the "configure.in" file! */
+#define	JAS_VERSION		"1.600.0"
+#endif
+
+#define	JAS_COPYRIGHT \
+	"Copyright (c) 1999-2000 Image Power, Inc. and the University of\n" \
+	"  British Columbia.\n" \
+	"Copyright (c) 2001-2002 Michael David Adams.\n" \
+	"All rights reserved.\n"
+
+#define	JAS_NOTES \
+	"For more information about this software, please visit the following\n" \
+	"web sites/pages:\n" \
+	"    http://www.ece.ubc.ca/~mdadams/jasper\n" \
+	"    http://www.jpeg.org/software\n" \
+	"To be added to the (moderated) JasPer software announcements\n" \
+	"mailing list, send an email to:\n" \
+	"    jasper-announce-subscribe@yahoogroups.com\n" \
+	"To be added to the (unmoderated) JasPer software discussion\n" \
+	"mailing list, send an email to:\n" \
+	"    jasper-discussion-subscribe@yahoogroups.com\n" \
+	"Please send any bug reports to:\n" \
+	"    mdadams@ieee.org\n"
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+const char *jas_getversion(void);
+/* Get the version information for the JasPer library. */
+/* Note:  Since libjasper can be built as a shared library, the version
+  returned by this function may not necessarily correspond to JAS_VERSION. */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/include/jasper/jasper.h b/converter/other/jpeg2000/libjasper/include/jasper/jasper.h
new file mode 100644
index 00000000..b003acfa
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/include/jasper/jasper.h
@@ -0,0 +1,137 @@
+/*
+ * 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__
+ */
+
+#ifndef JAS_JASPER_H
+#define JAS_JASPER_H
+
+#include <jasper/jas_types.h>
+#include <jasper/jas_version.h>
+
+#include <jasper/jas_init.h>
+#include <jasper/jas_fix.h>
+#include <jasper/jas_debug.h>
+#include <jasper/jas_getopt.h>
+#include <jasper/jas_image.h>
+#include <jasper/jas_math.h>
+#include <jasper/jas_malloc.h>
+#include <jasper/jas_seq.h>
+#include <jasper/jas_stream.h>
+#include <jasper/jas_string.h>
+#include <jasper/jas_tvp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jp2/Makefile b/converter/other/jpeg2000/libjasper/jp2/Makefile
new file mode 100644
index 00000000..254b7f56
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jp2/Makefile
@@ -0,0 +1,19 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/jpeg2000/libjasper/jp2
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+JASPERSRCDIR=$(SRCDIR)/$(SUBDIR)/..
+
+include $(BUILDDIR)/Makefile.config
+
+LIB_OBJECTS = jp2_cod.o jp2_dec.o jp2_enc.o
+
+MERGE_OBJECTS =
+
+all: partlist $(LIB_OBJECTS)
+
+include $(JASPERSRCDIR)/Makefile.common
+
diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c b/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c
new file mode 100644
index 00000000..4769c408
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jp2/jp2_cod.c
@@ -0,0 +1,928 @@
+/*
+ * 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__
+ */
+
+/*
+ * JP2 Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "pm_c_util.h"
+
+#include "jasper/jas_stream.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_debug.h"
+
+#include "jp2_cod.h"
+
+/******************************************************************************\
+* Function prototypes.
+\******************************************************************************/
+
+#define	ONES(n)	((1 << (n)) - 1)
+
+jp2_boxinfo_t *jp2_boxinfolookup(int type);
+
+static int jp2_getuint8(jas_stream_t *in, uint_fast8_t *val);
+static int jp2_getuint16(jas_stream_t *in, uint_fast16_t *val);
+static int jp2_getuint32(jas_stream_t *in, uint_fast32_t *val);
+static int jp2_getuint64(jas_stream_t *in, uint_fast64_t *val);
+static int jp2_putuint8(jas_stream_t *out, uint_fast8_t val);
+static int jp2_putuint16(jas_stream_t *out, uint_fast16_t val);
+static int jp2_putuint32(jas_stream_t *out, uint_fast32_t val);
+
+static int jp2_getint(jas_stream_t *in, int s, int n, int_fast32_t *val);
+
+jp2_box_t *jp2_box_get(jas_stream_t *in);
+void jp2_box_dump(jp2_box_t *box, FILE *out);
+
+static int jp2_jp_getdata(jp2_box_t *box, jas_stream_t *in);
+static int jp2_jp_putdata(jp2_box_t *box, jas_stream_t *out);
+static int jp2_ftyp_getdata(jp2_box_t *box, jas_stream_t *in);
+static int jp2_ftyp_putdata(jp2_box_t *box, jas_stream_t *out);
+static int jp2_ihdr_getdata(jp2_box_t *box, jas_stream_t *in);
+static int jp2_ihdr_putdata(jp2_box_t *box, jas_stream_t *out);
+static void jp2_bpcc_destroy(jp2_box_t *box);
+static int jp2_bpcc_getdata(jp2_box_t *box, jas_stream_t *in);
+static int jp2_bpcc_putdata(jp2_box_t *box, jas_stream_t *out);
+static int jp2_colr_getdata(jp2_box_t *box, jas_stream_t *in);
+static int jp2_colr_putdata(jp2_box_t *box, jas_stream_t *out);
+static void jp2_colr_dumpdata(jp2_box_t *box, FILE *out);
+static void jp2_colr_destroy(jp2_box_t *box);
+static void jp2_cdef_destroy(jp2_box_t *box);
+static int jp2_cdef_getdata(jp2_box_t *box, jas_stream_t *in);
+static int jp2_cdef_putdata(jp2_box_t *box, jas_stream_t *out);
+static void jp2_cdef_dumpdata(jp2_box_t *box, FILE *out);
+static void jp2_cmap_destroy(jp2_box_t *box);
+static int jp2_cmap_getdata(jp2_box_t *box, jas_stream_t *in);
+static int jp2_cmap_putdata(jp2_box_t *box, jas_stream_t *out);
+static void jp2_cmap_dumpdata(jp2_box_t *box, FILE *out);
+static void jp2_pclr_destroy(jp2_box_t *box);
+static int jp2_pclr_getdata(jp2_box_t *box, jas_stream_t *in);
+static int jp2_pclr_putdata(jp2_box_t *box, jas_stream_t *out);
+static void jp2_pclr_dumpdata(jp2_box_t *box, FILE *out);
+
+/******************************************************************************\
+* Local data.
+\******************************************************************************/
+
+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_boxinfo_t jp2_boxinfo_unk = {
+	0, "Unknown", 0, {0, 0, 0, 0}
+};
+
+/******************************************************************************\
+* Box constructor.
+\******************************************************************************/
+
+jp2_box_t *jp2_box_create(int type)
+{
+	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;
+}
+
+/******************************************************************************\
+* Box destructor.
+\******************************************************************************/
+
+void jp2_box_destroy(jp2_box_t *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;
+	}
+}
+
+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;
+	}
+}
+
+/******************************************************************************\
+* Box input.
+\******************************************************************************/
+
+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;
+    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();
+
+error:
+	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);
+
+	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);
+	}
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+	}
+}
+
+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;
+}
+
+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);
+	}
+}
+
+static void jp2_colr_destroy(jp2_box_t *box)
+{
+	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;
+}
+
+/******************************************************************************\
+* Box output.
+\******************************************************************************/
+
+int jp2_box_put(jp2_box_t *box, jas_stream_t *out)
+{
+	jas_stream_t *tmpstream;
+	bool dataflag;
+
+	tmpstream = 0;
+
+	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);
+	}
+    /* 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
+       definition.  Either this encoder is incapable of making boxes with
+       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();
+
+error:
+
+	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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+
+	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;
+}
+
+/******************************************************************************\
+* Input operations for primitive types.
+\******************************************************************************/
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+static int jp2_getuint64(jas_stream_t *in, uint_fast64_t *val)
+{
+	abort();
+}
+
+/******************************************************************************\
+* Output operations for primitive types.
+\******************************************************************************/
+
+static int jp2_putuint8(jas_stream_t *out, uint_fast8_t val)
+{
+	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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* Miscellaneous code.
+\******************************************************************************/
+
+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;
+}
+
+
+
+
+
+static void jp2_cmap_destroy(jp2_box_t *box)
+{
+	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;
+}
+
+static int jp2_cmap_putdata(jp2_box_t *box, jas_stream_t *out)
+{
+	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);
+	}
+}
+
+static void jp2_pclr_destroy(jp2_box_t *box)
+{
+	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;
+}
+
+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;
+    */
+	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]);
+		}
+	}
+}
+
+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;
+}
+
+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;
+}
diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_cod.h b/converter/other/jpeg2000/libjasper/jp2/jp2_cod.h
new file mode 100644
index 00000000..96b48d12
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jp2/jp2_cod.h
@@ -0,0 +1,347 @@
+/*
+ * 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__
+ */
+
+/*
+ * JP2 Library
+ *
+ * $Id$
+ */
+
+#ifndef JP2_COD_H
+#define JP2_COD_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_types.h"
+
+/******************************************************************************\
+* Macros.
+\******************************************************************************/
+
+#define	JP2_SPTOBPC(s, p) \
+	((((p) - 1) & 0x7f) | (((s) & 1) << 7))
+
+/******************************************************************************\
+* Box class.
+\******************************************************************************/
+
+#define	JP2_BOX_HDRLEN	8
+
+/* Box types. */
+#define	JP2_BOX_JP		0x6a502020	/* Signature */
+#define JP2_BOX_FTYP	0x66747970	/* File Type */
+#define	JP2_BOX_JP2H	0x6a703268	/* JP2 Header */
+#define	JP2_BOX_IHDR	0x69686472	/* Image Header */
+#define	JP2_BOX_BPCC	0x62706363	/* Bits Per Component */
+#define	JP2_BOX_COLR	0x636f6c72	/* Color Specification */
+#define	JP2_BOX_PCLR	0x70636c72	/* Palette */
+#define	JP2_BOX_CMAP	0x636d6170	/* Component Mapping */
+#define	JP2_BOX_CDEF	0x63646566	/* Channel Definition */
+#define	JP2_BOX_RES		0x72657320	/* Resolution */
+#define	JP2_BOX_RESC	0x72657363	/* Capture Resolution */
+#define	JP2_BOX_RESD	0x72657364	/* Default Display Resolution */
+#define	JP2_BOX_JP2C	0x6a703263	/* Contiguous Code Stream */
+#define	JP2_BOX_JP2I	0x6a703269	/* Intellectual Property */
+#define	JP2_BOX_XML		0x786d6c20	/* XML */
+#define	JP2_BOX_UUID	0x75756964	/* UUID */
+#define	JP2_BOX_UINF	0x75696e66	/* UUID Info */
+#define	JP2_BOX_ULST	0x75637374	/* UUID List */
+#define	JP2_BOX_URL		0x75726c20	/* URL */
+
+#define	JP2_BOX_SUPER	0x01
+#define	JP2_BOX_NODATA	0x02
+
+/* JP box data. */
+
+#define	JP2_JP_MAGIC	0x0d0a870a
+#define	JP2_JP_LEN		12
+
+typedef struct {
+	uint_fast32_t magic;
+} jp2_jp_t;
+
+/* FTYP box data. */
+
+#define	JP2_FTYP_MAXCOMPATCODES	32
+#define	JP2_FTYP_MAJVER		0x6a703220
+#define	JP2_FTYP_MINVER		0
+#define	JP2_FTYP_COMPATCODE		JP2_FTYP_MAJVER
+
+typedef struct {
+	uint_fast32_t majver;
+	uint_fast32_t minver;
+	uint_fast32_t numcompatcodes;
+	uint_fast32_t compatcodes[JP2_FTYP_MAXCOMPATCODES];
+} jp2_ftyp_t;
+
+/* IHDR box data. */
+
+#define	JP2_IHDR_COMPTYPE	7
+#define	JP2_IHDR_BPCNULL	255
+
+typedef struct {
+	uint_fast32_t width;
+	uint_fast32_t height;
+	uint_fast16_t numcmpts;
+	uint_fast8_t bpc;
+	uint_fast8_t comptype;
+	uint_fast8_t csunk;
+	uint_fast8_t ipr;
+} jp2_ihdr_t;
+
+/* BPCC box data. */
+
+typedef struct {
+	uint_fast16_t numcmpts;
+	uint_fast8_t *bpcs;
+} jp2_bpcc_t;
+
+/* COLR box data. */
+
+#define	JP2_COLR_ENUM	1
+#define	JP2_COLR_ICC	2
+#define	JP2_COLR_PRI	0
+
+#define	JP2_COLR_SRGB	16
+#define	JP2_COLR_SGRAY	17
+#define	JP2_COLR_SYCC	18
+
+typedef struct {
+	uint_fast8_t method;
+	uint_fast8_t pri;
+	uint_fast8_t approx;
+	uint_fast32_t csid;
+	uint_fast8_t *iccp;
+	int iccplen;
+	/* XXX - Someday we ought to add ICC profile data here. */
+} jp2_colr_t;
+
+/* PCLR box data. */
+
+typedef struct {
+	uint_fast16_t numlutents;
+	uint_fast8_t numchans;
+	int_fast32_t *lutdata;
+	uint_fast8_t *bpc;
+} jp2_pclr_t;
+
+/* CDEF box per-channel data. */
+
+#define JP2_CDEF_RGB_R	1
+#define JP2_CDEF_RGB_G	2
+#define JP2_CDEF_RGB_B	3
+
+#define JP2_CDEF_YCBCR_Y	1
+#define JP2_CDEF_YCBCR_CB	2
+#define JP2_CDEF_YCBCR_CR	3
+
+#define	JP2_CDEF_GRAY_Y	1
+
+#define	JP2_CDEF_TYPE_COLOR	0
+#define	JP2_CDEF_TYPE_OPACITY	1
+#define	JP2_CDEF_TYPE_UNSPEC	65535
+#define	JP2_CDEF_ASOC_ALL	0
+#define	JP2_CDEF_ASOC_NONE	65535
+
+typedef struct {
+	uint_fast16_t channo;
+	uint_fast16_t type;
+	uint_fast16_t assoc;
+} jp2_cdefchan_t;
+
+/* CDEF box data. */
+
+typedef struct {
+	uint_fast16_t numchans;
+	jp2_cdefchan_t *ents;
+} jp2_cdef_t;
+
+typedef struct {
+	uint_fast16_t cmptno;
+	uint_fast8_t map;
+	uint_fast8_t pcol;
+} jp2_cmapent_t;
+
+typedef struct {
+	uint_fast16_t numchans;
+	jp2_cmapent_t *ents;
+} jp2_cmap_t;
+
+#define	JP2_CMAP_DIRECT		0
+#define	JP2_CMAP_PALETTE	1
+
+/* Generic box. */
+
+struct jp2_boxops_s;
+typedef struct {
+
+	struct jp2_boxops_s *ops;
+	struct jp2_boxinfo_s *info;
+
+	uint_fast32_t type;
+	uint_fast32_t len;
+
+	union {
+		jp2_jp_t jp;
+		jp2_ftyp_t ftyp;
+		jp2_ihdr_t ihdr;
+		jp2_bpcc_t bpcc;
+		jp2_colr_t colr;
+		jp2_pclr_t pclr;
+		jp2_cdef_t cdef;
+		jp2_cmap_t cmap;
+	} data;
+
+} jp2_box_t;
+
+typedef struct jp2_boxops_s {
+	void (*init)(jp2_box_t *box);
+	void (*destroy)(jp2_box_t *box);
+	int (*getdata)(jp2_box_t *box, jas_stream_t *in);
+	int (*putdata)(jp2_box_t *box, jas_stream_t *out);
+	void (*dumpdata)(jp2_box_t *box, FILE *out);
+} jp2_boxops_t;
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+typedef struct jp2_boxinfo_s {
+	int type;
+	const char *name;
+	int flags;
+	jp2_boxops_t ops;
+} jp2_boxinfo_t;
+
+/******************************************************************************\
+* Box class.
+\******************************************************************************/
+
+jp2_box_t *jp2_box_create(int type);
+void jp2_box_destroy(jp2_box_t *box);
+jp2_box_t *jp2_box_get(jas_stream_t *in);
+int jp2_box_put(jp2_box_t *box, jas_stream_t *out);
+
+#define JP2_DTYPETOBPC(dtype) \
+  ((JAS_IMAGE_CDT_GETSGND(dtype) << 7) | (JAS_IMAGE_CDT_GETPREC(dtype) - 1))
+#define	JP2_BPCTODTYPE(bpc) \
+  (JAS_IMAGE_CDT_SETSGND(bpc >> 7) | JAS_IMAGE_CDT_SETPREC((bpc & 0x7f) + 1))
+
+#define ICC_CS_RGB	0x52474220
+#define ICC_CS_YCBCR	0x59436272
+#define ICC_CS_GRAY	0x47524159
+
+jp2_cdefchan_t *jp2_cdef_lookup(jp2_cdef_t *cdef, int channo);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
new file mode 100644
index 00000000..3cce9278
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
@@ -0,0 +1,649 @@
+/*
+ * 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__
+ */
+
+/*
+ * JP2 Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_image.h"
+#include "jasper/jas_stream.h"
+#include "jasper/jas_math.h"
+#include "jasper/jas_debug.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_version.h"
+
+#include "jp2_cod.h"
+#include "jp2_dec.h"
+
+#define	JP2_VALIDATELEN	(JAS_MIN(JP2_JP_LEN + 16, JAS_STREAM_MAXPUTBACK))
+
+static jp2_dec_t *jp2_dec_create(void);
+static void jp2_dec_destroy(jp2_dec_t *dec);
+static int jp2_getcs(jp2_colr_t *colr);
+static int jp2_getct(int colorspace, int type, int assoc);
+static int fromiccpcs(int cs);
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+jas_image_t *jp2_decode(jas_stream_t *in, char *optstr)
+{
+	jp2_box_t *box;
+	int found;
+	jas_image_t *image;
+	jp2_dec_t *dec;
+	bool samedtype;
+	int dtype;
+	int i;
+	jp2_cmap_t *cmapd;
+	jp2_pclr_t *pclrd;
+	jp2_cdef_t *cdefd;
+	int channo;
+	int newcmptno;
+	int_fast32_t *lutents;
+	jp2_cmapent_t *cmapent;
+	unsigned char *iccp;
+	int cs;
+
+	dec = 0;
+	box = 0;
+	image = 0;
+
+	if (!(dec = jp2_dec_create())) {
+		goto error;
+	}
+
+	/* Get the first box.  This should be a JP box. */
+	if (!(box = jp2_box_get(in))) {
+		jas_eprintf("error: cannot get box\n");
+		goto error;
+	}
+	if (box->type != JP2_BOX_JP) {
+		jas_eprintf("error: expecting signature box\n");
+		goto error;
+	}
+	if (box->data.jp.magic != JP2_JP_MAGIC) {
+		jas_eprintf("incorrect magic number\n");
+		goto error;
+	}
+	jp2_box_destroy(box);
+	box = 0;
+
+	/* Get the second box.  This should be a FTYP box. */
+	if (!(box = jp2_box_get(in))) {
+		goto error;
+	}
+	if (box->type != JP2_BOX_FTYP) {
+		jas_eprintf("expecting file type box\n");
+		goto error;
+	}
+	jp2_box_destroy(box);
+	box = 0;
+
+	/* Get more boxes... */
+	found = 0;
+	while ((box = jp2_box_get(in))) {
+		if (jas_getdbglevel() >= 1) {
+			fprintf(stderr, "box type %s\n", box->info->name);
+		}
+		switch (box->type) {
+		case JP2_BOX_JP2C:
+			found = 1;
+			break;
+		case JP2_BOX_IHDR:
+			if (!dec->ihdr) {
+				dec->ihdr = box;
+				box = 0;
+			}
+			break;
+		case JP2_BOX_BPCC:
+			if (!dec->bpcc) {
+				dec->bpcc = box;
+				box = 0;
+			}
+			break;
+		case JP2_BOX_CDEF:
+			if (!dec->cdef) {
+				dec->cdef = box;
+				box = 0;
+			}
+			break;
+		case JP2_BOX_PCLR:
+			if (!dec->pclr) {
+				dec->pclr = box;
+				box = 0;
+			}
+			break;
+		case JP2_BOX_CMAP:
+			if (!dec->cmap) {
+				dec->cmap = box;
+				box = 0;
+			}
+			break;
+		case JP2_BOX_COLR:
+			if (!dec->colr) {
+				dec->colr = box;
+				box = 0;
+			}
+			break;
+		}
+		if (box) {
+			jp2_box_destroy(box);
+			box = 0;
+		}
+		if (found) {
+			break;
+		}
+	}
+
+	if (!found) {
+		jas_eprintf("error: no code stream found\n");
+		goto error;
+	}
+
+	if (!(dec->image = jpc_decode(in, optstr))) {
+		jas_eprintf("error: cannot decode code stream\n");
+		goto error;
+	}
+
+	/* An IHDR box must be present. */
+	if (!dec->ihdr) {
+		jas_eprintf("error: missing IHDR box\n");
+		goto error;
+	}
+
+	/* Does the number of components indicated in the IHDR box match
+	  the value specified in the code stream? */
+	if (dec->ihdr->data.ihdr.numcmpts != jas_image_numcmpts(dec->image)) {
+		jas_eprintf("warning: number of components mismatch\n");
+	}
+
+	/* At least one component must be present. */
+	if (!jas_image_numcmpts(dec->image)) {
+		jas_eprintf("error: no components\n");
+		goto error;
+	}
+
+	/* Determine if all components have the same data type. */
+	samedtype = true;
+	dtype = jas_image_cmptdtype(dec->image, 0);
+	for (i = 1; i < jas_image_numcmpts(dec->image); ++i) {
+		if (jas_image_cmptdtype(dec->image, i) != dtype) {
+			samedtype = false;
+			break;
+		}
+	}
+
+	/* Is the component data type indicated in the IHDR box consistent
+	  with the data in the code stream? */
+	if ((samedtype && dec->ihdr->data.ihdr.bpc != JP2_DTYPETOBPC(dtype)) ||
+	  (!samedtype && dec->ihdr->data.ihdr.bpc != JP2_IHDR_BPCNULL)) {
+		jas_eprintf("warning: component data type mismatch\n");
+	}
+
+	/* Is the compression type supported? */
+	if (dec->ihdr->data.ihdr.comptype != JP2_IHDR_COMPTYPE) {
+		jas_eprintf("error: unsupported compression type\n");
+		goto error;
+	}
+
+	if (dec->bpcc) {
+		/* Is the number of components indicated in the BPCC box
+		  consistent with the code stream data? */
+		if (dec->bpcc->data.bpcc.numcmpts != jas_image_numcmpts(
+		  dec->image)) {
+			jas_eprintf("warning: number of components mismatch\n");
+		}
+		/* Is the component data type information indicated in the BPCC
+		  box consistent with the code stream data? */
+		if (!samedtype) {
+			for (i = 0; i < jas_image_numcmpts(dec->image); ++i) {
+				if (jas_image_cmptdtype(dec->image, i) != JP2_BPCTODTYPE(dec->bpcc->data.bpcc.bpcs[i])) {
+					jas_eprintf("warning: component data type mismatch\n");
+				}
+			}
+		} else {
+			jas_eprintf("warning: superfluous BPCC box\n");
+		}
+	}
+
+	/* A COLR box must be present. */
+	if (!dec->colr) {
+		jas_eprintf("error: no COLR box\n");
+		goto error;
+	}
+
+	switch (dec->colr->data.colr.method) {
+	case JP2_COLR_ENUM:
+		jas_image_setcolorspace(dec->image, jp2_getcs(&dec->colr->data.colr));
+		break;
+	case JP2_COLR_ICC:
+		if (dec->colr->data.colr.iccplen < 128) {
+			abort();
+		}
+		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);
+		jas_image_setcolorspace(dec->image, fromiccpcs(cs));
+		break;
+	}
+
+	/* If a CMAP box is present, a PCLR box must also be present. */
+	if (dec->cmap && !dec->pclr) {
+		jas_eprintf("warning: missing PCLR box or superfluous CMAP box\n");
+		jp2_box_destroy(dec->cmap);
+		dec->cmap = 0;
+	}
+
+	/* If a CMAP box is not present, a PCLR box must not be present. */
+	if (!dec->cmap && dec->pclr) {
+		jas_eprintf("warning: missing CMAP box or superfluous PCLR box\n");
+		jp2_box_destroy(dec->pclr);
+		dec->pclr = 0;
+	}
+
+	/* Determine the number of channels (which is essentially the number
+	  of components after any palette mappings have been applied). */
+	dec->numchans = dec->cmap ? dec->cmap->data.cmap.numchans : jas_image_numcmpts(dec->image);
+
+	/* Perform a basic sanity check on the CMAP box if present. */
+	if (dec->cmap) {
+		for (i = 0; i < dec->numchans; ++i) {
+			/* Is the component number reasonable? */
+			if (dec->cmap->data.cmap.ents[i].cmptno >= jas_image_numcmpts(dec->image)) {
+				jas_eprintf("error: invalid component number in CMAP box\n");
+				goto error;
+			}
+			/* Is the LUT index reasonable? */
+			if (dec->cmap->data.cmap.ents[i].pcol >= dec->pclr->data.pclr.numchans) {
+				jas_eprintf("error: invalid CMAP LUT index\n");
+				goto error;
+			}
+		}
+	}
+
+	/* Allocate space for the channel-number to component-number LUT. */
+	if (!(dec->chantocmptlut = jas_malloc(dec->numchans * sizeof(uint_fast16_t)))) {
+		jas_eprintf("error: no memory\n");
+		goto error;
+	}
+
+	if (!dec->cmap) {
+		for (i = 0; i < dec->numchans; ++i) {
+			dec->chantocmptlut[i] = i;
+		}
+	} else {
+		cmapd = &dec->cmap->data.cmap;
+		pclrd = &dec->pclr->data.pclr;
+		cdefd = &dec->cdef->data.cdef;
+		for (channo = 0; channo < cmapd->numchans; ++channo) {
+			cmapent = &cmapd->ents[channo];
+			if (cmapent->map == JP2_CMAP_DIRECT) {
+				dec->chantocmptlut[channo] = channo;
+			} else if (cmapent->map == JP2_CMAP_PALETTE) {
+				lutents = jas_malloc(pclrd->numlutents * sizeof(int_fast32_t));
+				for (i = 0; i < pclrd->numlutents; ++i) {
+					lutents[i] = pclrd->lutdata[cmapent->pcol + i * pclrd->numchans];
+				}
+				newcmptno = jas_image_numcmpts(dec->image);
+				jas_image_depalettize(dec->image, cmapent->cmptno, pclrd->numlutents, lutents, JP2_BPCTODTYPE(pclrd->bpc[cmapent->pcol]), newcmptno);
+				dec->chantocmptlut[channo] = newcmptno;
+				jas_free(lutents);
+#if 0
+				if (dec->cdef) {
+					cdefent = jp2_cdef_lookup(cdefd, channo);
+					if (!cdefent) {
+						abort();
+					}
+				jas_image_setcmpttype(dec->image, newcmptno, jp2_getct(jas_image_colorspace(dec->image), cdefent->type, cdefent->assoc));
+				} else {
+				jas_image_setcmpttype(dec->image, newcmptno, jp2_getct(jas_image_colorspace(dec->image), 0, channo + 1));
+				}
+#endif
+			}
+		}
+	}
+
+	/* Mark all components as being of unknown type. */
+
+	for (i = 0; i < jas_image_numcmpts(dec->image); ++i) {
+		jas_image_setcmpttype(dec->image, i, JAS_IMAGE_CT_UNKNOWN);
+	}
+
+	/* Determine the type of each component. */
+	if (dec->cdef) {
+		for (i = 0; i < dec->numchans; ++i) {
+			jas_image_setcmpttype(dec->image,
+			  dec->chantocmptlut[dec->cdef->data.cdef.ents[i].channo],
+			  jp2_getct(jas_image_colorspace(dec->image),
+			  dec->cdef->data.cdef.ents[i].type, dec->cdef->data.cdef.ents[i].assoc));
+		}
+	} else {
+		for (i = 0; i < dec->numchans; ++i) {
+			jas_image_setcmpttype(dec->image, dec->chantocmptlut[i],
+			  jp2_getct(jas_image_colorspace(dec->image), 0, i + 1));
+		}
+	}
+
+	/* Delete any components that are not of interest. */
+	for (i = jas_image_numcmpts(dec->image) - 1; i >= 0; --i) {
+		if (jas_image_cmpttype(dec->image, i) == JAS_IMAGE_CT_UNKNOWN) {
+			jas_image_delcmpt(dec->image, i);
+		}
+	}
+
+	/* Ensure that some components survived. */
+	if (!jas_image_numcmpts(dec->image)) {
+		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;
+	dec->image = 0;
+
+	jp2_dec_destroy(dec);
+
+	return image;
+
+error:
+	if (box) {
+		jp2_box_destroy(box);
+	}
+	if (dec) {
+		jp2_dec_destroy(dec);
+	}
+	return 0;
+}
+
+int jp2_validate(jas_stream_t *in)
+{
+	char buf[JP2_VALIDATELEN];
+	int i;
+	int n;
+
+	assert(JAS_STREAM_MAXPUTBACK >= JP2_VALIDATELEN);
+
+	/* Read the validation data (i.e., the data used for detecting
+	  the format). */
+	if ((n = jas_stream_read(in, buf, JP2_VALIDATELEN)) < 0) {
+		return -1;
+	}
+
+	/* Put the validation data back onto the stream, so that the
+	  stream position will not be changed. */
+	for (i = n - 1; i >= 0; --i) {
+		if (jas_stream_ungetc(in, buf[i]) == EOF) {
+			return -1;
+		}
+	}
+
+	/* Did we read enough data? */
+	if (n < JP2_VALIDATELEN) {
+		return -1;
+	}
+
+	/* Is the box type correct? */
+	if (((buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]) !=
+	  JP2_BOX_JP)
+	{
+		return -1;
+	}
+
+	return 0;
+}
+
+static jp2_dec_t *jp2_dec_create(void)
+{
+	jp2_dec_t *dec;
+
+	if (!(dec = jas_malloc(sizeof(jp2_dec_t)))) {
+		return 0;
+	}
+	dec->ihdr = 0;
+	dec->bpcc = 0;
+	dec->cdef = 0;
+	dec->pclr = 0;
+	dec->image = 0;
+	dec->chantocmptlut = 0;
+	dec->cmap = 0;
+	dec->colr = 0;
+	return dec;
+}
+
+static void jp2_dec_destroy(jp2_dec_t *dec)
+{
+	if (dec->ihdr) {
+		jp2_box_destroy(dec->ihdr);
+	}
+	if (dec->bpcc) {
+		jp2_box_destroy(dec->bpcc);
+	}
+	if (dec->cdef) {
+		jp2_box_destroy(dec->cdef);
+	}
+	if (dec->pclr) {
+		jp2_box_destroy(dec->pclr);
+	}
+	if (dec->image) {
+		jas_image_destroy(dec->image);
+	}
+	if (dec->cmap) {
+		jp2_box_destroy(dec->cmap);
+	}
+	if (dec->colr) {
+		jp2_box_destroy(dec->colr);
+	}
+	if (dec->chantocmptlut) {
+		jas_free(dec->chantocmptlut);
+	}
+	jas_free(dec);
+}
+
+
+
+
+
+
+static int jp2_getct(int colorspace, int type, int assoc)
+{
+	if (type == 1 && assoc == 0) {
+		return JAS_IMAGE_CT_OPACITY;
+	}
+	if (type == 0 && assoc >= 1 && assoc <= 65534) {
+		switch (colorspace) {
+		case JAS_IMAGE_CS_RGB:
+			switch (assoc) {
+			case JP2_CDEF_RGB_R:
+				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R);
+				break;
+			case JP2_CDEF_RGB_G:
+				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G);
+				break;
+			case JP2_CDEF_RGB_B:
+				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B);
+				break;
+			}
+			break;
+		case JAS_IMAGE_CS_YCBCR:
+			switch (assoc) {
+			case JP2_CDEF_YCBCR_Y:
+				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_Y);
+				break;
+			case JP2_CDEF_YCBCR_CB:
+				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_CB);
+				break;
+			case JP2_CDEF_YCBCR_CR:
+				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_CR);
+				break;
+			}
+			break;
+		case JAS_IMAGE_CS_GRAY:
+			switch (assoc) {
+			case JP2_CDEF_GRAY_Y:
+				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y);
+				break;
+			}
+			break;
+#if 0
+		case JAS_IMAGE_CS_ICC:
+#endif
+		default:
+			return JAS_IMAGE_CT_COLOR(assoc - 1);
+			break;
+		}
+	}
+	return JAS_IMAGE_CT_UNKNOWN;
+}
+
+static int jp2_getcs(jp2_colr_t *colr)
+{
+	if (colr->method == JP2_COLR_ENUM) {
+		switch (colr->csid) {
+		case JP2_COLR_SRGB:
+			return JAS_IMAGE_CS_RGB;
+			break;
+		case JP2_COLR_SYCC:
+			return JAS_IMAGE_CS_YCBCR;
+			break;
+		case JP2_COLR_SGRAY:
+			return JAS_IMAGE_CS_GRAY;
+			break;
+		}
+	}
+	return JAS_IMAGE_CS_UNKNOWN;
+}
+
+static int fromiccpcs(int cs)
+{
+	switch (cs) {
+	case ICC_CS_RGB:
+		return JAS_IMAGE_CS_RGB;
+		break;
+	case ICC_CS_YCBCR:
+		return JAS_IMAGE_CS_YCBCR;
+		break;
+	case ICC_CS_GRAY:
+		return JAS_IMAGE_CS_GRAY;
+		break;
+	}
+	return JAS_IMAGE_CS_UNKNOWN;
+}
diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.h b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.h
new file mode 100644
index 00000000..300be107
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.h
@@ -0,0 +1,134 @@
+/*
+ * 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__
+ */
+
+#ifndef JP2_DEC_H
+#define JP2_DEC_H
+
+#include "jasper/jas_image.h"
+#include "jasper/jas_stream.h"
+#include "jp2_cod.h"
+
+typedef struct {
+
+	jp2_box_t *pclr;
+	jp2_box_t *cdef;
+	jp2_box_t *ihdr;
+	jp2_box_t *bpcc;
+	jp2_box_t *cmap;
+	jp2_box_t *colr;
+	jas_image_t *image;
+	uint_fast16_t numchans;
+	uint_fast16_t *chantocmptlut;
+
+} jp2_dec_t;
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_enc.c b/converter/other/jpeg2000/libjasper/jp2/jp2_enc.c
new file mode 100644
index 00000000..12538248
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jp2/jp2_enc.c
@@ -0,0 +1,414 @@
+/*
+ * 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__
+ */
+
+/*
+ * JP2 Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_image.h"
+#include "jasper/jas_stream.h"
+
+#include "jp2_cod.h"
+
+static uint_fast32_t jp2_gettypeasoc(int colorspace, int ctype);
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+int jp2_encode(jas_image_t *image, jas_stream_t *out, char *optstr)
+{
+	jp2_box_t *box;
+	jp2_ftyp_t *ftyp;
+	jp2_ihdr_t *ihdr;
+	jas_stream_t *tmpstream;
+	int allcmptssame;
+	jp2_bpcc_t *bpcc;
+	long len;
+	uint_fast16_t cmptno;
+	jp2_colr_t *colr;
+	char buf[4096];
+	uint_fast32_t overhead;
+	jp2_cdefchan_t *cdefchanent;
+	jp2_cdef_t *cdef;
+	int i;
+	uint_fast32_t typeasoc;
+
+	box = 0;
+	tmpstream = 0;
+
+	/* Output the signature box. */
+
+	if (!(box = jp2_box_create(JP2_BOX_JP))) {
+		goto error;
+	}
+	box->data.jp.magic = JP2_JP_MAGIC;
+	if (jp2_box_put(box, out)) {
+		goto error;
+	}
+	jp2_box_destroy(box);
+	box = 0;
+
+	/* Output the file type box. */
+
+	if (!(box = jp2_box_create(JP2_BOX_FTYP))) {
+		goto error;
+	}
+	ftyp = &box->data.ftyp;
+	ftyp->majver = JP2_FTYP_MAJVER;
+	ftyp->minver = JP2_FTYP_MINVER;
+	ftyp->numcompatcodes = 1;
+	ftyp->compatcodes[0] = JP2_FTYP_COMPATCODE;
+	if (jp2_box_put(box, out)) {
+		goto error;
+	}
+	jp2_box_destroy(box);
+	box = 0;
+
+	/*
+	 * Generate the data portion of the JP2 header box.
+	 * We cannot simply output the header for this box
+	 * since we do not yet know the correct value for the length
+	 * field.
+	 */
+
+	if (!(tmpstream = jas_stream_memopen(0, 0))) {
+		goto error;
+	}
+
+	/* Generate image header box. */
+
+	if (!(box = jp2_box_create(JP2_BOX_IHDR))) {
+		goto error;
+	}
+	ihdr = &box->data.ihdr;
+	ihdr->width = jas_image_width(image);
+	ihdr->height = jas_image_height(image);
+	ihdr->numcmpts = jas_image_numcmpts(image);
+	allcmptssame = 0;
+	ihdr->bpc = allcmptssame ? JP2_SPTOBPC(jas_image_cmptsgnd(image, 0),
+	  jas_image_cmptprec(image, 0)) : JP2_IHDR_BPCNULL;
+	ihdr->comptype = JP2_IHDR_COMPTYPE;
+	ihdr->csunk = 0;
+	ihdr->ipr = 0;
+	if (jp2_box_put(box, tmpstream)) {
+		goto error;
+	}
+	jp2_box_destroy(box);
+	box = 0;
+
+	/* Generate bits per component box. */
+
+	if (!allcmptssame) {
+		if (!(box = jp2_box_create(JP2_BOX_BPCC))) {
+			goto error;
+		}
+		bpcc = &box->data.bpcc;
+		bpcc->numcmpts = jas_image_numcmpts(image);
+		if (!(bpcc->bpcs = jas_malloc(bpcc->numcmpts *
+		  sizeof(uint_fast8_t)))) {
+			goto error;
+		}
+		for (cmptno = 0; cmptno < bpcc->numcmpts; ++cmptno) {
+			bpcc->bpcs[cmptno] = JP2_SPTOBPC(jas_image_cmptsgnd(image,
+			  cmptno), jas_image_cmptprec(image, cmptno));
+		}
+		if (jp2_box_put(box, tmpstream)) {
+			goto error;
+		}
+		jp2_box_destroy(box);
+		box = 0;
+	}
+
+	/* Generate color specification box. */
+
+	if (!(box = jp2_box_create(JP2_BOX_COLR))) {
+		goto error;
+	}
+	colr = &box->data.colr;
+	colr->method = JP2_COLR_ENUM;
+	colr->pri = JP2_COLR_PRI;
+	colr->approx = 0;
+	colr->csid = (jas_image_colorspace(image) == JAS_IMAGE_CS_RGB) ? JP2_COLR_SRGB :
+	  JP2_COLR_SGRAY;
+	if (jp2_box_put(box, tmpstream)) {
+		goto error;
+	}
+	jp2_box_destroy(box);
+	box = 0;
+
+	if (!(jas_image_colorspace(image) == JAS_IMAGE_CS_RGB &&
+	  jas_image_numcmpts(image) == 3 &&
+	  jas_image_getcmptbytype(image, 0) ==
+	  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R) &&
+	  jas_image_getcmptbytype(image, 1) ==
+	  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G) &&
+	  jas_image_getcmptbytype(image, 2) ==
+	  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B)) &&
+	  !(jas_image_colorspace(image) == JAS_IMAGE_CS_YCBCR &&
+	  jas_image_numcmpts(image) != 3 &&
+	  jas_image_getcmptbytype(image, 0) ==
+	  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_Y) &&
+	  jas_image_getcmptbytype(image, 1) ==
+	  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_CB) &&
+	  jas_image_getcmptbytype(image, 2) ==
+	  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_CR)) &&
+	  !(jas_image_colorspace(image) == JAS_IMAGE_CS_GRAY &&
+	  jas_image_numcmpts(image) == 1 &&
+	  jas_image_getcmptbytype(image, 0) ==
+	  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y))) {
+
+		if (!(box = jp2_box_create(JP2_BOX_CDEF))) {
+			goto error;
+		}
+		cdef = &box->data.cdef;
+		cdef->numchans = jas_image_numcmpts(image);
+		cdef->ents = jas_malloc(cdef->numchans * sizeof(jp2_cdefchan_t));
+		for (i = 0; i < jas_image_numcmpts(image); ++i) {
+			cdefchanent = &cdef->ents[i];
+			cdefchanent->channo = i;
+			typeasoc = jp2_gettypeasoc(jas_image_colorspace(image), jas_image_cmpttype(image, i));
+			cdefchanent->type = typeasoc >> 16;
+			cdefchanent->assoc = typeasoc & 0x7fff;
+		}
+		jp2_box_destroy(box);
+		box = 0;
+	}
+
+	/* Determine the total length of the JP2 header box. */
+
+	len = jas_stream_tell(tmpstream);
+	jas_stream_rewind(tmpstream);
+
+	/*
+	 * Output the JP2 header box and all of the boxes which it contains.
+	 */
+
+	if (!(box = jp2_box_create(JP2_BOX_JP2H))) {
+		goto error;
+	}
+	box->len = len + JP2_BOX_HDRLEN;
+	if (jp2_box_put(box, out)) {
+		goto error;
+	}
+	jp2_box_destroy(box);
+	box = 0;
+
+	if (jas_stream_copy(out, tmpstream, len)) {
+		goto error;
+	}
+
+	jas_stream_close(tmpstream);
+	tmpstream = 0;
+
+	/*
+	 * Output the contiguous code stream box.
+	 */
+
+	if (!(box = jp2_box_create(JP2_BOX_JP2C))) {
+		goto error;
+	}
+	box->len = 0;
+	if (jp2_box_put(box, out)) {
+		goto error;
+	}
+	jp2_box_destroy(box);
+	box = 0;
+
+	/* Output the JPEG-2000 code stream. */
+
+	overhead = jas_stream_getrwcount(out);
+	sprintf(buf, "%s\n_jp2overhead=%lu\n", (optstr ? optstr : ""),
+	  (unsigned long) overhead);
+
+	if (jpc_encode(image, out, buf)) {
+		goto error;
+	}
+
+	return 0;
+	abort();
+
+error:
+
+	if (box) {
+		jp2_box_destroy(box);
+	}
+	if (tmpstream) {
+		jas_stream_close(tmpstream);
+	}
+	return -1;
+}
+
+
+static uint_fast32_t jp2_gettypeasoc(int colorspace, int ctype)
+{
+	int type;
+	int asoc;
+
+	if (ctype & JAS_IMAGE_CT_OPACITY) {
+		type = JP2_CDEF_TYPE_OPACITY;
+		asoc = JP2_CDEF_ASOC_ALL;
+		goto done;
+	}
+
+	type = JP2_CDEF_TYPE_UNSPEC;
+	asoc = JP2_CDEF_ASOC_NONE;
+	switch (colorspace) {
+	case JAS_IMAGE_CS_RGB:
+		switch (JAS_IMAGE_CT_COLOR(ctype)) {
+		case JAS_IMAGE_CT_RGB_R:
+			type = JP2_CDEF_TYPE_COLOR;
+			asoc = JP2_CDEF_RGB_R;
+			break;
+		case JAS_IMAGE_CT_RGB_G:
+			type = JP2_CDEF_TYPE_COLOR;
+			asoc = JP2_CDEF_RGB_G;
+			break;
+		case JAS_IMAGE_CT_RGB_B:
+			type = JP2_CDEF_TYPE_COLOR;
+			asoc = JP2_CDEF_RGB_B;
+			break;
+		}
+		break;
+	case JAS_IMAGE_CS_YCBCR:
+		switch (JAS_IMAGE_CT_COLOR(ctype)) {
+		case JAS_IMAGE_CT_YCBCR_Y:
+			type = JP2_CDEF_TYPE_COLOR;
+			asoc = JP2_CDEF_YCBCR_Y;
+			break;
+		case JAS_IMAGE_CT_YCBCR_CB:
+			type = JP2_CDEF_TYPE_COLOR;
+			asoc = JP2_CDEF_YCBCR_CB;
+			break;
+		case JAS_IMAGE_CT_YCBCR_CR:
+			type = JP2_CDEF_TYPE_COLOR;
+			asoc = JP2_CDEF_YCBCR_CR;
+			break;
+		}
+		break;
+	case JAS_IMAGE_CS_GRAY:
+		type = JP2_CDEF_TYPE_COLOR;
+		asoc = JP2_CDEF_GRAY_Y;
+		break;
+	}
+
+done:
+	return (type << 16) | asoc;
+}
+
diff --git a/converter/other/jpeg2000/libjasper/jp2/partlist b/converter/other/jpeg2000/libjasper/jp2/partlist
new file mode 100644
index 00000000..26ec4c8a
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jp2/partlist
@@ -0,0 +1 @@
+/mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jp2/jp2_cod.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jp2/jp2_dec.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jp2/jp2_enc.o
diff --git a/converter/other/jpeg2000/libjasper/jpc/Makefile b/converter/other/jpeg2000/libjasper/jpc/Makefile
new file mode 100644
index 00000000..e176bd48
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/Makefile
@@ -0,0 +1,22 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/jpeg2000/libjasper/jpc
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+JASPERSRCDIR=$(SRCDIR)/$(SUBDIR)/..
+
+include $(BUILDDIR)/Makefile.config
+
+LIB_OBJECTS = jpc_bs.o jpc_cs.o jpc_dec.o jpc_enc.o \
+	jpc_math.o jpc_mct.o jpc_mqcod.o jpc_mqdec.o jpc_mqenc.o \
+	jpc_qmfb.o jpc_tagtree.o jpc_t1cod.o jpc_t1dec.o jpc_t1enc.o \
+	jpc_tsfb.o jpc_t2cod.o jpc_t2dec.o jpc_t2enc.o jpc_util.o
+
+MERGE_OBJECTS =
+
+all: partlist $(LIB_OBJECTS)
+
+include $(JASPERSRCDIR)/Makefile.common
+
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c
new file mode 100644
index 00000000..54f0a819
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.c
@@ -0,0 +1,478 @@
+/*
+ * 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__
+ */
+
+/*
+ * Bit Stream Class
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_math.h"
+#include "jasper/jas_debug.h"
+
+#include "jpc_bs.h"
+
+/******************************************************************************\
+* Code for opening and closing bit streams.
+\******************************************************************************/
+
+/* Allocate a new bit stream. */
+static jpc_bitstream_t *jpc_bitstream_alloc()
+{
+	jpc_bitstream_t *bitstream;
+
+	/* Allocate memory for the new bit stream object. */
+	if (!(bitstream = jas_malloc(sizeof(jpc_bitstream_t)))) {
+		return 0;
+	}
+	/* Initialize all of the data members. */
+	bitstream->stream_ = 0;
+	bitstream->cnt_ = 0;
+	bitstream->flags_ = 0;
+	bitstream->openmode_ = 0;
+
+	return bitstream;
+}
+
+/* Open a bit stream from a stream. */
+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;
+	}
+
+	/* By default, do not close the underlying (character) stream, upon
+	  the close of the bit stream. */
+	bitstream->flags_ = JPC_BITSTREAM_NOCLOSE;
+
+	bitstream->stream_ = stream;
+	bitstream->openmode_ = (mode[0] == 'w') ? JPC_BITSTREAM_WRITE :
+	  JPC_BITSTREAM_READ;
+
+	/* Mark the data buffer as empty. */
+	bitstream->cnt_ = (bitstream->openmode_ == JPC_BITSTREAM_READ) ? 0 : 8;
+	bitstream->buf_ = 0;
+
+	return bitstream;
+}
+
+/* Close a bit stream. */
+int jpc_bitstream_close(jpc_bitstream_t *bitstream)
+{
+	int ret = 0;
+
+	/* Align to the next byte boundary while considering the effects of
+	  bit stuffing. */
+	if (jpc_bitstream_align(bitstream)) {
+		ret = -1;
+	}
+
+	/* If necessary, close the underlying (character) stream. */
+	if (!(bitstream->flags_ & JPC_BITSTREAM_NOCLOSE) && bitstream->stream_) {
+		if (jas_stream_close(bitstream->stream_)) {
+			ret = -1;
+		}
+		bitstream->stream_ = 0;
+	}
+
+	jas_free(bitstream);
+	return ret;
+}
+
+/******************************************************************************\
+* Code for reading/writing from/to bit streams.
+\******************************************************************************/
+
+/* Get a bit from a bit stream. */
+int jpc_bitstream_getbit_func(jpc_bitstream_t *bitstream)
+{
+	int ret;
+	JAS_DBGLOG(1000, ("jpc_bitstream_getbit_func(%p)\n", bitstream));
+	ret = jpc_bitstream_getbit_macro(bitstream);
+	JAS_DBGLOG(1000, ("jpc_bitstream_getbit_func -> %d\n", ret));
+	return ret;
+}
+
+/* Put a bit to a bit stream. */
+int jpc_bitstream_putbit_func(jpc_bitstream_t *bitstream, int b)
+{
+	int ret;
+	JAS_DBGLOG(1000, ("jpc_bitstream_putbit_func(%p, %d)\n", bitstream, b));
+	ret = jpc_bitstream_putbit_macro(bitstream, b);
+	JAS_DBGLOG(1000, ("jpc_bitstream_putbit_func() -> %d\n", ret));
+	return ret;
+}
+
+/* Get one or more bits from a bit stream. */
+long jpc_bitstream_getbits(jpc_bitstream_t *bitstream, int n)
+{
+	long v;
+	int u;
+
+	/* We can reliably get at most 31 bits since ISO/IEC 9899 only
+	  guarantees that a long can represent values up to 2^31-1. */
+	assert(n >= 0 && n < 32);
+
+	/* Get the number of bits requested from the specified bit stream. */
+	v = 0;
+	while (--n >= 0) {
+		if ((u = jpc_bitstream_getbit(bitstream)) < 0) {
+			return -1;
+		}
+		v = (v << 1) | u;
+	}
+	return v;
+}
+
+/* Put one or more bits to a bit stream. */
+int jpc_bitstream_putbits(jpc_bitstream_t *bitstream, int n, long v)
+{
+	int m;
+
+	/* We can reliably put at most 31 bits since ISO/IEC 9899 only
+	  guarantees that a long can represent values up to 2^31-1. */
+	assert(n >= 0 && n < 32);
+	/* Ensure that only the bits to be output are nonzero. */
+	assert(!(v & (~JAS_ONES(n))));
+
+	/* Put the desired number of bits to the specified bit stream. */
+	m = n - 1;
+	while (--n >= 0) {
+		if (jpc_bitstream_putbit(bitstream, (v >> m) & 1) == EOF) {
+			return EOF;
+		}
+		v <<= 1;
+	}
+	return 0;
+}
+
+/******************************************************************************\
+* Code for buffer filling and flushing.
+\******************************************************************************/
+
+/* Fill the buffer for a bit stream. */
+int jpc_bitstream_fillbuf(jpc_bitstream_t *bitstream)
+{
+	int c;
+	/* Note: The count has already been decremented by the caller. */
+	assert(bitstream->openmode_ & JPC_BITSTREAM_READ);
+	assert(bitstream->cnt_ <= 0);
+
+	if (bitstream->flags_ & JPC_BITSTREAM_ERR) {
+		bitstream->cnt_ = 0;
+		return -1;
+	}
+
+	if (bitstream->flags_ & JPC_BITSTREAM_EOF) {
+		bitstream->buf_ = 0x7f;
+		bitstream->cnt_ = 7;
+		return 1;
+	}
+
+	bitstream->buf_ = (bitstream->buf_ << 8) & 0xffff;
+	if ((c = jas_stream_getc((bitstream)->stream_)) == EOF) {
+		bitstream->flags_ |= JPC_BITSTREAM_EOF;
+		return 1;
+	}
+	bitstream->cnt_ = (bitstream->buf_ == 0xff00) ? 6 : 7;
+	bitstream->buf_ |= c & ((1 << (bitstream->cnt_ + 1)) - 1);
+	return (bitstream->buf_ >> bitstream->cnt_) & 1;
+}
+
+
+/******************************************************************************\
+* Code related to flushing.
+\******************************************************************************/
+
+/* Does the bit stream need to be aligned to a byte boundary (considering
+  the effects of bit stuffing)? */
+int jpc_bitstream_needalign(jpc_bitstream_t *bitstream)
+{
+	if (bitstream->openmode_ & JPC_BITSTREAM_READ) {
+		/* The bit stream is open for reading. */
+		/* If there are any bits buffered for reading, or the
+		  previous byte forced a stuffed bit, alignment is
+		  required. */
+		if ((bitstream->cnt_ < 8 && bitstream->cnt_ > 0) ||
+		  ((bitstream->buf_ >> 8) & 0xff) == 0xff) {
+			return 1;
+		}
+	} else if (bitstream->openmode_ & JPC_BITSTREAM_WRITE) {
+		/* The bit stream is open for writing. */
+		/* If there are any bits buffered for writing, or the
+		  previous byte forced a stuffed bit, alignment is
+		  required. */
+		if ((bitstream->cnt_ < 8 && bitstream->cnt_ >= 0) ||
+		  ((bitstream->buf_ >> 8) & 0xff) == 0xff) {
+			return 1;
+		}
+	} else {
+		/* This should not happen.  Famous last words, eh? :-) */
+		assert(0);
+		return -1;
+	}
+	return 0;
+}
+
+/* How many additional bytes would be output if we align the bit stream? */
+int jpc_bitstream_pending(jpc_bitstream_t *bitstream)
+{
+	if (bitstream->openmode_ & JPC_BITSTREAM_WRITE) {
+		/* The bit stream is being used for writing. */
+#if 1
+		/* XXX - Is this really correct?  Check someday... */
+		if (bitstream->cnt_ < 8) {
+			return 1;
+		}
+#else
+		if (bitstream->cnt_ < 8) {
+			if (((bitstream->buf_ >> 8) & 0xff) == 0xff) {
+				return 2;
+			}
+			return 1;
+		}
+#endif
+		return 0;
+	} else {
+		/* This operation should not be invoked on a bit stream that
+		  is being used for reading. */
+		return -1;
+	}
+}
+
+/* Align the bit stream to a byte boundary. */
+int jpc_bitstream_align(jpc_bitstream_t *bitstream)
+{
+	int ret;
+	if (bitstream->openmode_ & JPC_BITSTREAM_READ) {
+		ret = jpc_bitstream_inalign(bitstream, 0, 0);
+	} else if (bitstream->openmode_ & JPC_BITSTREAM_WRITE) {
+		ret = jpc_bitstream_outalign(bitstream, 0);
+	}
+	return ret;
+}
+
+/* Align a bit stream in the input case. */
+int jpc_bitstream_inalign(jpc_bitstream_t *bitstream, int fillmask,
+  int filldata)
+{
+	int n;
+	int v;
+	int u;
+	int numfill;
+	int m;
+
+	numfill = 7;
+	m = 0;
+	v = 0;
+	if (bitstream->cnt_ > 0) {
+		n = bitstream->cnt_;
+	} else if (!bitstream->cnt_) {
+		n = ((bitstream->buf_ & 0xff) == 0xff) ? 7 : 0;
+	} else {
+		n = 0;
+	}
+	if (n > 0) {
+		if ((u = jpc_bitstream_getbits(bitstream, n)) < 0) {
+			return -1;
+		}
+		m += n;
+		v = (v << n) | u;
+	}
+	if ((bitstream->buf_ & 0xff) == 0xff) {
+		if ((u = jpc_bitstream_getbits(bitstream, 7)) < 0) {
+			return -1;
+		}
+		v = (v << 7) | u;
+		m += 7;
+	}
+	if (m > numfill) {
+		v >>= m - numfill;
+	} else {
+		filldata >>= numfill - m;
+		fillmask >>= numfill - m;
+	}
+	if (((~(v ^ filldata)) & fillmask) != fillmask) {
+		/* The actual fill pattern does not match the expected one. */
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Align a bit stream in the output case. */
+int jpc_bitstream_outalign(jpc_bitstream_t *bitstream, int filldata)
+{
+	int n;
+	int v;
+
+	/* Ensure that this bit stream is open for writing. */
+	assert(bitstream->openmode_ & JPC_BITSTREAM_WRITE);
+
+	/* Ensure that the first bit of fill data is zero. */
+	/* Note: The first bit of fill data must be zero.  If this were not
+	  the case, the fill data itself could cause further bit stuffing to
+	  be required (which would cause numerous complications). */
+	assert(!(filldata & (~0x3f)));
+
+	if (!bitstream->cnt_) {
+		if ((bitstream->buf_ & 0xff) == 0xff) {
+			n = 7;
+			v = filldata;
+		} else {
+			n = 0;
+			v = 0;
+		}
+	} else if (bitstream->cnt_ > 0 && bitstream->cnt_ < 8) {
+		n = bitstream->cnt_;
+		v = filldata >> (7 - n);
+	} else {
+		n = 0;
+		v = 0;
+		return 0;
+	}
+
+	/* Write the appropriate fill data to the bit stream. */
+	if (n > 0) {
+		if (jpc_bitstream_putbits(bitstream, n, v)) {
+			return -1;
+		}
+	}
+	if (bitstream->cnt_ < 8) {
+		assert(bitstream->cnt_ >= 0 && bitstream->cnt_ < 8);
+		assert((bitstream->buf_ & 0xff) != 0xff);
+		/* Force the pending byte of output to be written to the
+		  underlying (character) stream. */
+		if (jas_stream_putc(bitstream->stream_, bitstream->buf_ & 0xff) == EOF) {
+			return -1;
+		}
+		bitstream->cnt_ = 8;
+		bitstream->buf_ = (bitstream->buf_ << 8) & 0xffff;
+	}
+
+	return 0;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h
new file mode 100644
index 00000000..f515972b
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_bs.h
@@ -0,0 +1,280 @@
+/*
+ * 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__
+ */
+
+/*
+ * Bit Stream Class
+ *
+ * $Id$
+ */
+
+#ifndef JPC_BS_H
+#define JPC_BS_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_stream.h"
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/*
+ * Bit stream open mode flags.
+ */
+
+/* Bit stream open for reading. */
+#define	JPC_BITSTREAM_READ	0x01
+/* Bit stream open for writing. */
+#define	JPC_BITSTREAM_WRITE	0x02
+
+/*
+ * Bit stream flags.
+ */
+
+/* Do not close underlying character stream. */
+#define	JPC_BITSTREAM_NOCLOSE	0x01
+/* End of file has been reached while reading. */
+#define	JPC_BITSTREAM_EOF	0x02
+/* An I/O error has occured. */
+#define	JPC_BITSTREAM_ERR	0x04
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/* Bit stream class. */
+
+typedef struct {
+
+	/* Some miscellaneous flags. */
+	int flags_;
+
+	/* The input/output buffer. */
+	uint_fast16_t buf_;
+
+	/* The number of bits remaining in the byte being read/written. */
+	int cnt_;
+
+	/* The underlying stream associated with this bit stream. */
+	jas_stream_t *stream_;
+
+	/* The mode in which this bit stream was opened. */
+	int openmode_;
+
+} jpc_bitstream_t;
+
+/******************************************************************************\
+* Functions/macros for opening and closing bit streams..
+\******************************************************************************/
+
+/* Open a stream as a bit stream. */
+jpc_bitstream_t *jpc_bitstream_sopen(jas_stream_t *stream, const char *mode);
+
+/* Close a bit stream. */
+int jpc_bitstream_close(jpc_bitstream_t *bitstream);
+
+/******************************************************************************\
+* Functions/macros for reading from and writing to bit streams..
+\******************************************************************************/
+
+/* Read a bit from a bit stream. */
+#if defined(DEBUG)
+#define	jpc_bitstream_getbit(bitstream) \
+	jpc_bitstream_getbit_func(bitstream)
+#else
+#define jpc_bitstream_getbit(bitstream) \
+	jpc_bitstream_getbit_macro(bitstream)
+#endif
+
+/* Write a bit to a bit stream. */
+#if defined(DEBUG)
+#define	jpc_bitstream_putbit(bitstream, v) \
+	jpc_bitstream_putbit_func(bitstream, v)
+#else
+#define	jpc_bitstream_putbit(bitstream, v) \
+	jpc_bitstream_putbit_macro(bitstream, v)
+#endif
+
+/* Read one or more bits from a bit stream. */
+long jpc_bitstream_getbits(jpc_bitstream_t *bitstream, int n);
+
+/* Write one or more bits to a bit stream. */
+int jpc_bitstream_putbits(jpc_bitstream_t *bitstream, int n, long v);
+
+/******************************************************************************\
+* Functions/macros for flushing and aligning bit streams.
+\******************************************************************************/
+
+/* Align the current position within the bit stream to the next byte
+  boundary. */
+int jpc_bitstream_align(jpc_bitstream_t *bitstream);
+
+/* Align the current position in the bit stream with the next byte boundary,
+  ensuring that certain bits consumed in the process match a particular
+  pattern. */
+int jpc_bitstream_inalign(jpc_bitstream_t *bitstream, int fillmask,
+  int filldata);
+
+/* Align the current position in the bit stream with the next byte boundary,
+  writing bits from the specified pattern (if necessary) in the process. */
+int jpc_bitstream_outalign(jpc_bitstream_t *bitstream, int filldata);
+
+/* Check if a bit stream needs alignment. */
+int jpc_bitstream_needalign(jpc_bitstream_t *bitstream);
+
+/* How many additional bytes would be output if the bit stream was aligned? */
+int jpc_bitstream_pending(jpc_bitstream_t *bitstream);
+
+/******************************************************************************\
+* Functions/macros for querying state information for bit streams.
+\******************************************************************************/
+
+/* Has EOF been encountered on a bit stream? */
+#define jpc_bitstream_eof(bitstream) \
+	((bitstream)->flags_ & JPC_BITSTREAM_EOF)
+
+/******************************************************************************\
+* Internals.
+\******************************************************************************/
+
+/* DO NOT DIRECTLY INVOKE ANY OF THE MACROS OR FUNCTIONS BELOW.  THEY ARE
+  FOR INTERNAL USE ONLY. */
+
+int jpc_bitstream_getbit_func(jpc_bitstream_t *bitstream);
+
+int jpc_bitstream_putbit_func(jpc_bitstream_t *bitstream, int v);
+
+int jpc_bitstream_fillbuf(jpc_bitstream_t *bitstream);
+
+#define	jpc_bitstream_getbit_macro(bitstream) \
+	(assert((bitstream)->openmode_ & JPC_BITSTREAM_READ), \
+	  (--(bitstream)->cnt_ >= 0) ? \
+	  (((bitstream)->buf_ >> (bitstream)->cnt_) & 1) : \
+	  jpc_bitstream_fillbuf(bitstream))
+
+#define jpc_bitstream_putbit_macro(bitstream, bit) \
+	(assert((bitstream)->openmode_ & JPC_BITSTREAM_WRITE), \
+	  (--(bitstream)->cnt_ < 0) ? \
+	  ((bitstream)->buf_ = ((bitstream)->buf_ << 8) & 0xffff, \
+	  (bitstream)->cnt_ = ((bitstream)->buf_ == 0xff00) ? 6 : 7, \
+	  (bitstream)->buf_ |= ((bit) & 1) << (bitstream)->cnt_, \
+	  (jas_stream_putc((bitstream)->stream_, (bitstream)->buf_ >> 8) == EOF) \
+	  ? (EOF) : ((bit) & 1)) : \
+	  ((bitstream)->buf_ |= ((bit) & 1) << (bitstream)->cnt_, \
+	  (bit) & 1))
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_cod.h b/converter/other/jpeg2000/libjasper/jpc/jpc_cod.h
new file mode 100644
index 00000000..9b3ddbee
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_cod.h
@@ -0,0 +1,127 @@
+/*
+ * 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$
+ */
+
+#ifndef JPC_COD_H
+#define JPC_COD_H
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/* The nominal word size used by this implementation. */
+#define	JPC_PREC	32
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c
new file mode 100644
index 00000000..63cf8ba7
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.c
@@ -0,0 +1,1614 @@
+/*
+ * 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__
+ */
+
+/*
+ * JPEG-2000 Code Stream Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_debug.h"
+
+#include "jpc_cs.h"
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/* Marker segment table entry. */
+typedef struct {
+	int id;
+	const char *name;
+	jpc_msops_t ops;
+} jpc_mstabent_t;
+
+/******************************************************************************\
+* Local prototypes.
+\******************************************************************************/
+
+static jpc_mstabent_t *jpc_mstab_lookup(int id);
+
+static int jpc_poc_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_poc_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_poc_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static void jpc_poc_destroyparms(jpc_ms_t *ms);
+
+static int jpc_unk_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_sot_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_siz_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_cod_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_coc_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_qcd_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_qcc_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_rgn_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_sop_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_ppm_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_ppt_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_crg_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+static int jpc_com_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+
+static int jpc_sot_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_siz_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_cod_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_coc_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_qcd_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_qcc_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_rgn_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_unk_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_sop_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_ppm_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_ppt_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_crg_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+static int jpc_com_putparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+
+static int jpc_sot_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_siz_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_cod_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_coc_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_qcd_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_qcc_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_rgn_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_unk_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_sop_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_ppm_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_ppt_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_crg_dumpparms(jpc_ms_t *ms, FILE *out);
+static int jpc_com_dumpparms(jpc_ms_t *ms, FILE *out);
+
+static void jpc_siz_destroyparms(jpc_ms_t *ms);
+static void jpc_qcd_destroyparms(jpc_ms_t *ms);
+static void jpc_qcc_destroyparms(jpc_ms_t *ms);
+static void jpc_cod_destroyparms(jpc_ms_t *ms);
+static void jpc_coc_destroyparms(jpc_ms_t *ms);
+static void jpc_unk_destroyparms(jpc_ms_t *ms);
+static void jpc_ppm_destroyparms(jpc_ms_t *ms);
+static void jpc_ppt_destroyparms(jpc_ms_t *ms);
+static void jpc_crg_destroyparms(jpc_ms_t *ms);
+static void jpc_com_destroyparms(jpc_ms_t *ms);
+
+static void jpc_qcx_destroycompparms(jpc_qcxcp_t *compparms);
+static int jpc_qcx_getcompparms(jpc_qcxcp_t *compparms, jpc_cstate_t *cstate,
+  jas_stream_t *in, uint_fast16_t len);
+static int jpc_qcx_putcompparms(jpc_qcxcp_t *compparms, jpc_cstate_t *cstate,
+  jas_stream_t *out);
+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);
+static int jpc_cox_putcompparms(jpc_ms_t *ms, jpc_cstate_t *cstate,
+  jas_stream_t *out, int prtflag, jpc_coxcp_t *compparms);
+
+/******************************************************************************\
+* Global data.
+\******************************************************************************/
+
+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}}
+};
+
+/******************************************************************************\
+* Code stream manipulation functions.
+\******************************************************************************/
+
+/* 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;
+}
+
+/* Destroy a code stream state object. */
+void jpc_cstate_destroy(jpc_cstate_t *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;
+}
+
+/* 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;
+}
+
+/******************************************************************************\
+* Marker segment operations.
+\******************************************************************************/
+
+/* Create a marker segment of the specified type. */
+jpc_ms_t *jpc_ms_create(int type)
+{
+	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;
+}
+
+/* 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);
+}
+
+/* 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");
+	}
+}
+
+/******************************************************************************\
+* SOT marker segment operations.
+\******************************************************************************/
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* SIZ marker segment operations.
+\******************************************************************************/
+
+static void jpc_siz_destroyparms(jpc_ms_t *ms)
+{
+	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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* 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);
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* 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);
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+/******************************************************************************\
+* COD/COC marker segment operation helper functions.
+\******************************************************************************/
+
+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;
+		}
+/* 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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* RGN marker segment operations.
+\******************************************************************************/
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* QCD marker segment operations.
+\******************************************************************************/
+
+static void jpc_qcd_destroyparms(jpc_ms_t *ms)
+{
+	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);
+}
+
+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);
+}
+
+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;
+}
+
+/******************************************************************************\
+* QCC marker segment operations.
+\******************************************************************************/
+
+static void jpc_qcc_destroyparms(jpc_ms_t *ms)
+{
+	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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* QCD/QCC marker segment helper functions.
+\******************************************************************************/
+
+static void jpc_qcx_destroycompparms(jpc_qcxcp_t *compparms)
+{
+	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;
+	}
+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]);
+		}
+	}
+} else {
+	compparms->stepsizes = 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;
+}
+
+/******************************************************************************\
+* SOP marker segment operations.
+\******************************************************************************/
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* PPM marker segment operations.
+\******************************************************************************/
+
+static void jpc_ppm_destroyparms(jpc_ms_t *ms)
+{
+	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;
+
+error:
+	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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* PPT marker segment operations.
+\******************************************************************************/
+
+static void jpc_ppt_destroyparms(jpc_ms_t *ms)
+{
+	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;
+
+error:
+	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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* 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);
+	}
+}
+
+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;
+
+error:
+	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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* CRG marker segment operations.
+\******************************************************************************/
+
+static void jpc_crg_destroyparms(jpc_ms_t *ms)
+{
+	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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* Operations for COM marker segment.
+\******************************************************************************/
+
+static void jpc_com_destroyparms(jpc_ms_t *ms)
+{
+	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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* 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);
+	}
+}
+
+static int jpc_unk_getparms(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in)
+{
+	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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* Primitive I/O operations.
+\******************************************************************************/
+
+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 jpc_putuint8(jas_stream_t *out, uint_fast8_t val)
+{
+	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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* Miscellany
+\******************************************************************************/
+
+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;
+}
+
+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 jpc_getdata(jas_stream_t *in, jas_stream_t *out, long 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);
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h
new file mode 100644
index 00000000..07a046d1
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_cs.h
@@ -0,0 +1,812 @@
+/*
+ * 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__
+ */
+
+/*
+ * JPEG-2000 Code Stream Library
+ *
+ * $Id$
+ */
+
+#ifndef JPC_CS_H
+#define JPC_CS_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_image.h"
+#include "jasper/jas_stream.h"
+
+#include "jpc_cod.h"
+
+/******************************************************************************\
+* Constants and Types.
+\******************************************************************************/
+
+/* The maximum number of resolution levels. */
+#define	JPC_MAXRLVLS	33
+
+/* The maximum number of bands. */
+#define	JPC_MAXBANDS	(3 * JPC_MAXRLVLS + 1)
+
+/* The maximum number of layers. */
+#define JPC_MAXLYRS	16384
+
+/**************************************\
+* Code stream.
+\**************************************/
+
+/*
+ * Code stream states.
+ */
+
+/* Initial. */
+#define	JPC_CS_INIT	0
+/* Main header. */
+#define	JPC_CS_MHDR	1
+/* Tile-part header. */
+#define	JPC_CS_THDR	2
+/* Main trailer. */
+#define	JPC_CS_MTLR	3
+/* Tile-part data. */
+#define	JPC_CS_TDATA	4
+
+/*
+ * Unfortunately, the code stream syntax was not designed in such a way that
+ * any given marker segment can be correctly decoded without additional state
+ * derived from previously decoded marker segments.
+ * For example, a RGN/COC/QCC marker segment cannot be decoded unless the
+ * number of components is known.
+ */
+
+/*
+ * Code stream state information.
+ */
+
+typedef struct {
+
+	/* The number of components. */
+	int numcomps;
+
+} jpc_cstate_t;
+
+/**************************************\
+* SOT marker segment parameters.
+\**************************************/
+
+typedef struct {
+
+	/* The tile number. */
+	uint_fast16_t tileno;
+
+	/* The combined length of the marker segment and its auxilary data
+	  (i.e., packet data). */
+	uint_fast32_t len;
+
+	/* The tile-part instance. */
+	uint_fast8_t partno;
+
+	/* The number of tile-parts. */
+	uint_fast8_t numparts;
+
+} jpc_sot_t;
+
+/**************************************\
+* SIZ marker segment parameters.
+\**************************************/
+
+/* Per component information. */
+
+typedef struct {
+
+	/* The precision of the samples. */
+	uint_fast8_t prec;
+
+	/* The signedness of the samples. */
+	uint_fast8_t sgnd;
+
+	/* The horizontal separation of samples with respect to the reference
+	  grid. */
+	uint_fast8_t hsamp;
+
+	/* The vertical separation of samples with respect to the reference
+	  grid. */
+	uint_fast8_t vsamp;
+
+} jpc_sizcomp_t;
+
+/* SIZ marker segment parameters. */
+
+typedef struct {
+
+	/* The code stream capabilities. */
+	uint_fast16_t caps;
+
+	/* The width of the image in units of the reference grid. */
+	uint_fast32_t width;
+
+	/* The height of the image in units of the reference grid. */
+	uint_fast32_t height;
+
+	/* The horizontal offset from the origin of the reference grid to the
+	  left side of the image area. */
+	uint_fast32_t xoff;
+
+	/* The vertical offset from the origin of the reference grid to the
+	  top side of the image area. */
+	uint_fast32_t yoff;
+
+	/* The nominal width of a tile in units of the reference grid. */
+	uint_fast32_t tilewidth;
+
+	/* The nominal height of a tile in units of the reference grid. */
+	uint_fast32_t tileheight;
+
+	/* The horizontal offset from the origin of the reference grid to the
+	  left side of the first tile. */
+	uint_fast32_t tilexoff;
+
+	/* The vertical offset from the origin of the reference grid to the
+	  top side of the first tile. */
+	uint_fast32_t tileyoff;
+
+	/* The number of components. */
+	uint_fast16_t numcomps;
+
+	/* The per-component information. */
+	jpc_sizcomp_t *comps;
+
+} jpc_siz_t;
+
+/**************************************\
+* COD marker segment parameters.
+\**************************************/
+
+/*
+ * Coding style constants.
+ */
+
+/* Precincts may be used. */
+#define	JPC_COX_PRT	0x01
+/* SOP marker segments may be used. */
+#define	JPC_COD_SOP	0x02
+/* EPH marker segments may be used. */
+#define	JPC_COD_EPH	0x04
+
+/*
+ * Progression order constants.
+ */
+
+/* Layer-resolution-component-precinct progressive
+  (i.e., progressive by fidelity). */
+#define	JPC_COD_LRCPPRG	0
+/* Resolution-layer-component-precinct progressive
+  (i.e., progressive by resolution). */
+#define	JPC_COD_RLCPPRG	1
+/* Resolution-precinct-component-layer progressive. */
+#define	JPC_COD_RPCLPRG	2
+/* Precinct-component-resolution-layer progressive. */
+#define	JPC_COD_PCRLPRG	3
+/* Component-position-resolution-layer progressive. */
+#define	JPC_COD_CPRLPRG	4
+
+/*
+ * Code block style constants.
+ */
+
+#define	JPC_COX_LAZY	0x01 /* Selective arithmetic coding bypass. */
+#define	JPC_COX_RESET	0x02 /* Reset context probabilities. */
+#define	JPC_COX_TERMALL	0x04 /* Terminate all coding passes. */
+#define	JPC_COX_VSC		0x08 /* Vertical stripe causal context formation. */
+#define	JPC_COX_PTERM	0x10 /* Predictable termination. */
+#define	JPC_COX_SEGSYM	0x20 /* Use segmentation symbols. */
+
+/* Transform constants. */
+#define	JPC_COX_INS	0x00 /* Irreversible 9/7. */
+#define	JPC_COX_RFT	0x01 /* Reversible 5/3. */
+
+/* Multicomponent transform constants. */
+#define	JPC_COD_NOMCT	0x00 /* No multicomponent transform. */
+#define	JPC_COD_MCT		0x01 /* Multicomponent transform. */
+
+/* Get the code block size value from the code block size exponent. */
+#define	JPC_COX_CBLKSIZEEXPN(x)		((x) - 2)
+/* Get the code block size exponent from the code block size value. */
+#define	JPC_COX_GETCBLKSIZEEXPN(x)	((x) + 2)
+
+/* Per resolution-level information. */
+
+typedef struct {
+
+	/* The packet partition width. */
+	uint_fast8_t parwidthval;
+
+	/* The packet partition height. */
+	uint_fast8_t parheightval;
+
+} jpc_coxrlvl_t;
+
+/* Per component information. */
+
+typedef struct {
+
+	/* The coding style. */
+	uint_fast8_t csty;
+
+	/* The number of decomposition levels. */
+	uint_fast8_t numdlvls;
+
+	/* The nominal code block width specifier. */
+	uint_fast8_t cblkwidthval;
+
+	/* The nominal code block height specifier. */
+	uint_fast8_t cblkheightval;
+
+	/* The style of coding passes. */
+	uint_fast8_t cblksty;
+
+	/* The QMFB employed. */
+	uint_fast8_t qmfbid;
+
+	/* The number of resolution levels. */
+	int numrlvls;
+
+	/* The per-resolution-level information. */
+	jpc_coxrlvl_t rlvls[JPC_MAXRLVLS];
+
+} jpc_coxcp_t;
+
+/* COD marker segment parameters. */
+
+typedef struct {
+
+	/* The general coding style. */
+	uint_fast8_t csty;
+
+	/* The progression order. */
+	uint_fast8_t prg;
+
+	/* The number of layers. */
+	uint_fast16_t numlyrs;
+
+	/* The multicomponent transform. */
+	uint_fast8_t mctrans;
+
+	/* Component-related parameters. */
+	jpc_coxcp_t compparms;
+
+} jpc_cod_t;
+
+/* COC marker segment parameters. */
+
+typedef struct {
+
+	/* The component number. */
+	uint_fast16_t compno;
+
+	/* Component-related parameters. */
+	jpc_coxcp_t compparms;
+
+} jpc_coc_t;
+
+/**************************************\
+* RGN marker segment parameters.
+\**************************************/
+
+/* The maxshift ROI style. */
+#define	JPC_RGN_MAXSHIFT	0x00
+
+typedef struct {
+
+	/* The component to which the marker applies. */
+	uint_fast16_t compno;
+
+	/* The ROI style. */
+	uint_fast8_t roisty;
+
+	/* The ROI shift value. */
+	uint_fast8_t roishift;
+
+} jpc_rgn_t;
+
+/**************************************\
+* QCD/QCC marker segment parameters.
+\**************************************/
+
+/*
+ * Quantization style constants.
+ */
+
+#define	JPC_QCX_NOQNT	0 /* No quantization. */
+#define	JPC_QCX_SIQNT	1 /* Scalar quantization, implicit. */
+#define	JPC_QCX_SEQNT	2 /* Scalar quantization, explicit. */
+
+/*
+ * Stepsize manipulation macros.
+ */
+
+#define	JPC_QCX_GETEXPN(x)	((x) >> 11)
+#define	JPC_QCX_GETMANT(x)	((x) & 0x07ff)
+#define	JPC_QCX_EXPN(x)		(assert(!((x) & (~0x1f))), (((x) & 0x1f) << 11))
+#define	JPC_QCX_MANT(x)		(assert(!((x) & (~0x7ff))), ((x) & 0x7ff))
+
+/* Per component information. */
+
+typedef struct {
+
+	/* The quantization style. */
+	uint_fast8_t qntsty;
+
+	/* The number of step sizes. */
+	int numstepsizes;
+
+	/* The step sizes. */
+	uint_fast16_t *stepsizes;
+
+	/* The number of guard bits. */
+	uint_fast8_t numguard;
+
+} jpc_qcxcp_t;
+
+/* QCC marker segment parameters. */
+
+typedef struct {
+
+	/* The component associated with this marker segment. */
+	uint_fast16_t compno;
+
+	/* The parameters. */
+	jpc_qcxcp_t compparms;
+
+} jpc_qcc_t;
+
+/* QCD marker segment parameters. */
+
+typedef struct {
+
+	/* The parameters. */
+	jpc_qcxcp_t compparms;
+
+} jpc_qcd_t;
+
+/**************************************\
+* POD marker segment parameters.
+\**************************************/
+
+typedef struct {
+
+	/* The progression order. */
+	uint_fast8_t prgord;
+
+	/* The lower bound (inclusive) on the resolution level for the
+	  progression order volume. */
+	uint_fast8_t rlvlnostart;
+
+	/* The upper bound (exclusive) on the resolution level for the
+	  progression order volume. */
+	uint_fast8_t rlvlnoend;
+
+	/* The lower bound (inclusive) on the component for the progression
+	  order volume. */
+	uint_fast16_t compnostart;
+
+	/* The upper bound (exclusive) on the component for the progression
+	  order volume. */
+	uint_fast16_t compnoend;
+
+	/* The upper bound (exclusive) on the layer for the progression
+	  order volume. */
+	uint_fast16_t lyrnoend;
+
+} jpc_pocpchg_t;
+
+/* An alias for the above type. */
+typedef jpc_pocpchg_t jpc_pchg_t;
+
+/* POC marker segment parameters. */
+
+typedef struct {
+
+	/* The number of progression order changes. */
+	int numpchgs;
+
+	/* The per-progression-order-change information. */
+	jpc_pocpchg_t *pchgs;
+
+} jpc_poc_t;
+
+/**************************************\
+* PPM/PPT marker segment parameters.
+\**************************************/
+
+/* PPM marker segment parameters. */
+
+typedef struct {
+
+	/* The index. */
+	uint_fast8_t ind;
+
+	/* The length. */
+	uint_fast16_t len;
+
+	/* The data. */
+	unsigned char *data;
+
+} jpc_ppm_t;
+
+/* PPT marker segment parameters. */
+
+typedef struct {
+
+	/* The index. */
+	uint_fast8_t ind;
+
+	/* The length. */
+	uint_fast32_t len;
+
+	/* The data. */
+	unsigned char *data;
+
+} jpc_ppt_t;
+
+/**************************************\
+* COM marker segment parameters.
+\**************************************/
+
+/*
+ * Registration IDs.
+ */
+
+#define	JPC_COM_BIN		0x00
+#define	JPC_COM_LATIN	0x01
+
+typedef struct {
+
+	/* The registration ID. */
+	uint_fast16_t regid;
+
+	/* The length of the data in bytes. */
+	uint_fast16_t len;
+
+	/* The data. */
+	unsigned char *data;
+
+} jpc_com_t;
+
+/**************************************\
+* SOP marker segment parameters.
+\**************************************/
+
+typedef struct {
+
+	/* The sequence number. */
+	uint_fast16_t seqno;
+
+} jpc_sop_t;
+
+/**************************************\
+* CRG marker segment parameters.
+\**************************************/
+
+/* Per component information. */
+
+typedef struct {
+
+	/* The horizontal offset. */
+	uint_fast16_t hoff;
+
+	/* The vertical offset. */
+	uint_fast16_t voff;
+
+} jpc_crgcomp_t;
+
+typedef struct {
+
+	/* The number of components. */
+	int numcomps;
+
+	/* Per component information. */
+	jpc_crgcomp_t *comps;
+
+} jpc_crg_t;
+
+/**************************************\
+* Marker segment parameters for unknown marker type.
+\**************************************/
+
+typedef struct {
+
+	/* The data. */
+	unsigned char *data;
+
+	/* The length. */
+	uint_fast16_t len;
+
+} jpc_unk_t;
+
+/**************************************\
+* Generic marker segment parameters.
+\**************************************/
+
+typedef union {
+	int soc;	/* unused */
+	jpc_sot_t sot;
+	int sod;	/* unused */
+	int eoc;	/* unused */
+	jpc_siz_t siz;
+	jpc_cod_t cod;
+	jpc_coc_t coc;
+	jpc_rgn_t rgn;
+	jpc_qcd_t qcd;
+	jpc_qcc_t qcc;
+	jpc_poc_t poc;
+	/* jpc_plm_t plm; */
+	/* jpc_plt_t plt; */
+	jpc_ppm_t ppm;
+	jpc_ppt_t ppt;
+	jpc_sop_t sop;
+	int eph;	/* unused */
+	jpc_com_t com;
+	jpc_crg_t crg;
+	jpc_unk_t unk;
+} jpc_msparms_t;
+
+/**************************************\
+* Marker segment.
+\**************************************/
+
+/* Marker segment IDs. */
+
+/* The smallest valid marker value. */
+#define	JPC_MS_MIN	0xff00
+
+/* The largest valid marker value. */
+#define	JPC_MS_MAX	0xffff
+
+/* The minimum marker value that cannot occur within packet data. */
+#define	JPC_MS_INMIN	0xff80
+/* The maximum marker value that cannot occur within packet data. */
+#define	JPC_MS_INMAX	0xffff
+
+/* Delimiting marker segments. */
+#define	JPC_MS_SOC	0xff4f /* Start of code stream (SOC). */
+#define	JPC_MS_SOT	0xff90 /* Start of tile-part (SOT). */
+#define	JPC_MS_SOD	0xff93 /* Start of data (SOD). */
+#define	JPC_MS_EOC	0xffd9 /* End of code stream (EOC). */
+
+/* Fixed information marker segments. */
+#define	JPC_MS_SIZ	0xff51 /* Image and tile size (SIZ). */
+
+/* Functional marker segments. */
+#define	JPC_MS_COD	0xff52 /* Coding style default (COD). */
+#define JPC_MS_COC	0xff53 /* Coding style component (COC). */
+#define	JPC_MS_RGN	0xff5e /* Region of interest (RGN). */
+#define JPC_MS_QCD	0xff5c /* Quantization default (QCD). */
+#define JPC_MS_QCC	0xff5d /* Quantization component (QCC). */
+#define JPC_MS_POC	0xff5f /* Progression order default (POC). */
+
+/* Pointer marker segments. */
+#define	JPC_MS_TLM	0xff55 /* Tile-part lengths, main header (TLM). */
+#define	JPC_MS_PLM	0xff57 /* Packet length, main header (PLM). */
+#define	JPC_MS_PLT	0xff58 /* Packet length, tile-part header (PLT). */
+#define	JPC_MS_PPM	0xff60 /* Packed packet headers, main header (PPM). */
+#define	JPC_MS_PPT	0xff61 /* Packet packet headers, tile-part header (PPT). */
+
+/* In bit stream marker segments. */
+#define	JPC_MS_SOP	0xff91	/* Start of packet (SOP). */
+#define	JPC_MS_EPH	0xff92	/* End of packet header (EPH). */
+
+/* Informational marker segments. */
+#define	JPC_MS_CRG	0xff63 /* Component registration (CRG). */
+#define JPC_MS_COM	0xff64 /* Comment (COM). */
+
+/* Forward declaration. */
+struct jpc_msops_s;
+
+/* Generic marker segment class. */
+
+typedef struct {
+
+	/* The type of marker segment. */
+	uint_fast16_t id;
+
+	/* The length of the marker segment. */
+	uint_fast16_t len;
+
+	/* The starting offset within the stream. */
+	uint_fast32_t off;
+
+	/* The parameters of the marker segment. */
+	jpc_msparms_t parms;
+
+	/* The marker segment operations. */
+	struct jpc_msops_s *ops;
+
+} jpc_ms_t;
+
+/* Marker segment operations (which depend on the marker segment type). */
+
+typedef struct jpc_msops_s {
+
+	/* Destroy the marker segment parameters. */
+	void (*destroyparms)(jpc_ms_t *ms);
+
+	/* Get the marker segment parameters from a stream. */
+	int (*getparms)(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *in);
+
+	/* Put the marker segment parameters to a stream. */
+	int (*putparms)(jpc_ms_t *ms, jpc_cstate_t *cstate, jas_stream_t *out);
+
+	/* Dump the marker segment parameters (for debugging). */
+	int (*dumpparms)(jpc_ms_t *ms, FILE *out);
+
+} jpc_msops_t;
+
+/******************************************************************************\
+* Macros/Functions.
+\******************************************************************************/
+
+/* Create a code-stream state object. */
+jpc_cstate_t *jpc_cstate_create(void);
+
+/* Destroy a code-stream state object. */
+void jpc_cstate_destroy(jpc_cstate_t *cstate);
+
+/* Create a marker segment. */
+jpc_ms_t *jpc_ms_create(int type);
+
+/* Destroy a marker segment. */
+void jpc_ms_destroy(jpc_ms_t *ms);
+
+/* Does a marker segment have parameters? */
+#define	JPC_MS_HASPARMS(x) \
+	(!((x) == JPC_MS_SOC || (x) == JPC_MS_SOD || (x) == JPC_MS_EOC || \
+	  (x) == JPC_MS_EPH || ((x) >= 0xff30 && (x) <= 0xff3f)))
+
+/* Get the marker segment type. */
+#define	jpc_ms_gettype(ms) \
+	((ms)->id)
+
+/* Read a marker segment from a stream. */
+jpc_ms_t *jpc_getms(jas_stream_t *in, jpc_cstate_t *cstate);
+
+/* Write a marker segment to a stream. */
+int jpc_putms(jas_stream_t *out, jpc_cstate_t *cstate, jpc_ms_t *ms);
+
+/* Copy code stream data from one stream to another. */
+int jpc_getdata(jas_stream_t *in, jas_stream_t *out, long n);
+
+/* Copy code stream data from one stream to another. */
+int jpc_putdata(jas_stream_t *out, jas_stream_t *in, long n);
+
+/* Dump a marker segment (for debugging). */
+void jpc_ms_dump(jpc_ms_t *ms, FILE *out);
+
+/* Read a 8-bit unsigned integer from a stream. */
+int jpc_getuint8(jas_stream_t *in, uint_fast8_t *val);
+
+/* Read a 16-bit unsigned integer from a stream. */
+int jpc_getuint16(jas_stream_t *in, uint_fast16_t *val);
+
+/* Read a 32-bit unsigned integer from a stream. */
+int jpc_getuint32(jas_stream_t *in, uint_fast32_t *val);
+
+/* Write a 8-bit unsigned integer to a stream. */
+int jpc_putuint8(jas_stream_t *out, uint_fast8_t val);
+
+/* Write a 16-bit unsigned integer to a stream. */
+int jpc_putuint16(jas_stream_t *out, uint_fast16_t val);
+
+/* Write a 32-bit unsigned integer to a stream. */
+int jpc_putuint32(jas_stream_t *out, uint_fast32_t val);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
new file mode 100644
index 00000000..42980225
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.c
@@ -0,0 +1,2334 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_math.h"
+#include "jasper/jas_tvp.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_debug.h"
+
+#include "jpc_fix.h"
+#include "jpc_dec.h"
+#include "jpc_cs.h"
+#include "jpc_mct.h"
+#include "jpc_t2dec.h"
+#include "jpc_t1dec.h"
+#include "jpc_math.h"
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+#define	JPC_MHSOC	0x0001
+  /* In the main header, expecting a SOC marker segment. */
+#define	JPC_MHSIZ	0x0002
+  /* In the main header, expecting a SIZ marker segment. */
+#define	JPC_MH		0x0004
+  /* In the main header, expecting "other" marker segments. */
+#define	JPC_TPHSOT	0x0008
+  /* In a tile-part header, expecting a SOT marker segment. */
+#define	JPC_TPH		0x0010
+  /* In a tile-part header, expecting "other" marker segments. */
+#define	JPC_MT		0x0020
+  /* In the main trailer. */
+
+typedef struct {
+
+	uint_fast16_t id;
+	/* The marker segment type. */
+
+	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. */
+
+} jpc_dec_mstabent_t;
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+/* COD/COC parameters have been specified. */
+#define	JPC_CSET	0x0001
+/* QCD/QCC parameters have been specified. */
+#define	JPC_QSET	0x0002
+/* COD/COC parameters set from a COC marker segment. */
+#define	JPC_COC	0x0004
+/* QCD/QCC parameters set from a QCC marker segment. */
+#define	JPC_QCC	0x0008
+
+/******************************************************************************\
+* Local function prototypes.
+\******************************************************************************/
+
+static int jpc_dec_dump(jpc_dec_t *dec, FILE *out);
+
+jpc_ppxstab_t *jpc_ppxstab_create(void);
+void jpc_ppxstab_destroy(jpc_ppxstab_t *tab);
+int jpc_ppxstab_grow(jpc_ppxstab_t *tab, int maxents);
+int jpc_ppxstab_insert(jpc_ppxstab_t *tab, jpc_ppxstabent_t *ent);
+jpc_streamlist_t *jpc_ppmstabtostreams(jpc_ppxstab_t *tab);
+int jpc_pptstabwrite(jas_stream_t *out, jpc_ppxstab_t *tab);
+jpc_ppxstabent_t *jpc_ppxstabent_create(void);
+void jpc_ppxstabent_destroy(jpc_ppxstabent_t *ent);
+
+int jpc_streamlist_numstreams(jpc_streamlist_t *streamlist);
+jpc_streamlist_t *jpc_streamlist_create(void);
+int jpc_streamlist_insert(jpc_streamlist_t *streamlist, int streamno,
+  jas_stream_t *stream);
+jas_stream_t *jpc_streamlist_remove(jpc_streamlist_t *streamlist, int streamno);
+void jpc_streamlist_destroy(jpc_streamlist_t *streamlist);
+jas_stream_t *jpc_streamlist_get(jpc_streamlist_t *streamlist, int streamno);
+
+static void jpc_dec_cp_resetflags(jpc_dec_cp_t *cp);
+static jpc_dec_cp_t *jpc_dec_cp_create(uint_fast16_t numcomps);
+static int jpc_dec_cp_isvalid(jpc_dec_cp_t *cp);
+static jpc_dec_cp_t *jpc_dec_cp_copy(jpc_dec_cp_t *cp);
+static int jpc_dec_cp_setfromcod(jpc_dec_cp_t *cp, jpc_cod_t *cod);
+static int jpc_dec_cp_setfromcoc(jpc_dec_cp_t *cp, jpc_coc_t *coc);
+static int jpc_dec_cp_setfromcox(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp,
+  jpc_coxcp_t *compparms, int flags);
+static int jpc_dec_cp_setfromqcd(jpc_dec_cp_t *cp, jpc_qcd_t *qcd);
+static int jpc_dec_cp_setfromqcc(jpc_dec_cp_t *cp, jpc_qcc_t *qcc);
+static int jpc_dec_cp_setfromqcx(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp,
+  jpc_qcxcp_t *compparms, int flags);
+static int jpc_dec_cp_setfromrgn(jpc_dec_cp_t *cp, jpc_rgn_t *rgn);
+static int jpc_dec_cp_prepare(jpc_dec_cp_t *cp);
+static void jpc_dec_cp_destroy(jpc_dec_cp_t *cp);
+static int jpc_dec_cp_setfrompoc(jpc_dec_cp_t *cp, jpc_poc_t *poc, int reset);
+static int jpc_pi_addpchgfrompoc(jpc_pi_t *pi, jpc_poc_t *poc);
+
+static int jpc_dec_decode(jpc_dec_t *dec);
+static jpc_dec_t *jpc_dec_create(jpc_dec_importopts_t *impopts, jas_stream_t *in);
+static void jpc_dec_destroy(jpc_dec_t *dec);
+static void jpc_dequantize(jas_matrix_t *x, jpc_fix_t absstepsize);
+static void jpc_undo_roi(jas_matrix_t *x, int roishift, int bgshift, int numbps);
+static jpc_fix_t jpc_calcabsstepsize(int stepsize, int numbits);
+static int jpc_dec_tiledecode(jpc_dec_t *dec, jpc_dec_tile_t *tile);
+static int jpc_dec_tileinit(jpc_dec_t *dec, jpc_dec_tile_t *tile);
+static int jpc_dec_tilefini(jpc_dec_t *dec, jpc_dec_tile_t *tile);
+static int jpc_dec_process_soc(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_sot(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_sod(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_siz(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_coc(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_poc(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_ppm(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_unk(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms);
+static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts);
+
+/******************************************************************************\
+* Global data.
+\******************************************************************************/
+
+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}
+};
+
+/******************************************************************************\
+* 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;
+
+	dec = 0;
+
+	if (jpc_dec_parseopts(optstr, &opts)) {
+		goto error;
+	}
+
+	jpc_initluts();
+
+	if (!(dec = jpc_dec_create(&opts, in))) {
+		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));
+	}
+
+	/* Save the return value. */
+	image = dec->image;
+
+	/* Stop the image from being discarded. */
+	dec->image = 0;
+
+	/* Destroy decoder. */
+	jpc_dec_destroy(dec);
+
+	return image;
+
+error:
+	if (dec) {
+		jpc_dec_destroy(dec);
+	}
+	return 0;
+}
+
+typedef enum {
+	OPT_MAXLYRS,
+	OPT_MAXPKTS,
+	OPT_DEBUG
+} optid_t;
+
+jas_taginfo_t decopts[] = {
+	{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;
+
+	opts->debug = 0;
+	opts->maxlyrs = JPC_MAXLYRS;
+	opts->maxpkts = -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;
+		}
+	}
+
+	jas_tvparser_destroy(tvp);
+
+	return 0;
+}
+
+/******************************************************************************\
+* Code for table-driven code stream decoder.
+\******************************************************************************/
+
+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;
+}
+
+static int jpc_dec_decode(jpc_dec_t *dec)
+{
+	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;
+
+	/* Initially, we should expect to encounter a SOC marker segment. */
+	dec->state = JPC_MHSOC;
+
+	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;
+		}
+
+		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;
+		}
+
+		/* 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);
+
+		if (ret < 0) {
+			return -1;
+		} else if (ret > 0) {
+			break;
+		}
+
+	}
+
+	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;
+
+	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;
+
+	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;
+}
+
+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;
+}
+
+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) {
+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;
+				}
+
+/************************************************/
+	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;
+}
+
+	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;
+}
+
+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;
+
+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) {
+if (!rlvl->bands) {
+	continue;
+}
+			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) {
+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;
+}
+
+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;
+}
+
+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);
+	}
+
+	/* We are done processing the code stream. */
+	dec->state = JPC_MT;
+
+	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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+
+	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;
+}
+
+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;
+}
+
+static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms)
+{
+	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;
+}
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+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;
+}
+
+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;
+}
+
+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;
+	}
+}
+
+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);
+}
+
+static int jpc_dec_cp_isvalid(jpc_dec_cp_t *cp)
+{
+	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;
+}
+
+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))));
+	}
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+static jpc_fix_t jpc_calcabsstepsize(int stepsize, int numbits)
+{
+	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;
+}
+
+static void jpc_dequantize(jas_matrix_t *x, jpc_fix_t absstepsize)
+{
+	int i;
+	int j;
+	int t;
+
+	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);
+		}
+	}
+
+}
+
+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);
+			}
+		}
+	}
+}
+
+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;
+dec->numpkts = 0;
+	dec->ppmseqno = 0;
+	dec->state = 0;
+	dec->cmpts = 0;
+	dec->pkthdrstreams = 0;
+	dec->ppmstab = 0;
+	dec->curtileendoff = 0;
+
+	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->cp) {
+		jpc_dec_cp_destroy(dec->cp);
+	}
+
+	if (dec->cmpts) {
+		jas_free(dec->cmpts);
+	}
+
+	if (dec->tiles) {
+		jas_free(dec->tiles);
+	}
+
+	jas_free(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;
+	}
+}
+
+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 *jpc_seg_alloc(void)
+{
+	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;
+}
+
+void jpc_seg_destroy(jpc_dec_seg_t *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_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;
+}
+
+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 *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;
+}
+
+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);
+}
+
+jas_stream_t *jpc_streamlist_get(jpc_streamlist_t *streamlist, int streamno)
+{
+	assert(streamno < streamlist->numstreams);
+	return streamlist->streams[streamno];
+}
+
+int jpc_streamlist_numstreams(jpc_streamlist_t *streamlist)
+{
+	return streamlist->numstreams;
+}
+
+jpc_ppxstab_t *jpc_ppxstab_create()
+{
+	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;
+}
+
+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 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;
+}
+
+int jpc_ppxstab_insert(jpc_ppxstab_t *tab, jpc_ppxstabent_t *ent)
+{
+	int inspt;
+	int 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;
+		}
+	}
+
+	for (i = tab->numents; i > inspt; --i) {
+		tab->ents[i] = tab->ents[i - 1];
+	}
+	tab->ents[i] = ent;
+	++tab->numents;
+
+	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;
+
+error:
+	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;
+}
+
+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;
+}
+
+void jpc_ppxstabent_destroy(jpc_ppxstabent_t *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
new file mode 100644
index 00000000..5231048d
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_dec.h
@@ -0,0 +1,745 @@
+/*
+ * 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__
+ */
+
+/*
+ * JPEG-2000 Decoder
+ *
+ * $Id$
+ */
+
+#ifndef JPC_DEC_H
+#define JPC_DEC_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_stream.h"
+
+#include "jpc_tsfb.h"
+#include "jpc_bs.h"
+#include "jpc_tagtree.h"
+#include "jpc_cs.h"
+#include "jpc_cod.h"
+#include "jpc_mqdec.h"
+#include "jpc_t2cod.h"
+
+/******************************************************************************\
+* Below are some ugly warts necessary to support packed packet headers.
+\******************************************************************************/
+
+/* PPM/PPT marker segment table entry. */
+
+typedef struct {
+
+	/* The index for this entry. */
+	uint_fast16_t ind;
+
+	/* The data length. */
+	uint_fast32_t len;
+
+	/* The data. */
+	unsigned char *data;
+
+} jpc_ppxstabent_t;
+
+/* PPM/PPT marker segment table. */
+
+typedef struct {
+
+	/* The number of entries. */
+	int numents;
+
+	/* The maximum number of entries (i.e., the allocated size of the array
+	  below). */
+	int maxents;
+
+	/* The table entries. */
+	jpc_ppxstabent_t **ents;
+
+} jpc_ppxstab_t;
+
+/* Stream list class. */
+
+typedef struct {
+
+	/* The number of streams in this list. */
+	int numstreams;
+
+	/* The maximum number of streams that can be accomodated without
+	  growing the streams array. */
+	int maxstreams;
+
+	/* The streams. */
+	jas_stream_t **streams;
+
+} jpc_streamlist_t;
+
+/******************************************************************************\
+* Coding parameters class.
+\******************************************************************************/
+
+/* Per-component coding parameters. */
+
+typedef struct {
+
+	/* How were various coding parameters set? */
+	int flags;
+
+	/* Per-component coding style parameters (e.g., explicit precinct sizes) */
+	uint_fast8_t csty;
+
+	/* The number of resolution levels. */
+	uint_fast8_t numrlvls;
+
+	/* The code block width exponent. */
+	uint_fast8_t cblkwidthexpn;
+
+	/* The code block height exponent. */
+	uint_fast8_t cblkheightexpn;
+
+	/* The QMFB ID. */
+	uint_fast8_t qmfbid;
+
+	/* The quantization style. */
+	uint_fast8_t qsty;
+
+	/* The number of quantizer step sizes. */
+	uint_fast16_t numstepsizes;
+
+	/* The step sizes. */
+	uint_fast16_t stepsizes[3 * JPC_MAXRLVLS + 1];
+
+	/* The number of guard bits. */
+	uint_fast8_t numguardbits;
+
+	/* The ROI shift value. */
+	uint_fast8_t roishift;
+
+	/* The code block parameters. */
+	uint_fast8_t cblkctx;
+
+	/* The precinct width exponents. */
+	uint_fast8_t prcwidthexpns[JPC_MAXRLVLS];
+
+	/* The precinct height exponents. */
+	uint_fast8_t prcheightexpns[JPC_MAXRLVLS];
+
+} jpc_dec_ccp_t;
+
+/* Coding paramters. */
+
+typedef struct {
+
+	/* How were these coding parameters set? */
+	int flags;
+
+	/* Progression change list. */
+	jpc_pchglist_t *pchglist;
+
+	/* Progression order. */
+	uint_fast8_t prgord;
+
+	/* The number of layers. */
+	uint_fast16_t numlyrs;
+
+	/* The MCT ID. */
+	uint_fast8_t mctid;
+
+	/* The coding style parameters (e.g., SOP, EPH). */
+	uint_fast8_t csty;
+
+	/* The number of components. */
+	uint_fast16_t numcomps;
+
+	/* The per-component coding parameters. */
+	jpc_dec_ccp_t *ccps;
+
+} jpc_dec_cp_t;
+
+/******************************************************************************\
+* Decoder class.
+\******************************************************************************/
+
+/* Decoder per-segment state information. */
+
+typedef struct jpc_dec_seg_s {
+
+	/* The next segment in the list. */
+	struct jpc_dec_seg_s *next;
+
+	/* The previous segment in the list. */
+	struct jpc_dec_seg_s *prev;
+
+	/* The starting pass number for this segment. */
+	int passno;
+
+	/* The number of passes in this segment. */
+	int numpasses;
+
+	/* The maximum number of passes in this segment. */
+	int maxpasses;
+
+	/* The type of data in this segment (i.e., MQ or raw). */
+	int type;
+
+	/* A stream containing the data for this segment. */
+	jas_stream_t *stream;
+
+	/* The number of bytes destined for this segment from the packet
+	  currently being decoded. */
+	int cnt;
+
+	/* A flag indicating if this segment has been terminated. */
+	int complete;
+
+	/* The layer number to which this segment belongs. */
+	/* If the segment spans multiple layers, then the largest layer number
+	  spanned by the segment is used. */
+	int lyrno;
+
+} jpc_dec_seg_t;
+
+/* Decoder segment list. */
+
+typedef struct {
+
+	/* The first entry in the list. */
+	jpc_dec_seg_t *head;
+
+	/* The last entry in the list. */
+	jpc_dec_seg_t *tail;
+
+} jpc_dec_seglist_t;
+
+/* Decoder per-code-block state information. */
+
+typedef struct {
+
+	/* The number of passes. */
+	int numpasses;
+
+	/* A list of segments that still need to be decoded. */
+	jpc_dec_seglist_t segs;
+
+	/* The first incomplete/partial segment. */
+	jpc_dec_seg_t *curseg;
+
+	/* The number of leading insignificant bit planes for this code block. */
+	int numimsbs;
+
+	/* The number of bits used to encode pass data lengths. */
+	int numlenbits;
+
+	/* The first pass number containing data for this code block. */
+	int firstpassno;
+
+	/* The MQ decoder. */
+	jpc_mqdec_t *mqdec;
+
+	/* The raw bit stream decoder. */
+	jpc_bitstream_t *nulldec;
+
+	/* The per-sample state information for this code block. */
+	jas_matrix_t *flags;
+
+	/* The sample data associated with this code block. */
+	jas_matrix_t *data;
+
+} jpc_dec_cblk_t;
+
+/* Decoder per-code-block-group state information. */
+
+typedef struct {
+
+	/* The x-coordinate of the top-left corner of the precinct. */
+	uint_fast32_t xstart;
+
+	/* The y-coordinate of the top-left corner of the precinct. */
+	uint_fast32_t ystart;
+
+	/* The x-coordinate of the bottom-right corner of the precinct
+	  (plus one). */
+	uint_fast32_t xend;
+
+	/* The y-coordinate of the bottom-right corner of the precinct
+	  (plus one). */
+	uint_fast32_t yend;
+
+	/* The number of code blocks spanning this precinct in the horizontal
+	  direction. */
+	int numhcblks;
+
+	/* The number of code blocks spanning this precinct in the vertical
+	  direction. */
+	int numvcblks;
+
+	/* The total number of code blocks in this precinct. */
+	int numcblks;
+
+	/* The per code block information. */
+	jpc_dec_cblk_t *cblks;
+
+	/* The inclusion tag tree. */
+	jpc_tagtree_t *incltagtree;
+
+	/* The insignificant MSBs tag tree. */
+	jpc_tagtree_t *numimsbstagtree;
+
+} jpc_dec_prc_t;
+
+/* Decoder per-band state information. */
+
+typedef struct {
+
+	/* The per-code-block-group state information. */
+	jpc_dec_prc_t *prcs;
+
+	/* The sample data associated with this band. */
+	jas_matrix_t *data;
+
+	/* The orientation of this band (i.e., LL, LH, HL, or HH). */
+	int orient;
+
+	/* The encoded quantizer step size. */
+	int stepsize;
+
+	/* The absolute quantizer step size. */
+	jpc_fix_t absstepsize;
+
+	/* The number of bit planes for this band. */
+	int numbps;
+
+	/* The analysis gain associated with this band. */
+	int analgain;
+
+	/* The ROI shift value for this band. */
+	int roishift;
+
+} jpc_dec_band_t;
+
+/* Decoder per-resolution-level state information. */
+
+typedef struct {
+
+	/* The number of bands associated with this resolution level. */
+	int numbands;
+
+	/* The per-band information. */
+	jpc_dec_band_t *bands;
+
+	/* The x-coordinate of the top-left corner of the tile-component
+	  at this resolution. */
+	uint_fast32_t xstart;
+
+	/* The y-coordinate of the top-left corner of the tile-component
+	  at this resolution. */
+	uint_fast32_t ystart;
+
+	/* The x-coordinate of the bottom-right corner of the tile-component
+	  at this resolution (plus one). */
+	uint_fast32_t xend;
+
+	/* The y-coordinate of the bottom-right corner of the tile-component
+	  at this resolution (plus one). */
+	uint_fast32_t yend;
+
+	/* The exponent value for the nominal precinct width measured
+	  relative to the associated LL band. */
+	int prcwidthexpn;
+
+	/* The exponent value for the nominal precinct height measured
+	  relative to the associated LL band. */
+	int prcheightexpn;
+
+	/* The number of precincts in the horizontal direction. */
+	int numhprcs;
+
+	/* The number of precincts in the vertical direction. */
+	int numvprcs;
+
+	/* The total number of precincts. */
+	int numprcs;
+
+	/* The exponent value for the nominal code block group width.
+	  This quantity is associated with the next lower resolution level
+	  (assuming that there is one). */
+	int cbgwidthexpn;
+
+	/* The exponent value for the nominal code block group height
+	  This quantity is associated with the next lower resolution level
+	  (assuming that there is one). */
+	int cbgheightexpn;
+
+	/* The exponent value for the code block width. */
+	uint_fast16_t cblkwidthexpn;
+
+	/* The exponent value for the code block height. */
+	uint_fast16_t cblkheightexpn;
+
+} jpc_dec_rlvl_t;
+
+/* Decoder per-tile-component state information. */
+
+typedef struct {
+
+	/* The x-coordinate of the top-left corner of the tile-component
+	  in the coordinate system of the tile-component. */
+	uint_fast32_t xstart;
+
+	/* The y-coordinate of the top-left corner of the tile-component
+	  in the coordinate system of the tile-component. */
+	uint_fast32_t ystart;
+
+	/* The x-coordinate of the bottom-right corner of the tile-component
+	  in the coordinate system of the tile-component (plus one). */
+	uint_fast32_t xend;
+
+	/* The y-coordinate of the bottom-right corner of the tile-component
+	  in the coordinate system of the tile-component (plus one). */
+	uint_fast32_t yend;
+
+	/* The component data for the current tile. */
+	jas_matrix_t *data;
+
+	/* The number of resolution levels. */
+	uint_fast16_t numrlvls;
+
+	/* The per resolution level information. */
+	jpc_dec_rlvl_t *rlvls;
+
+	/* The TSFB. */
+	jpc_tsfb_t *tsfb;
+
+} jpc_dec_tcomp_t;
+
+/*
+ * Tile states.
+ */
+
+#define	JPC_TILE_INIT	0
+#define	JPC_TILE_ACTIVE	1
+#define	JPC_TILE_ACTIVELAST	2
+#define	JPC_TILE_DONE	3
+
+/* Decoder per-tile state information. */
+
+typedef struct {
+
+	/* The processing state for this tile. */
+	int state;
+
+	/* The x-coordinate of the top-left corner of the tile on the reference
+	  grid. */
+	uint_fast32_t xstart;
+
+	/* The y-coordinate of the top-left corner of the tile on the reference
+	  grid. */
+	uint_fast32_t ystart;
+
+	/* The x-coordinate of the bottom-right corner of the tile on the
+	  reference grid (plus one). */
+	uint_fast32_t xend;
+
+	/* The y-coordinate of the bottom-right corner of the tile on the
+	  reference grid (plus one). */
+	uint_fast32_t yend;
+
+	/* The packed packet header data for this tile. */
+	jpc_ppxstab_t *pptstab;
+
+	/* A stream containing the packed packet header data for this tile. */
+	jas_stream_t *pkthdrstream;
+
+	/* The current position within the packed packet header stream. */
+	long pkthdrstreampos;
+
+	/* The coding parameters for this tile. */
+	jpc_dec_cp_t *cp;
+
+	/* The per tile-component information. */
+	jpc_dec_tcomp_t *tcomps;
+
+	/* The next expected tile-part number. */
+	int partno;
+
+	/* The number of tile-parts. */
+	int numparts;
+
+	/* The coding mode. */
+	int realmode;
+
+	/* The packet iterator for this tile. */
+	jpc_pi_t *pi;
+
+} jpc_dec_tile_t;
+
+/* Decoder per-component state information. */
+
+typedef struct {
+
+	/* The horizontal sampling period. */
+	uint_fast32_t hstep;
+
+	/* The vertical sampling period. */
+	uint_fast32_t vstep;
+
+	/* The number of samples in the horizontal direction. */
+	uint_fast32_t width;
+
+	/* The number of samples in the vertical direction. */
+	uint_fast32_t height;
+
+	/* The precision of the sample data. */
+	uint_fast16_t prec;
+
+	/* The signedness of the sample data. */
+	bool sgnd;
+
+	/* The sample alignment horizontal offset. */
+	uint_fast32_t hsubstep;
+	
+	/* The sample alignment vertical offset. */
+	uint_fast32_t vsubstep;
+
+} jpc_dec_cmpt_t;
+
+/* Decoder state information. */
+
+typedef struct {
+
+	/* The decoded image. */
+	jas_image_t *image;
+
+	/* The x-coordinate of the top-left corner of the image area on
+	  the reference grid. */
+	uint_fast32_t xstart;
+
+	/* The y-coordinate of the top-left corner of the image area on
+	  the reference grid. */
+	uint_fast32_t ystart;
+
+	/* The x-coordinate of the bottom-right corner of the image area on
+	  the reference grid (plus one). */
+	uint_fast32_t xend;
+
+	/* The y-coordinate of the bottom-right corner of the image area on
+	  the reference grid (plus one). */
+	uint_fast32_t yend;
+
+	/* The nominal tile width in units of the image reference grid. */
+	uint_fast32_t tilewidth;
+
+	/* The nominal tile height in units of the image reference grid. */
+	uint_fast32_t tileheight;
+
+	/* The horizontal offset from the origin of the reference grid to the
+	  left side of the first tile. */
+	uint_fast32_t tilexoff;
+
+	/* The vertical offset from the origin of the reference grid to the
+	  top side of the first tile. */
+	uint_fast32_t tileyoff;
+
+	/* The number of tiles spanning the image area in the vertical
+	  direction. */
+	int numhtiles;
+
+	/* The number of tiles spanning the image area in the horizontal
+	  direction. */
+	int numvtiles;
+
+	/* The total number of tiles. */
+	int numtiles;
+
+	/* The per-tile information. */
+	jpc_dec_tile_t *tiles;
+
+	/* The tile currently being processed. */
+	jpc_dec_tile_t *curtile;
+
+	/* The number of components. */
+	int numcomps;
+
+	/* The stream containing the input JPEG-2000 code stream data. */
+	jas_stream_t *in;
+
+	/* The default coding parameters for all tiles. */
+	jpc_dec_cp_t *cp;
+
+	/* The maximum number of layers that may be decoded. */
+	int maxlyrs;
+
+	/* The maximum number of packets that may be decoded. */
+	int maxpkts;
+
+	/* The number of packets decoded so far in the processing of the entire
+	  code stream. */
+	int numpkts;
+
+	/* The next expected PPM marker segment sequence number. */
+	int ppmseqno;
+
+	/* The current state for code stream processing. */
+	int state;
+
+	/* The per-component information. */
+	jpc_dec_cmpt_t *cmpts;
+
+	/* The information from PPM marker segments. */
+	jpc_ppxstab_t *ppmstab;
+
+	/* A list of streams containing packet header data from PPM marker
+	  segments. */
+	jpc_streamlist_t *pkthdrstreams;
+
+	/* The expected ending offset for a tile-part. */
+	long curtileendoff;
+
+	/* This is required by the tier-2 decoder. */
+	jpc_cstate_t *cstate;
+
+} jpc_dec_t;
+
+/* Decoder options. */
+
+typedef struct {
+
+	/* The debug level for the decoder. */
+	int debug;
+
+	/* The maximum number of layers to decode. */
+	int maxlyrs;
+
+	/* The maximum number of packets to decode. */
+	int maxpkts;
+
+} jpc_dec_importopts_t;
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Create a decoder segment object. */
+jpc_dec_seg_t *jpc_seg_alloc(void);
+
+/* Destroy a decoder segment object. */
+void jpc_seg_destroy(jpc_dec_seg_t *seg);
+
+/* Remove a segment from a segment list. */
+void jpc_seglist_remove(jpc_dec_seglist_t *list, jpc_dec_seg_t *node);
+
+/* Insert a segment into a segment list. */
+void jpc_seglist_insert(jpc_dec_seglist_t *list, jpc_dec_seg_t *ins,
+  jpc_dec_seg_t *node);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
new file mode 100644
index 00000000..3284dfeb
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c
@@ -0,0 +1,2624 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+#include <float.h>
+
+#include "jasper/jas_string.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_image.h"
+#include "jasper/jas_fix.h"
+#include "jasper/jas_tvp.h"
+#include "jasper/jas_version.h"
+#include "jasper/jas_math.h"
+#include "jasper/jas_debug.h"
+
+#include "jpc_flt.h"
+#include "jpc_fix.h"
+#include "jpc_tagtree.h"
+#include "jpc_enc.h"
+#include "jpc_cs.h"
+#include "jpc_mct.h"
+#include "jpc_tsfb.h"
+#include "jpc_qmfb.h"
+#include "jpc_t1enc.h"
+#include "jpc_t2enc.h"
+#include "jpc_cod.h"
+#include "jpc_math.h"
+#include "jpc_util.h"
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+#define JPC_POW2(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) \
+  (((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)	\
+  (1 << (n))
+
+jpc_enc_tile_t *jpc_enc_tile_create(jpc_enc_cp_t *cp, jas_image_t *image, int tileno);
+void jpc_enc_tile_destroy(jpc_enc_tile_t *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);
+static void tcmpt_destroy(jpc_enc_tcmpt_t *tcmpt);
+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);
+static void rlvl_destroy(jpc_enc_rlvl_t *rlvl);
+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);
+static void band_destroy(jpc_enc_band_t *bands);
+static jpc_enc_prc_t *prc_create(jpc_enc_prc_t *prc, jpc_enc_cp_t *cp,
+  jpc_enc_band_t *band);
+static void prc_destroy(jpc_enc_prc_t *prcs);
+static jpc_enc_cblk_t *cblk_create(jpc_enc_cblk_t *cblk, jpc_enc_cp_t *cp,
+  jpc_enc_prc_t *prc);
+static void cblk_destroy(jpc_enc_cblk_t *cblks);
+int ratestrtosize(const char *s, uint_fast32_t rawsize, uint_fast32_t *size);
+static void pass_destroy(jpc_enc_pass_t *pass);
+void jpc_enc_dump(jpc_enc_t *enc);
+
+/******************************************************************************\
+* Local prototypes.
+\******************************************************************************/
+
+void quantize(jas_matrix_t *data, jpc_fix_t stepsize);
+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);
+jpc_enc_t *jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image);
+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);
+}
+
+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
+} 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}
+};
+
+typedef enum {
+	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}
+};
+
+typedef enum {
+	MODE_INT,
+	MODE_REAL
+} modeid_t;
+
+jas_taginfo_t modetab[] = {
+	{MODE_INT, "int"},
+	{MODE_REAL, "real"},
+	{-1, 0}
+};
+
+/******************************************************************************\
+* 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;
+
+	enc = 0;
+	cp = 0;
+
+	jpc_initluts();
+
+	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;
+
+	/* 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;
+	}
+
+	/* 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;
+	}
+
+	jpc_enc_destroy(enc);
+
+	return 0;
+
+error:
+	if (cp) {
+		jpc_enc_cp_destroy(cp);
+	}
+	if (enc) {
+		jpc_enc_destroy(enc);
+	}
+	return -1;
+}
+
+/******************************************************************************\
+* Option parsing code.
+\******************************************************************************/
+
+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;
+
+error:
+
+	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);
+}
+
+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;
+}
+
+/******************************************************************************\
+* Encoder constructor and destructor.
+\******************************************************************************/
+
+jpc_enc_t *jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image)
+{
+	jpc_enc_t *enc;
+
+	enc = 0;
+
+	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;
+
+	if (!(enc->cstate = jpc_cstate_create())) {
+		goto error;
+	}
+	enc->len = 0;
+	enc->mainbodysize = 0;
+
+	return enc;
+
+error:
+
+	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);
+}
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+static int jpc_enc_encodemainhdr(jpc_enc_t *enc)
+{
+	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;
+
+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;
+
+#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;
+#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;
+}
+
+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 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
+
+		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;
+
+		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;
+		}
+
+#if 0
+fprintf(stderr, "ENCODE TILE DATA\n");
+#endif
+		if (jpc_enc_encodetiledata(enc)) {
+			fprintf(stderr, "dotile failed\n");
+			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;
+}
+
+int jpc_enc_encodetiledata(jpc_enc_t *enc)
+{
+assert(enc->tmpstream);
+	if (jpc_enc_encpkts(enc, enc->tmpstream)) {
+		return -1;
+	}
+	return 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;
+	}
+
+	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);
+	}
+}
+
+			jas_matrix_set(data, i, j, t);
+		}
+	}
+}
+
+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
+	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
+}
+
+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);
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+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);
+}
+
+	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);
+}
+
+			++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);
+}
+
+		/* 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;
+}
+				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;
+}
+
+/******************************************************************************\
+* 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;
+
+error:
+
+	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);
+}
+
+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;
+
+error:
+
+	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);
+	}
+}
+
+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;
+error:
+
+	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);
+	}
+}
+
+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];
+
+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);
+}
+	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;
+		}
+	}
+}
+
+	return band;
+
+error:
+	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);
+	}
+}
+
+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;
+rlvlno = rlvl - tcmpt->rlvls;
+	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;
+} else {
+	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;
+
+error:
+	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);
+	}
+}
+
+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;
+
+error:
+	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);
+	}
+}
+
+static void pass_destroy(jpc_enc_pass_t *pass)
+{
+	/* 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));
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.h b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.h
new file mode 100644
index 00000000..cfd754c9
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.h
@@ -0,0 +1,695 @@
+/*
+ * 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$
+ */
+
+#ifndef JPC_ENC_H
+#define JPC_ENC_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_seq.h"
+
+#include "jpc_t2cod.h"
+#include "jpc_mqenc.h"
+#include "jpc_cod.h"
+#include "jpc_tagtree.h"
+#include "jpc_cs.h"
+#include "jpc_flt.h"
+#include "jpc_tsfb.h"
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/* The number of bits used in various lookup tables. */
+#define	JPC_NUMEXTRABITS	JPC_NMSEDEC_FRACBITS
+
+/* An invalid R-D slope value. */
+#define	JPC_BADRDSLOPE	(-1)
+
+/******************************************************************************\
+* Coding parameters types.
+\******************************************************************************/
+
+/* Per-component coding paramters. */
+
+typedef struct {
+
+	/* The horizontal sampling period. */
+	uint_fast8_t sampgrdstepx;
+
+	/* The vertical sampling period. */
+	uint_fast8_t sampgrdstepy;
+
+	/* The sample alignment horizontal offset. */
+	uint_fast8_t sampgrdsubstepx;
+
+	/* The sample alignment vertical offset. */
+	uint_fast8_t sampgrdsubstepy;
+
+	/* The precision of the samples. */
+	uint_fast8_t prec;
+
+	/* The signedness of the samples. */
+	bool sgnd;
+
+	/* The number of step sizes. */
+	uint_fast16_t numstepsizes;
+
+	/* The quantizer step sizes. */
+	uint_fast16_t stepsizes[JPC_MAXBANDS];
+
+} jpc_enc_ccp_t;
+
+/* Per-tile coding parameters. */
+
+typedef struct {
+
+	/* The coding mode. */
+	bool intmode;
+
+	/* The coding style (i.e., SOP, EPH). */
+	uint_fast8_t csty;
+
+	/* The progression order. */
+	uint_fast8_t prg;
+
+	/* The multicomponent transform. */
+	uint_fast8_t mctid;
+
+	/* The number of layers. */
+	uint_fast16_t numlyrs;
+
+	/* The normalized bit rates associated with the various
+	  intermediate layers. */
+	jpc_fix_t *ilyrrates;
+
+} jpc_enc_tcp_t;
+
+/* Per tile-component coding parameters. */
+
+typedef struct {
+
+	/* The coding style (i.e., explicit precinct sizes). */
+	uint_fast8_t csty;
+
+	/* The maximum number of resolution levels allowed. */
+	uint_fast8_t maxrlvls;
+
+	/* The exponent for the nominal code block width. */
+	uint_fast16_t cblkwidthexpn;
+
+	/* The exponent for the nominal code block height. */
+	uint_fast16_t cblkheightexpn;
+
+	/* The code block style parameters (e.g., lazy, terminate all,
+	  segmentation symbols, causal, reset probability models). */
+	uint_fast8_t cblksty;
+
+	/* The QMFB. */
+	uint_fast8_t qmfbid;
+
+	/* The precinct width values. */
+	uint_fast16_t prcwidthexpns[JPC_MAXRLVLS];
+
+	/* The precinct height values. */
+	uint_fast16_t prcheightexpns[JPC_MAXRLVLS];
+
+	/* The number of guard bits. */
+	uint_fast8_t numgbits;
+
+} jpc_enc_tccp_t;
+
+/* Coding parameters. */
+
+typedef struct {
+
+	/* The debug level. */
+	int debug;
+
+	/* The horizontal offset from the origin of the reference grid to the
+	  left edge of the image area. */
+	uint_fast32_t imgareatlx;
+
+	/* The vertical offset from the origin of the reference grid to the
+	  top edge of the image area. */
+	uint_fast32_t imgareatly;
+
+	/* The horizontal offset from the origin of the reference grid to the
+	  right edge of the image area (plus one). */
+	uint_fast32_t refgrdwidth;
+
+	/* The vertical offset from the origin of the reference grid to the
+	  bottom edge of the image area (plus one). */
+	uint_fast32_t refgrdheight;
+
+	/* The horizontal offset from the origin of the tile grid to the
+	  origin of the reference grid. */
+	uint_fast32_t tilegrdoffx;
+
+	/* The vertical offset from the origin of the tile grid to the
+	  origin of the reference grid. */
+	uint_fast32_t tilegrdoffy;
+
+	/* The nominal tile width in units of the image reference grid. */
+	uint_fast32_t tilewidth;
+
+	/* The nominal tile height in units of the image reference grid. */
+	uint_fast32_t tileheight;
+
+	/* The number of tiles spanning the image area in the horizontal
+	  direction. */
+	uint_fast32_t numhtiles;
+
+	/* The number of tiles spanning the image area in the vertical
+	  direction. */
+	uint_fast32_t numvtiles;
+
+	/* The number of tiles. */
+	uint_fast32_t numtiles;
+
+	/* The number of components. */
+	uint_fast16_t numcmpts;
+
+	/* The per-component coding parameters. */
+	jpc_enc_ccp_t *ccps;
+
+	/* The per-tile coding parameters. */
+	jpc_enc_tcp_t tcp;
+
+	/* The per-tile-component coding parameters. */
+	jpc_enc_tccp_t tccp;
+
+	/* The target code stream length in bytes. */
+	uint_fast32_t totalsize;
+
+	/* The raw (i.e., uncompressed) size of the image in bytes. */
+	uint_fast32_t rawsize;
+
+} jpc_enc_cp_t;
+
+/******************************************************************************\
+* Encoder class.
+\******************************************************************************/
+
+/* Encoder per-coding-pass state information. */
+
+typedef struct {
+
+	/* The starting offset for this pass. */
+	int start;
+
+	/* The ending offset for this pass. */
+	int end;
+
+	/* The type of data in this pass (i.e., MQ or raw). */
+	int type;
+
+	/* Flag indicating that this pass is terminated. */
+	int term;
+
+	/* The entropy coder state after coding this pass. */
+	jpc_mqencstate_t mqencstate;
+
+	/* The layer to which this pass has been assigned. */
+	int lyrno;
+
+	/* The R-D slope for this pass. */
+	jpc_flt_t rdslope;
+
+	/* The weighted MSE reduction associated with this pass. */
+	jpc_flt_t wmsedec;
+
+	/* The cumulative weighted MSE reduction. */
+	jpc_flt_t cumwmsedec;
+
+	/* The normalized MSE reduction. */
+	long nmsedec;
+
+} jpc_enc_pass_t;
+
+/* Encoder per-code-block state information. */
+
+typedef struct {
+
+	/* The number of passes. */
+	int numpasses;
+
+	/* The per-pass information. */
+	jpc_enc_pass_t *passes;
+
+	/* The number of passes encoded so far. */
+	int numencpasses;
+
+	/* The number of insignificant MSBs. */
+	int numimsbs;
+
+	/* The number of bits used to encode pass data lengths. */
+	int numlenbits;
+
+	/* The byte stream for this code block. */
+	jas_stream_t *stream;
+
+	/* The entropy encoder. */
+	jpc_mqenc_t *mqenc;
+
+	/* The data for this code block. */
+	jas_matrix_t *data;
+
+	/* The state for this code block. */
+	jas_matrix_t *flags;
+
+	/* The number of bit planes required for this code block. */
+	int numbps;
+
+	/* The next pass to be encoded. */
+	jpc_enc_pass_t *curpass;
+
+	/* The per-code-block-group state information. */
+	struct jpc_enc_prc_s *prc;
+
+	/* The saved current pass. */
+	/* This is used by the rate control code. */
+	jpc_enc_pass_t *savedcurpass;
+
+	/* The saved length indicator size. */
+	/* This is used by the rate control code. */
+	int savednumlenbits;
+
+	/* The saved number of encoded passes. */
+	/* This is used by the rate control code. */
+	int savednumencpasses;
+
+} jpc_enc_cblk_t;
+
+/* Encoder per-code-block-group state information. */
+
+typedef struct jpc_enc_prc_s {
+
+	/* The x-coordinate of the top-left corner of the precinct. */
+	uint_fast32_t tlx;
+
+	/* The y-coordinate of the top-left corner of the precinct. */
+	uint_fast32_t tly;
+
+	/* The x-coordinate of the bottom-right corner of the precinct
+	  (plus one). */
+	uint_fast32_t brx;
+
+	/* The y-coordinate of the bottom-right corner of the precinct
+	  (plus one). */
+	uint_fast32_t bry;
+
+	/* The number of code blocks spanning the precinct in the horizontal
+	direction. */
+	int numhcblks;
+
+	/* The number of code blocks spanning the precinct in the vertical
+	direction. */
+	int numvcblks;
+
+	/* The total number of code blocks. */
+	int numcblks;
+
+	/* The per-code-block information. */
+	jpc_enc_cblk_t *cblks;
+
+	/* The inclusion tag tree. */
+	jpc_tagtree_t *incltree;
+
+	/* The insignifcant MSBs tag tree. */
+	jpc_tagtree_t *nlibtree;
+
+	/* The per-band information. */
+	struct jpc_enc_band_s *band;
+
+	/* The saved inclusion tag tree. */
+	/* This is used by rate control. */
+	jpc_tagtree_t *savincltree;
+
+	/* The saved leading-insignificant-bit-planes tag tree. */
+	/* This is used by rate control. */
+	jpc_tagtree_t *savnlibtree;
+
+} jpc_enc_prc_t;
+
+/* Encoder per-band state information. */
+
+typedef struct jpc_enc_band_s {
+
+	/* The per precinct information. */
+	jpc_enc_prc_t *prcs;
+
+	/* The coefficient data for this band. */
+	jas_matrix_t *data;
+
+	/* The orientation of this band (i.e., LL, LH, HL, or HH). */
+	int orient;
+
+	/* The number of bit planes associated with this band. */
+	int numbps;
+
+	/* The quantizer step size. */
+	jpc_fix_t absstepsize;
+
+	/* The encoded quantizer step size. */
+	int stepsize;
+
+	/* The L2 norm of the synthesis basis functions associated with
+	  this band.  (The MCT is not considered in this value.) */
+	jpc_fix_t synweight;
+
+	/* The analysis gain for this band. */
+	int analgain;
+
+	/* The per-resolution-level information. */
+	struct jpc_enc_rlvl_s *rlvl;
+
+} jpc_enc_band_t;
+
+/* Encoder per-resolution-level state information. */
+
+typedef struct jpc_enc_rlvl_s {
+
+	/* The x-coordinate of the top-left corner of the tile-component
+	  at this resolution. */
+	uint_fast32_t tlx;
+
+	/* The y-coordinate of the top-left corner of the tile-component
+	  at this resolution. */
+	uint_fast32_t tly;
+
+	/* The x-coordinate of the bottom-right corner of the tile-component
+	  at this resolution (plus one). */
+	uint_fast32_t brx;
+
+	/* The y-coordinate of the bottom-right corner of the tile-component
+	  at this resolution (plus one). */
+	uint_fast32_t bry;
+
+	/* The exponent value for the nominal precinct width measured
+	  relative to the associated LL band. */
+	int prcwidthexpn;
+
+	/* The exponent value for the nominal precinct height measured
+	  relative to the associated LL band. */
+	int prcheightexpn;
+
+	/* The number of precincts spanning the resolution level in the
+	  horizontal direction. */
+	int numhprcs;
+
+	/* The number of precincts spanning the resolution level in the
+	  vertical direction. */
+	int numvprcs;
+
+	/* The total number of precincts. */
+	int numprcs;
+
+	/* The exponent value for the nominal code block group width.
+	  This quantity is associated with the next lower resolution level
+	  (assuming that there is one). */
+	int cbgwidthexpn;
+
+	/* The exponent value for the nominal code block group height.
+	  This quantity is associated with the next lower resolution level
+	  (assuming that there is one). */
+	int cbgheightexpn;
+
+	/* The exponent value for the code block width. */
+	uint_fast16_t cblkwidthexpn;
+
+	/* The exponent value for the code block height. */
+	uint_fast16_t cblkheightexpn;
+
+	/* The number of bands associated with this resolution level. */
+	int numbands;
+
+	/* The per-band information. */
+	jpc_enc_band_t *bands;
+
+	/* The parent tile-component. */
+	struct jpc_enc_tcmpt_s *tcmpt;
+
+} jpc_enc_rlvl_t;
+
+/* Encoder per-tile-component state information. */
+
+typedef struct jpc_enc_tcmpt_s {
+
+	/* The number of resolution levels. */
+	uint_fast16_t numrlvls;
+
+	/* The per-resolution-level information. */
+	jpc_enc_rlvl_t *rlvls;
+
+	/* The tile-component data. */
+	jas_matrix_t *data;
+
+	/* The QMFB. */
+	int qmfbid;
+
+	/* The number of bands. */
+	int numbands;
+
+	/* The TSFB. */
+	jpc_tsfb_t *tsfb;
+
+	/* The synthesis energy weight (for the MCT). */
+	jpc_fix_t synweight;
+
+	/* The precinct width exponents. */
+	int prcwidthexpns[JPC_MAXRLVLS];
+
+	/* The precinct height exponents. */
+	int prcheightexpns[JPC_MAXRLVLS];
+
+	/* The code block width exponent. */
+	int cblkwidthexpn;
+
+	/* The code block height exponent. */
+	int cblkheightexpn;
+
+	/* Coding style (i.e., explicit precinct sizes). */
+	int csty;
+
+	/* Code block style. */
+	int cblksty;
+
+	/* The number of quantizer step sizes. */
+	uint_fast16_t numstepsizes;
+
+	/* The encoded quantizer step sizes. */
+	uint_fast16_t stepsizes[JPC_MAXBANDS];
+
+	/* The parent tile. */
+	struct jpc_enc_tile_s *tile;
+
+} jpc_enc_tcmpt_t;
+
+/* Encoder per-tile state information. */
+
+typedef struct jpc_enc_tile_s {
+
+	/* The tile number. */
+	uint_fast32_t tileno;
+
+	/* The x-coordinate of the top-left corner of the tile measured with
+	  respect to the reference grid. */
+	uint_fast32_t tlx;
+
+	/* The y-coordinate of the top-left corner of the tile measured with
+	  respect to the reference grid. */
+	uint_fast32_t tly;
+
+	/* The x-coordinate of the bottom-right corner of the tile measured
+	  with respect to the reference grid (plus one). */
+	uint_fast32_t brx;
+
+	/* The y-coordinate of the bottom-right corner of the tile measured
+	  with respect to the reference grid (plus one). */
+	uint_fast32_t bry;
+
+	/* The coding style. */
+	uint_fast8_t csty;
+
+	/* The progression order. */
+	uint_fast8_t prg;
+
+	/* The number of layers. */
+	uint_fast16_t numlyrs;
+
+	/* The MCT to employ (if any). */
+	uint_fast8_t mctid;
+
+	/* The packet iterator (used to determine the order of packet
+	  generation). */
+	jpc_pi_t *pi;
+
+	/* The coding mode (i.e., integer or real). */
+	bool intmode;
+
+	/* The number of bytes to allocate to the various layers. */
+	uint_fast32_t *lyrsizes;
+
+	/* The number of tile-components. */
+	int numtcmpts;
+
+	/* The per tile-component information. */
+	jpc_enc_tcmpt_t *tcmpts;
+
+	/* The raw (i.e., uncompressed) size of this tile. */
+	uint_fast32_t rawsize;
+
+} jpc_enc_tile_t;
+
+/* Encoder class. */
+
+typedef struct jpc_enc_s {
+
+	/* The image being encoded. */
+	jas_image_t *image;
+
+	/* The output stream. */
+	jas_stream_t *out;
+
+	/* The coding parameters. */
+	jpc_enc_cp_t *cp;
+
+	/* The tile currently being processed. */
+	jpc_enc_tile_t *curtile;
+
+	/* The code stream state. */
+	jpc_cstate_t *cstate;
+
+	/* The number of bytes output so far. */
+	uint_fast32_t len;
+
+	/* The number of bytes available for the main body of the code stream. */
+	/* This is used for rate allocation purposes. */
+	uint_fast32_t mainbodysize;
+
+	/* The marker segment currently being processed. */
+	/* This member is a convenience for making cleanup easier. */
+	jpc_ms_t *mrk;
+
+	/* The stream used to temporarily hold tile-part data. */
+	jas_stream_t *tmpstream;
+
+} jpc_enc_t;
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_fix.h b/converter/other/jpeg2000/libjasper/jpc/jpc_fix.h
new file mode 100644
index 00000000..5ff0c9f8
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_fix.h
@@ -0,0 +1,193 @@
+/*
+ * 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__
+ */
+
+/*
+ * Fixed-Point Number Class
+ *
+ * $Id$
+ */
+
+#ifndef JPC_FIX_H
+#define JPC_FIX_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_fix.h"
+
+/******************************************************************************\
+* Basic parameters of the fixed-point type.
+\******************************************************************************/
+
+/* The integral type used to represent a fixed-point number.  This
+  type must be capable of representing values from -(2^31) to 2^31-1
+  (inclusive). */
+typedef int_fast32_t jpc_fix_t;
+
+/* The integral type used to respresent higher-precision intermediate results.
+  This type should be capable of representing values from -(2^63) to 2^63-1
+  (inclusive). */
+typedef int_fast64_t jpc_fix_big_t;
+
+/* The number of bits used for the fractional part of a fixed-point number. */
+#define JPC_FIX_FRACBITS	13
+
+/******************************************************************************\
+* Instantiations of the generic fixed-point number macros for the
+* parameters given above.  (Too bad C does not support templates, eh?)
+* The purpose of these macros is self-evident if one examines the
+* corresponding macros in the jasper/jas_fix.h header file.
+\******************************************************************************/
+
+#define	JPC_FIX_ZERO	JAS_FIX_ZERO(jpc_fix_t, JPC_FIX_FRACBITS)
+#define	JPC_FIX_ONE		JAS_FIX_ONE(jpc_fix_t, JPC_FIX_FRACBITS)
+#define	JPC_FIX_HALF	JAS_FIX_HALF(jpc_fix_t, JPC_FIX_FRACBITS)
+
+#define jpc_inttofix(x)	JAS_INTTOFIX(jpc_fix_t, JPC_FIX_FRACBITS, x)
+#define jpc_fixtoint(x)	JAS_FIXTOINT(jpc_fix_t, JPC_FIX_FRACBITS, x)
+#define jpc_fixtodbl(x)	JAS_FIXTODBL(jpc_fix_t, JPC_FIX_FRACBITS, x)
+#define jpc_dbltofix(x)	JAS_DBLTOFIX(jpc_fix_t, JPC_FIX_FRACBITS, x)
+
+#define	jpc_fix_add(x, y)	JAS_FIX_ADD(jpc_fix_t, JPC_FIX_FRACBITS, x, y)
+#define	jpc_fix_sub(x, y)	JAS_FIX_SUB(jpc_fix_t, JPC_FIX_FRACBITS, x, y)
+#define	jpc_fix_mul(x, y) \
+	JAS_FIX_MUL(jpc_fix_t, JPC_FIX_FRACBITS, jpc_fix_big_t, x, y)
+#define	jpc_fix_mulbyint(x, y) \
+	JAS_FIX_MULBYINT(jpc_fix_t, JPC_FIX_FRACBITS, x, y)
+#define	jpc_fix_div(x, y) \
+	JAS_FIX_DIV(jpc_fix_t, JPC_FIX_FRACBITS, jpc_fix_big_t, x, y)
+#define	jpc_fix_neg(x)		JAS_FIX_NEG(jpc_fix_t, JPC_FIX_FRACBITS, x)
+#define	jpc_fix_asl(x, n)	JAS_FIX_ASL(jpc_fix_t, JPC_FIX_FRACBITS, x, n)
+#define	jpc_fix_asr(x, n)	JAS_FIX_ASR(jpc_fix_t, JPC_FIX_FRACBITS, x, n)
+
+#define jpc_fix_pluseq(x, y)	JAS_FIX_PLUSEQ(jpc_fix_t, JPC_FIX_FRACBITS, x, y)
+#define jpc_fix_minuseq(x, y)	JAS_FIX_MINUSEQ(jpc_fix_t, JPC_FIX_FRACBITS, x, y)
+#define	jpc_fix_muleq(x, y)	\
+	JAS_FIX_MULEQ(jpc_fix_t, JPC_FIX_FRACBITS, jpc_fix_big_t, x, y)
+
+#define	jpc_fix_abs(x)		JAS_FIX_ABS(jpc_fix_t, JPC_FIX_FRACBITS, x)
+#define	jpc_fix_isint(x)	JAS_FIX_ISINT(jpc_fix_t, JPC_FIX_FRACBITS, x)
+#define jpc_fix_sgn(x)		JAS_FIX_SGN(jpc_fix_t, JPC_FIX_FRACBITS, x)
+#define	jpc_fix_round(x)	JAS_FIX_ROUND(jpc_fix_t, JPC_FIX_FRACBITS, x)
+#define	jpc_fix_floor(x)	JAS_FIX_FLOOR(jpc_fix_t, JPC_FIX_FRACBITS, x)
+#define jpc_fix_trunc(x)	JAS_FIX_TRUNC(jpc_fix_t, JPC_FIX_FRACBITS, x)
+
+/******************************************************************************\
+* Extra macros for convenience.
+\******************************************************************************/
+
+/* Compute the sum of three fixed-point numbers. */
+#define jpc_fix_add3(x, y, z)	jpc_fix_add(jpc_fix_add(x, y), z)
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_flt.h b/converter/other/jpeg2000/libjasper/jpc/jpc_flt.h
new file mode 100644
index 00000000..088eb00c
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_flt.h
@@ -0,0 +1,129 @@
+/*
+ * 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__
+ */
+
+/*
+ * Floating-Point Class
+ *
+ * $Id$
+ */
+
+#ifndef JPC_FLT_H
+#define JPC_FLT_H
+
+#include <float.h>
+
+/* The code ought to be modified so this type is not used at all. */
+/* Very few places in the code rely on floating-point arithmetic, aside
+  from conversions in printf's. */
+typedef double jpc_flt_t;
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_math.c b/converter/other/jpeg2000/libjasper/jpc/jpc_math.c
new file mode 100644
index 00000000..d860847d
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_math.c
@@ -0,0 +1,170 @@
+/*
+ * 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__
+ */
+
+/*
+ * Math Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes
+\******************************************************************************/
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "jpc_math.h"
+
+/******************************************************************************\
+* Miscellaneous Functions
+\******************************************************************************/
+
+/* Calculate the integer quantity floor(log2(x)), where x is a positive
+  integer. */
+int jpc_floorlog2(int x)
+{
+	int y;
+
+	/* The argument must be positive. */
+	assert(x > 0);
+
+	y = 0;
+	while (x > 1) {
+		x >>= 1;
+		++y;
+	}
+	return y;
+}
+
+/* Calculate the bit position of the first leading one in a nonnegative
+  integer. */
+/* This function is the basically the same as ceillog2(x), except that the
+  allowable range for x is slightly different. */
+int jpc_firstone(int x)
+{
+	int n;
+
+	/* The argument must be nonnegative. */
+	assert(x >= 0);
+
+	n = -1;
+	while (x > 0) {
+		x >>= 1;
+		++n;
+	}
+	return n;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_math.h b/converter/other/jpeg2000/libjasper/jpc/jpc_math.h
new file mode 100644
index 00000000..e343bab1
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_math.h
@@ -0,0 +1,155 @@
+/*
+ * 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__
+ */
+
+#ifndef	JPC_MATH_H
+#define	JPC_MATH_H
+
+/******************************************************************************\
+* Includes
+\******************************************************************************/
+
+#include	<assert.h>
+
+/******************************************************************************\
+* Macros
+\******************************************************************************/
+
+/* Compute the floor of the quotient of two integers. */
+#define	JPC_FLOORDIV(x, y)	(assert(x >= 0 && y > 0), (x) / (y))
+
+/* Compute the ceiling of the quotient of two integers. */
+#define	JPC_CEILDIV(x, y)	(assert(x >= 0 && y > 0), ((x) + (y) - 1) / (y))
+
+/* Compute the floor of (x / 2^y). */
+#define	JPC_FLOORDIVPOW2(x, y) \
+	(assert(x >= 0 && y > 0), (x) >> (y))
+
+/* Compute the ceiling of (x / 2^y). */
+#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)
+*/
+#define	JPC_CEILDIVPOW2U(x, y) \
+	(((x) + (1 << (y)) - 1) >> (y))
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Calculate the bit position of the first leading one in a nonnegative
+  integer. */
+int jpc_firstone(int x);
+
+/* Calculate the integer quantity floor(log2(x)), where x is a positive
+  integer. */
+int jpc_floorlog2(int x);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mct.c b/converter/other/jpeg2000/libjasper/jpc/jpc_mct.c
new file mode 100644
index 00000000..7c16c3e5
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mct.c
@@ -0,0 +1,337 @@
+/*
+ * 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__
+ */
+
+/*
+ * Multicomponent Transform Code
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <assert.h>
+
+#include "jasper/jas_seq.h"
+
+#include "jpc_fix.h"
+#include "jpc_mct.h"
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+/* Compute the forward RCT. */
+
+void jpc_rct(jas_matrix_t *c0, jas_matrix_t *c1, jas_matrix_t *c2)
+{
+	int numrows;
+	int numcols;
+	int i;
+	int j;
+	jpc_fix_t *c0p;
+	jpc_fix_t *c1p;
+	jpc_fix_t *c2p;
+
+	numrows = jas_matrix_numrows(c0);
+	numcols = jas_matrix_numcols(c0);
+
+	/* All three matrices must have the same dimensions. */
+	assert(jas_matrix_numrows(c1) == numrows && jas_matrix_numcols(c1) == numcols
+	  && jas_matrix_numrows(c2) == numrows && jas_matrix_numcols(c2) == numcols);
+
+	for (i = 0; i < numrows; i++) {
+		c0p = jas_matrix_getref(c0, i, 0);
+		c1p = jas_matrix_getref(c1, i, 0);
+		c2p = jas_matrix_getref(c2, i, 0);
+		for (j = numcols; j > 0; --j) {
+			int r;
+			int g;
+			int b;
+			int y;
+			int u;
+			int v;
+			r = *c0p;
+			g = *c1p;
+			b = *c2p;
+			y = (r + (g << 1) + b) >> 2;
+			u = b - g;
+			v = r - g;
+			*c0p++ = y;
+			*c1p++ = u;
+			*c2p++ = v;
+		}
+	}
+}
+
+/* Compute the inverse RCT. */
+
+void jpc_irct(jas_matrix_t *c0, jas_matrix_t *c1, jas_matrix_t *c2)
+{
+	int numrows;
+	int numcols;
+	int i;
+	int j;
+	jpc_fix_t *c0p;
+	jpc_fix_t *c1p;
+	jpc_fix_t *c2p;
+
+	numrows = jas_matrix_numrows(c0);
+	numcols = jas_matrix_numcols(c0);
+
+	/* All three matrices must have the same dimensions. */
+	assert(jas_matrix_numrows(c1) == numrows && jas_matrix_numcols(c1) == numcols
+	  && jas_matrix_numrows(c2) == numrows && jas_matrix_numcols(c2) == numcols);
+
+	for (i = 0; i < numrows; i++) {
+		c0p = jas_matrix_getref(c0, i, 0);
+		c1p = jas_matrix_getref(c1, i, 0);
+		c2p = jas_matrix_getref(c2, i, 0);
+		for (j = numcols; j > 0; --j) {
+			int r;
+			int g;
+			int b;
+			int y;
+			int u;
+			int v;
+			y = *c0p;
+			u = *c1p;
+			v = *c2p;
+			g = y - ((u + v) >> 2);
+			r = v + g;
+			b = u + g;
+			*c0p++ = r;
+			*c1p++ = g;
+			*c2p++ = b;
+		}
+	}
+}
+
+void jpc_ict(jas_matrix_t *c0, jas_matrix_t *c1, jas_matrix_t *c2)
+{
+	int numrows;
+	int numcols;
+	int i;
+	int j;
+	jpc_fix_t r;
+	jpc_fix_t g;
+	jpc_fix_t b;
+	jpc_fix_t y;
+	jpc_fix_t u;
+	jpc_fix_t v;
+	jpc_fix_t *c0p;
+	jpc_fix_t *c1p;
+	jpc_fix_t *c2p;
+
+	numrows = jas_matrix_numrows(c0);
+	assert(jas_matrix_numrows(c1) == numrows && jas_matrix_numrows(c2) == numrows);
+	numcols = jas_matrix_numcols(c0);
+	assert(jas_matrix_numcols(c1) == numcols && jas_matrix_numcols(c2) == numcols);
+	for (i = 0; i < numrows; ++i) {
+		c0p = jas_matrix_getref(c0, i, 0);
+		c1p = jas_matrix_getref(c1, i, 0);
+		c2p = jas_matrix_getref(c2, i, 0);
+		for (j = numcols; j > 0; --j) {
+			r = *c0p;
+			g = *c1p;
+			b = *c2p;
+			y = jpc_fix_add3(jpc_fix_mul(jpc_dbltofix(0.299), r), jpc_fix_mul(jpc_dbltofix(0.587), g),
+			  jpc_fix_mul(jpc_dbltofix(0.114), b));
+			u = jpc_fix_add3(jpc_fix_mul(jpc_dbltofix(-0.16875), r), jpc_fix_mul(jpc_dbltofix(-0.33126), g),
+			  jpc_fix_mul(jpc_dbltofix(0.5), b));
+			v = jpc_fix_add3(jpc_fix_mul(jpc_dbltofix(0.5), r), jpc_fix_mul(jpc_dbltofix(-0.41869), g),
+			  jpc_fix_mul(jpc_dbltofix(-0.08131), b));
+			*c0p++ = y;
+			*c1p++ = u;
+			*c2p++ = v;
+		}
+	}
+}
+
+void jpc_iict(jas_matrix_t *c0, jas_matrix_t *c1, jas_matrix_t *c2)
+{
+	int numrows;
+	int numcols;
+	int i;
+	int j;
+	jpc_fix_t r;
+	jpc_fix_t g;
+	jpc_fix_t b;
+	jpc_fix_t y;
+	jpc_fix_t u;
+	jpc_fix_t v;
+	jpc_fix_t *c0p;
+	jpc_fix_t *c1p;
+	jpc_fix_t *c2p;
+
+	numrows = jas_matrix_numrows(c0);
+	assert(jas_matrix_numrows(c1) == numrows && jas_matrix_numrows(c2) == numrows);
+	numcols = jas_matrix_numcols(c0);
+	assert(jas_matrix_numcols(c1) == numcols && jas_matrix_numcols(c2) == numcols);
+	for (i = 0; i < numrows; ++i) {
+		c0p = jas_matrix_getref(c0, i, 0);
+		c1p = jas_matrix_getref(c1, i, 0);
+		c2p = jas_matrix_getref(c2, i, 0);
+		for (j = numcols; j > 0; --j) {
+			y = *c0p;
+			u = *c1p;
+			v = *c2p;
+			r = jpc_fix_add(y, jpc_fix_mul(jpc_dbltofix(1.402), v));
+			g = jpc_fix_add3(y, jpc_fix_mul(jpc_dbltofix(-0.34413), u),
+			  jpc_fix_mul(jpc_dbltofix(-0.71414), v));
+			b = jpc_fix_add(y, jpc_fix_mul(jpc_dbltofix(1.772), u));
+			*c0p++ = r;
+			*c1p++ = g;
+			*c2p++ = b;
+		}
+	}
+}
+
+jpc_fix_t jpc_mct_getsynweight(int mctid, int cmptno)
+{
+	jpc_fix_t synweight;
+
+	switch (mctid) {
+	case JPC_MCT_RCT:
+		switch (cmptno) {
+		case 0:
+			synweight = jpc_dbltofix(sqrt(3.0));
+			break;
+		case 1:
+			synweight = jpc_dbltofix(sqrt(0.6875));
+			break;
+		case 2:
+			synweight = jpc_dbltofix(sqrt(0.6875));
+			break;
+		}
+		break;
+	case JPC_MCT_ICT:
+		switch (cmptno) {
+		case 0:
+			synweight = jpc_dbltofix(sqrt(3.0000));
+			break;
+		case 1:
+			synweight = jpc_dbltofix(sqrt(3.2584));
+			break;
+		case 2:
+			synweight = jpc_dbltofix(sqrt(2.4755));
+			break;
+		}
+		break;
+	default:
+		synweight = JPC_FIX_ONE;
+		break;
+	}
+
+	return synweight;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mct.h b/converter/other/jpeg2000/libjasper/jpc/jpc_mct.h
new file mode 100644
index 00000000..d03d6ce1
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mct.h
@@ -0,0 +1,160 @@
+/*
+ * 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__
+ */
+
+/*
+ * Multicomponent Transform Code
+ *
+ * $Id$
+ */
+
+#ifndef JPC_MCT_H
+#define JPC_MCT_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_seq.h"
+#include "jasper/jas_fix.h"
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/*
+ * Multicomponent transform IDs.
+ */
+
+#define JPC_MCT_NONE	0
+#define JPC_MCT_ICT		1
+#define JPC_MCT_RCT		2
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Calculate the forward RCT. */
+void jpc_rct(jas_matrix_t *c0, jas_matrix_t *c1, jas_matrix_t *c2);
+
+/* Calculate the inverse RCT. */
+void jpc_irct(jas_matrix_t *c0, jas_matrix_t *c1, jas_matrix_t *c2);
+
+/* Calculate the forward ICT. */
+void jpc_ict(jas_matrix_t *c0, jas_matrix_t *c1, jas_matrix_t *c2);
+
+/* Calculate the inverse ICT. */
+void jpc_iict(jas_matrix_t *c0, jas_matrix_t *c1, jas_matrix_t *c2);
+
+/* Get the synthesis weight associated with a particular component. */
+jpc_fix_t jpc_mct_getsynweight(int mctid, int cmptno);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.c b/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.c
new file mode 100644
index 00000000..535eaa2d
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.c
@@ -0,0 +1,228 @@
+/*
+ * 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__
+ */
+
+/*
+ * MQ Arithmetic Coder
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_malloc.h"
+
+#include "jpc_mqcod.h"
+
+/******************************************************************************\
+* Data.
+\******************************************************************************/
+
+/* MQ coder per-state information. */
+
+jpc_mqstate_t jpc_mqstates[47 * 2] = {
+	{0x5601, 0, &jpc_mqstates[ 2], &jpc_mqstates[ 3]},
+	{0x5601, 1, &jpc_mqstates[ 3], &jpc_mqstates[ 2]},
+	{0x3401, 0, &jpc_mqstates[ 4], &jpc_mqstates[12]},
+	{0x3401, 1, &jpc_mqstates[ 5], &jpc_mqstates[13]},
+	{0x1801, 0, &jpc_mqstates[ 6], &jpc_mqstates[18]},
+	{0x1801, 1, &jpc_mqstates[ 7], &jpc_mqstates[19]},
+	{0x0ac1, 0, &jpc_mqstates[ 8], &jpc_mqstates[24]},
+	{0x0ac1, 1, &jpc_mqstates[ 9], &jpc_mqstates[25]},
+	{0x0521, 0, &jpc_mqstates[10], &jpc_mqstates[58]},
+	{0x0521, 1, &jpc_mqstates[11], &jpc_mqstates[59]},
+	{0x0221, 0, &jpc_mqstates[76], &jpc_mqstates[66]},
+	{0x0221, 1, &jpc_mqstates[77], &jpc_mqstates[67]},
+	{0x5601, 0, &jpc_mqstates[14], &jpc_mqstates[13]},
+	{0x5601, 1, &jpc_mqstates[15], &jpc_mqstates[12]},
+	{0x5401, 0, &jpc_mqstates[16], &jpc_mqstates[28]},
+	{0x5401, 1, &jpc_mqstates[17], &jpc_mqstates[29]},
+	{0x4801, 0, &jpc_mqstates[18], &jpc_mqstates[28]},
+	{0x4801, 1, &jpc_mqstates[19], &jpc_mqstates[29]},
+	{0x3801, 0, &jpc_mqstates[20], &jpc_mqstates[28]},
+	{0x3801, 1, &jpc_mqstates[21], &jpc_mqstates[29]},
+	{0x3001, 0, &jpc_mqstates[22], &jpc_mqstates[34]},
+	{0x3001, 1, &jpc_mqstates[23], &jpc_mqstates[35]},
+	{0x2401, 0, &jpc_mqstates[24], &jpc_mqstates[36]},
+	{0x2401, 1, &jpc_mqstates[25], &jpc_mqstates[37]},
+	{0x1c01, 0, &jpc_mqstates[26], &jpc_mqstates[40]},
+	{0x1c01, 1, &jpc_mqstates[27], &jpc_mqstates[41]},
+	{0x1601, 0, &jpc_mqstates[58], &jpc_mqstates[42]},
+	{0x1601, 1, &jpc_mqstates[59], &jpc_mqstates[43]},
+	{0x5601, 0, &jpc_mqstates[30], &jpc_mqstates[29]},
+	{0x5601, 1, &jpc_mqstates[31], &jpc_mqstates[28]},
+	{0x5401, 0, &jpc_mqstates[32], &jpc_mqstates[28]},
+	{0x5401, 1, &jpc_mqstates[33], &jpc_mqstates[29]},
+	{0x5101, 0, &jpc_mqstates[34], &jpc_mqstates[30]},
+	{0x5101, 1, &jpc_mqstates[35], &jpc_mqstates[31]},
+	{0x4801, 0, &jpc_mqstates[36], &jpc_mqstates[32]},
+	{0x4801, 1, &jpc_mqstates[37], &jpc_mqstates[33]},
+	{0x3801, 0, &jpc_mqstates[38], &jpc_mqstates[34]},
+	{0x3801, 1, &jpc_mqstates[39], &jpc_mqstates[35]},
+	{0x3401, 0, &jpc_mqstates[40], &jpc_mqstates[36]},
+	{0x3401, 1, &jpc_mqstates[41], &jpc_mqstates[37]},
+	{0x3001, 0, &jpc_mqstates[42], &jpc_mqstates[38]},
+	{0x3001, 1, &jpc_mqstates[43], &jpc_mqstates[39]},
+	{0x2801, 0, &jpc_mqstates[44], &jpc_mqstates[38]},
+	{0x2801, 1, &jpc_mqstates[45], &jpc_mqstates[39]},
+	{0x2401, 0, &jpc_mqstates[46], &jpc_mqstates[40]},
+	{0x2401, 1, &jpc_mqstates[47], &jpc_mqstates[41]},
+	{0x2201, 0, &jpc_mqstates[48], &jpc_mqstates[42]},
+	{0x2201, 1, &jpc_mqstates[49], &jpc_mqstates[43]},
+	{0x1c01, 0, &jpc_mqstates[50], &jpc_mqstates[44]},
+	{0x1c01, 1, &jpc_mqstates[51], &jpc_mqstates[45]},
+	{0x1801, 0, &jpc_mqstates[52], &jpc_mqstates[46]},
+	{0x1801, 1, &jpc_mqstates[53], &jpc_mqstates[47]},
+	{0x1601, 0, &jpc_mqstates[54], &jpc_mqstates[48]},
+	{0x1601, 1, &jpc_mqstates[55], &jpc_mqstates[49]},
+	{0x1401, 0, &jpc_mqstates[56], &jpc_mqstates[50]},
+	{0x1401, 1, &jpc_mqstates[57], &jpc_mqstates[51]},
+	{0x1201, 0, &jpc_mqstates[58], &jpc_mqstates[52]},
+	{0x1201, 1, &jpc_mqstates[59], &jpc_mqstates[53]},
+	{0x1101, 0, &jpc_mqstates[60], &jpc_mqstates[54]},
+	{0x1101, 1, &jpc_mqstates[61], &jpc_mqstates[55]},
+	{0x0ac1, 0, &jpc_mqstates[62], &jpc_mqstates[56]},
+	{0x0ac1, 1, &jpc_mqstates[63], &jpc_mqstates[57]},
+	{0x09c1, 0, &jpc_mqstates[64], &jpc_mqstates[58]},
+	{0x09c1, 1, &jpc_mqstates[65], &jpc_mqstates[59]},
+	{0x08a1, 0, &jpc_mqstates[66], &jpc_mqstates[60]},
+	{0x08a1, 1, &jpc_mqstates[67], &jpc_mqstates[61]},
+	{0x0521, 0, &jpc_mqstates[68], &jpc_mqstates[62]},
+	{0x0521, 1, &jpc_mqstates[69], &jpc_mqstates[63]},
+	{0x0441, 0, &jpc_mqstates[70], &jpc_mqstates[64]},
+	{0x0441, 1, &jpc_mqstates[71], &jpc_mqstates[65]},
+	{0x02a1, 0, &jpc_mqstates[72], &jpc_mqstates[66]},
+	{0x02a1, 1, &jpc_mqstates[73], &jpc_mqstates[67]},
+	{0x0221, 0, &jpc_mqstates[74], &jpc_mqstates[68]},
+	{0x0221, 1, &jpc_mqstates[75], &jpc_mqstates[69]},
+	{0x0141, 0, &jpc_mqstates[76], &jpc_mqstates[70]},
+	{0x0141, 1, &jpc_mqstates[77], &jpc_mqstates[71]},
+	{0x0111, 0, &jpc_mqstates[78], &jpc_mqstates[72]},
+	{0x0111, 1, &jpc_mqstates[79], &jpc_mqstates[73]},
+	{0x0085, 0, &jpc_mqstates[80], &jpc_mqstates[74]},
+	{0x0085, 1, &jpc_mqstates[81], &jpc_mqstates[75]},
+	{0x0049, 0, &jpc_mqstates[82], &jpc_mqstates[76]},
+	{0x0049, 1, &jpc_mqstates[83], &jpc_mqstates[77]},
+	{0x0025, 0, &jpc_mqstates[84], &jpc_mqstates[78]},
+	{0x0025, 1, &jpc_mqstates[85], &jpc_mqstates[79]},
+	{0x0015, 0, &jpc_mqstates[86], &jpc_mqstates[80]},
+	{0x0015, 1, &jpc_mqstates[87], &jpc_mqstates[81]},
+	{0x0009, 0, &jpc_mqstates[88], &jpc_mqstates[82]},
+	{0x0009, 1, &jpc_mqstates[89], &jpc_mqstates[83]},
+	{0x0005, 0, &jpc_mqstates[90], &jpc_mqstates[84]},
+	{0x0005, 1, &jpc_mqstates[91], &jpc_mqstates[85]},
+	{0x0001, 0, &jpc_mqstates[90], &jpc_mqstates[86]},
+	{0x0001, 1, &jpc_mqstates[91], &jpc_mqstates[87]},
+	{0x5601, 0, &jpc_mqstates[92], &jpc_mqstates[92]},
+	{0x5601, 1, &jpc_mqstates[93], &jpc_mqstates[93]},
+};
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h b/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h
new file mode 100644
index 00000000..914f8e8a
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.h
@@ -0,0 +1,174 @@
+/*
+ * 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__
+ */
+
+/*
+ * MQ Arithmetic Coder
+ *
+ * $Id$
+ */
+
+#ifndef JPC_MQCOD_H
+#define JPC_MQCOD_H
+
+/*****************************************************************************\
+* Includes.
+\*****************************************************************************/
+
+#include "pm_c_util.h"
+#include "jasper/jas_types.h"
+
+/*****************************************************************************\
+* Types.
+\*****************************************************************************/
+
+/*
+ * MQ coder context information.
+ */
+
+typedef struct {
+
+	/* The most probable symbol (MPS). */
+	bool mps;
+
+	/* The state index. */
+	int_fast16_t ind;
+
+} jpc_mqctx_t;
+
+/*
+ * MQ coder state table entry.
+ */
+
+typedef struct jpc_mqstate_s {
+
+	/* The Qe value. */
+	uint_fast16_t qeval;
+
+	/* The MPS. */
+	uint_fast16_t mps;
+
+	/* The NMPS state. */
+	struct jpc_mqstate_s *nmps;
+
+	/* The NLPS state. */
+	struct jpc_mqstate_s *nlps;
+
+} jpc_mqstate_t;
+
+/******************************************************************************\
+* Data.
+\******************************************************************************/
+
+/* The state table for the MQ coder. */
+extern jpc_mqstate_t jpc_mqstates[];
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqdec.c b/converter/other/jpeg2000/libjasper/jpc/jpc_mqdec.c
new file mode 100644
index 00000000..f58a1c7d
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqdec.c
@@ -0,0 +1,339 @@
+/*
+ * 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__
+ */
+
+/*
+ * MQ Arithmetic Decoder
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_math.h"
+#include "jasper/jas_debug.h"
+
+#include "jpc_mqdec.h"
+
+/******************************************************************************\
+* Local macros.
+\******************************************************************************/
+
+#if defined(DEBUG)
+#define	MQDEC_CALL(n, x) \
+	((jas_getdbglevel() >= (n)) ? ((void)(x)) : ((void)0))
+#else
+#define	MQDEC_CALL(n, x)
+#endif
+
+/******************************************************************************\
+* Local function prototypes.
+\******************************************************************************/
+
+static void jpc_mqdec_bytein(jpc_mqdec_t *mqdec);
+
+/******************************************************************************\
+* Code for creation and destruction of a MQ decoder.
+\******************************************************************************/
+
+/* Create a MQ decoder. */
+jpc_mqdec_t *jpc_mqdec_create(int maxctxs, jas_stream_t *in)
+{
+	jpc_mqdec_t *mqdec;
+
+	/* There must be at least one context. */
+	assert(maxctxs > 0);
+
+	/* Allocate memory for the MQ decoder. */
+	if (!(mqdec = jas_malloc(sizeof(jpc_mqdec_t)))) {
+		goto error;
+	}
+	mqdec->in = in;
+	mqdec->maxctxs = maxctxs;
+	/* Allocate memory for the per-context state information. */
+	if (!(mqdec->ctxs = jas_malloc(mqdec->maxctxs * sizeof(jpc_mqstate_t *)))) {
+		goto error;
+	}
+	/* Set the current context to the first context. */
+	mqdec->curctx = mqdec->ctxs;
+
+	/* If an input stream has been associated with the MQ decoder,
+	  initialize the decoder state from the stream. */
+	if (mqdec->in) {
+		jpc_mqdec_init(mqdec);
+	}
+	/* Initialize the per-context state information. */
+	jpc_mqdec_setctxs(mqdec, 0, 0);
+
+	return mqdec;
+
+error:
+	/* Oops...  Something has gone wrong. */
+	if (mqdec) {
+		jpc_mqdec_destroy(mqdec);
+	}
+	return 0;
+}
+
+/* Destroy a MQ decoder. */
+void jpc_mqdec_destroy(jpc_mqdec_t *mqdec)
+{
+	if (mqdec->ctxs) {
+		jas_free(mqdec->ctxs);
+	}
+	jas_free(mqdec);
+}
+
+/******************************************************************************\
+* Code for initialization of a MQ decoder.
+\******************************************************************************/
+
+/* Initialize the state of a MQ decoder. */
+
+void jpc_mqdec_init(jpc_mqdec_t *mqdec)
+{
+	int c;
+
+	mqdec->eof = 0;
+	mqdec->creg = 0;
+	/* Get the next byte from the input stream. */
+	if ((c = jas_stream_getc(mqdec->in)) == EOF) {
+		/* We have encountered an I/O error or EOF. */
+		c = 0xff;
+		mqdec->eof = 1;
+	}
+	mqdec->inbuffer = c;
+	mqdec->creg += mqdec->inbuffer << 16;
+	jpc_mqdec_bytein(mqdec);
+	mqdec->creg <<= 7;
+	mqdec->ctreg -= 7;
+	mqdec->areg = 0x8000;
+}
+
+/* Set the input stream for a MQ decoder. */
+
+void jpc_mqdec_setinput(jpc_mqdec_t *mqdec, jas_stream_t *in)
+{
+	mqdec->in = in;
+}
+
+/* Initialize one or more contexts. */
+
+void jpc_mqdec_setctxs(jpc_mqdec_t *mqdec, int numctxs, jpc_mqctx_t *ctxs)
+{
+	jpc_mqstate_t **ctx;
+	int n;
+
+	ctx = mqdec->ctxs;
+	n = JAS_MIN(mqdec->maxctxs, numctxs);
+	while (--n >= 0) {
+		*ctx = &jpc_mqstates[2 * ctxs->ind + ctxs->mps];
+		++ctx;
+		++ctxs;
+	}
+	n = mqdec->maxctxs - numctxs;
+	while (--n >= 0) {
+		*ctx = &jpc_mqstates[0];
+		++ctx;
+	}
+}
+
+/* Initialize a context. */
+
+void jpc_mqdec_setctx(jpc_mqdec_t *mqdec, int ctxno, jpc_mqctx_t *ctx)
+{
+	jpc_mqstate_t **ctxi;
+	ctxi = &mqdec->ctxs[ctxno];
+	*ctxi = &jpc_mqstates[2 * ctx->ind + ctx->mps];
+}
+
+/******************************************************************************\
+* Code for decoding a bit.
+\******************************************************************************/
+
+/* Decode a bit. */
+
+int jpc_mqdec_getbit_func(register jpc_mqdec_t *mqdec)
+{
+	int bit;
+	JAS_DBGLOG(100, ("jpc_mqdec_getbit_func(%p)\n", mqdec));
+	MQDEC_CALL(100, jpc_mqdec_dump(mqdec, stderr));
+	bit = jpc_mqdec_getbit_macro(mqdec);
+	MQDEC_CALL(100, jpc_mqdec_dump(mqdec, stderr));
+	JAS_DBGLOG(100, ("ctx = %d, decoded %d\n", mqdec->curctx -
+	  mqdec->ctxs, bit));
+	return bit;
+}
+
+/* Apply MPS_EXCHANGE algorithm (with RENORMD). */
+int jpc_mqdec_mpsexchrenormd(register jpc_mqdec_t *mqdec)
+{
+	int ret;
+	register jpc_mqstate_t *state = *mqdec->curctx;
+	jpc_mqdec_mpsexchange(mqdec->areg, state->qeval, mqdec->curctx, ret);
+	jpc_mqdec_renormd(mqdec->areg, mqdec->creg, mqdec->ctreg, mqdec->in,
+	  mqdec->eof, mqdec->inbuffer);
+	return ret;
+}
+
+/* Apply LPS_EXCHANGE algorithm (with RENORMD). */
+int jpc_mqdec_lpsexchrenormd(register jpc_mqdec_t *mqdec)
+{
+	int ret;
+	register jpc_mqstate_t *state = *mqdec->curctx;
+	jpc_mqdec_lpsexchange(mqdec->areg, state->qeval, mqdec->curctx, ret);
+	jpc_mqdec_renormd(mqdec->areg, mqdec->creg, mqdec->ctreg, mqdec->in,
+	  mqdec->eof, mqdec->inbuffer);
+	return ret;
+}
+
+/******************************************************************************\
+* Support code.
+\******************************************************************************/
+
+/* Apply the BYTEIN algorithm. */
+static void jpc_mqdec_bytein(jpc_mqdec_t *mqdec)
+{
+	int c;
+	unsigned char prevbuf;
+
+	if (!mqdec->eof) {
+		if ((c = jas_stream_getc(mqdec->in)) == EOF) {
+			mqdec->eof = 1;
+			c = 0xff;
+		}
+		prevbuf = mqdec->inbuffer;
+		mqdec->inbuffer = c;
+		if (prevbuf == 0xff) {
+			if (c > 0x8f) {
+				mqdec->creg += 0xff00;
+				mqdec->ctreg = 8;
+			} else {
+				mqdec->creg += c << 9;
+				mqdec->ctreg = 7;
+			}
+		} else {
+			mqdec->creg += c << 8;
+			mqdec->ctreg = 8;
+		}
+	} else {
+		mqdec->creg += 0xff00;
+		mqdec->ctreg = 8;
+	}
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqdec.h b/converter/other/jpeg2000/libjasper/jpc/jpc_mqdec.h
new file mode 100644
index 00000000..30185506
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqdec.h
@@ -0,0 +1,320 @@
+/*
+ * 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__
+ */
+
+/*
+ * MQ Arithmetic Decoder
+ *
+ * $Id$
+ */
+
+#ifndef JPC_MQDEC_H
+#define JPC_MQDEC_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_stream.h"
+
+#include "jpc_mqcod.h"
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/* MQ arithmetic decoder. */
+
+typedef struct {
+
+	/* The C register. */
+	uint_fast32_t creg;
+
+	/* The A register. */
+	uint_fast32_t areg;
+
+	/* The CT register. */
+	uint_fast32_t ctreg;
+
+	/* The current context. */
+	jpc_mqstate_t **curctx;
+
+	/* The per-context information. */
+	jpc_mqstate_t **ctxs;
+
+	/* The maximum number of contexts. */
+	int maxctxs;
+
+	/* The stream from which to read data. */
+	jas_stream_t *in;
+
+	/* The last character read. */
+	unsigned char inbuffer;
+
+	/* The EOF indicator. */
+	int eof;
+
+} jpc_mqdec_t;
+
+/******************************************************************************\
+* Functions/macros for construction and destruction.
+\******************************************************************************/
+
+/* Create a MQ decoder. */
+jpc_mqdec_t *jpc_mqdec_create(int maxctxs, jas_stream_t *in);
+
+/* Destroy a MQ decoder. */
+void jpc_mqdec_destroy(jpc_mqdec_t *dec);
+
+/******************************************************************************\
+* Functions/macros for initialization.
+\******************************************************************************/
+
+/* Set the input stream associated with a MQ decoder. */
+void jpc_mqdec_setinput(jpc_mqdec_t *dec, jas_stream_t *in);
+
+/* Initialize a MQ decoder. */
+void jpc_mqdec_init(jpc_mqdec_t *dec);
+
+/******************************************************************************\
+* Functions/macros for manipulating contexts.
+\******************************************************************************/
+
+/* Set the current context for a MQ decoder. */
+#define	jpc_mqdec_setcurctx(dec, ctxno) \
+	((mqdec)->curctx = &(mqdec)->ctxs[ctxno]);
+
+/* Set the state information for a particular context of a MQ decoder. */
+void jpc_mqdec_setctx(jpc_mqdec_t *dec, int ctxno, jpc_mqctx_t *ctx);
+
+/* Set the state information for all contexts of a MQ decoder. */
+void jpc_mqdec_setctxs(jpc_mqdec_t *dec, int numctxs, jpc_mqctx_t *ctxs);
+
+/******************************************************************************\
+* Functions/macros for decoding bits.
+\******************************************************************************/
+
+/* Decode a symbol. */
+#if !defined(DEBUG)
+#define	jpc_mqdec_getbit(dec) \
+	jpc_mqdec_getbit_macro(dec)
+#else
+#define	jpc_mqdec_getbit(dec) \
+	jpc_mqdec_getbit_func(dec)
+#endif
+
+/* Decode a symbol (assuming an unskewed probability distribution). */
+#if !defined(DEBUG)
+#define	jpc_mqdec_getbitnoskew(dec) \
+	jpc_mqdec_getbit_macro(dec)
+#else
+#define	jpc_mqdec_getbitnoskew(dec) \
+	jpc_mqdec_getbit_func(dec)
+#endif
+
+/******************************************************************************\
+* Functions/macros for debugging.
+\******************************************************************************/
+
+/* Dump the MQ decoder state for debugging. */
+void mqdec_dump(jpc_mqdec_t *dec, FILE *out);
+
+/******************************************************************************\
+* EVERYTHING BELOW THIS POINT IS IMPLEMENTATION SPECIFIC AND NOT PART OF THE
+* APPLICATION INTERFACE.  DO NOT RELY ON ANY OF THE INTERNAL FUNCTIONS/MACROS
+* GIVEN BELOW.
+\******************************************************************************/
+
+#define	jpc_mqdec_getbit_macro(dec) \
+	((((dec)->areg -= (*(dec)->curctx)->qeval), \
+	  (dec)->creg >> 16 >= (*(dec)->curctx)->qeval) ? \
+	  ((((dec)->creg -= (*(dec)->curctx)->qeval << 16), \
+	  (dec)->areg & 0x8000) ?  (*(dec)->curctx)->mps : \
+	  jpc_mqdec_mpsexchrenormd(dec)) : \
+	  jpc_mqdec_lpsexchrenormd(dec))
+
+#define	jpc_mqdec_mpsexchange(areg, delta, curctx, bit) \
+{ \
+	if ((areg) < (delta)) { \
+		register jpc_mqstate_t *state = *(curctx); \
+		/* LPS decoded. */ \
+		(bit) = state->mps ^ 1; \
+		*(curctx) = state->nlps; \
+	} else { \
+		register jpc_mqstate_t *state = *(curctx); \
+		/* MPS decoded. */ \
+		(bit) = state->mps; \
+		*(curctx) = state->nmps; \
+	} \
+}
+
+#define	jpc_mqdec_lpsexchange(areg, delta, curctx, bit) \
+{ \
+	if ((areg) >= (delta)) { \
+		register jpc_mqstate_t *state = *(curctx); \
+		(areg) = (delta); \
+		(bit) = state->mps ^ 1; \
+		*(curctx) = state->nlps; \
+	} else { \
+		register jpc_mqstate_t *state = *(curctx); \
+		(areg) = (delta); \
+		(bit) = state->mps; \
+		*(curctx) = state->nmps; \
+	} \
+}
+
+#define	jpc_mqdec_renormd(areg, creg, ctreg, in, eof, inbuf) \
+{ \
+	do { \
+		if (!(ctreg)) { \
+			jpc_mqdec_bytein2(creg, ctreg, in, eof, inbuf); \
+		} \
+		(areg) <<= 1; \
+		(creg) <<= 1; \
+		--(ctreg); \
+	} while (!((areg) & 0x8000)); \
+}
+
+#define	jpc_mqdec_bytein2(creg, ctreg, in, eof, inbuf) \
+{ \
+	int c; \
+	unsigned char prevbuf; \
+	if (!(eof)) { \
+		if ((c = jas_stream_getc(in)) == EOF) { \
+			(eof) = 1; \
+			c = 0xff; \
+		} \
+		prevbuf = (inbuf); \
+		(inbuf) = c; \
+		if (prevbuf == 0xff) { \
+			if (c > 0x8f) { \
+				(creg) += 0xff00; \
+				(ctreg) = 8; \
+			} else { \
+				(creg) += c << 9; \
+				(ctreg) = 7; \
+			} \
+		} else { \
+			(creg) += c << 8; \
+			(ctreg) = 8; \
+		} \
+	} else { \
+		(creg) += 0xff00; \
+		(ctreg) = 8; \
+	} \
+}
+
+int jpc_mqdec_getbit_func(jpc_mqdec_t *dec);
+int jpc_mqdec_mpsexchrenormd(jpc_mqdec_t *dec);
+int jpc_mqdec_lpsexchrenormd(jpc_mqdec_t *dec);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c
new file mode 100644
index 00000000..0219a000
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.c
@@ -0,0 +1,441 @@
+/*
+ * 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__
+ */
+
+/*
+ * MQ Arithmetic Encoder
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "jasper/jas_stream.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_math.h"
+#include "jasper/jas_debug.h"
+
+#include "jpc_mqenc.h"
+
+/******************************************************************************\
+* Macros
+\******************************************************************************/
+
+#if defined(DEBUG)
+#define	JPC_MQENC_CALL(n, x) \
+	((jas_getdbglevel() >= (n)) ? ((void)(x)) : ((void)0))
+#else
+#define	JPC_MQENC_CALL(n, x)
+#endif
+
+#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; \
+	} \
+}
+
+#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)); \
+}
+
+#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)); \
+}
+
+#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; \
+	} \
+}
+
+#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; \
+}
+
+/******************************************************************************\
+* Local function protoypes.
+\******************************************************************************/
+
+static void jpc_mqenc_setbits(jpc_mqenc_t *mqenc);
+
+/******************************************************************************\
+* Code for creation and destruction of encoder.
+\******************************************************************************/
+
+/* Create a MQ encoder. */
+
+jpc_mqenc_t *jpc_mqenc_create(int maxctxs, jas_stream_t *out)
+{
+	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 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;
+
+	jpc_mqenc_init(mqenc);
+
+	/* Initialize the per-context state information to something sane. */
+	jpc_mqenc_setctxs(mqenc, 0, 0);
+
+	return mqenc;
+
+error:
+	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);
+}
+
+/******************************************************************************\
+* State initialization code.
+\******************************************************************************/
+
+/* Initialize the coding state of a MQ encoder. */
+
+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;
+}
+
+/* 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;
+	}
+
+}
+
+/* Get the coding state for a MQ encoder. */
+
+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;
+}
+
+/******************************************************************************\
+* Code for coding symbols.
+\******************************************************************************/
+
+/* Encode a bit. */
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+/******************************************************************************\
+* Miscellaneous code.
+\******************************************************************************/
+
+/* Terminate the code word. */
+
+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;
+}
+
+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;
+	}
+}
+
+/* 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;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.h b/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.h
new file mode 100644
index 00000000..1421ae4d
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.h
@@ -0,0 +1,285 @@
+/*
+ * 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__
+ */
+
+/*
+ * MQ Arithmetic Encoder
+ *
+ * $Id$
+ */
+
+#ifndef JPC_MQENC_H
+#define JPC_MQENC_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_stream.h"
+
+#include "jpc_mqcod.h"
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/*
+ * Termination modes.
+ */
+
+#define	JPC_MQENC_DEFTERM	0	/* default termination */
+#define	JPC_MQENC_PTERM		1	/* predictable termination */
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/* MQ arithmetic encoder class. */
+
+typedef struct {
+
+	/* The C register. */
+	uint_fast32_t creg;
+
+	/* The A register. */
+	uint_fast32_t areg;
+
+	/* The CT register. */
+	uint_fast32_t ctreg;
+
+	/* The maximum number of contexts. */
+	int maxctxs;
+
+	/* The per-context information. */
+	jpc_mqstate_t **ctxs;
+
+	/* The current context. */
+	jpc_mqstate_t **curctx;
+
+	/* The stream for encoder output. */
+	jas_stream_t *out;
+
+	/* The byte buffer (i.e., the B variable in the standard). */
+	int_fast16_t outbuf;
+
+	/* The last byte output. */
+	int_fast16_t lastbyte;
+
+	/* The error indicator. */
+	int err;
+	
+} jpc_mqenc_t;
+
+/* MQ arithmetic encoder state information. */
+
+typedef struct {
+
+	/* The A register. */
+	unsigned areg;
+
+	/* The C register. */
+	unsigned creg;
+
+	/* The CT register. */
+	unsigned ctreg;
+
+	/* The last byte output by the encoder. */
+	int lastbyte;
+
+} jpc_mqencstate_t;
+
+/******************************************************************************\
+* Functions/macros for construction and destruction.
+\******************************************************************************/
+
+/* Create a MQ encoder. */
+jpc_mqenc_t *jpc_mqenc_create(int maxctxs, jas_stream_t *out);
+
+/* Destroy a MQ encoder. */
+void jpc_mqenc_destroy(jpc_mqenc_t *enc);
+
+/******************************************************************************\
+* Functions/macros for initialization.
+\******************************************************************************/
+
+/* Initialize a MQ encoder. */
+void jpc_mqenc_init(jpc_mqenc_t *enc);
+
+/******************************************************************************\
+* Functions/macros for context manipulation.
+\******************************************************************************/
+
+/* Set the current context. */
+#define	jpc_mqenc_setcurctx(enc, ctxno) \
+        ((enc)->curctx = &(enc)->ctxs[ctxno]);
+
+/* Set the state information for a particular context. */
+void jpc_mqenc_setctx(jpc_mqenc_t *enc, int ctxno, jpc_mqctx_t *ctx);
+
+/* Set the state information for multiple contexts. */
+void jpc_mqenc_setctxs(jpc_mqenc_t *enc, int numctxs, jpc_mqctx_t *ctxs);
+
+/******************************************************************************\
+* Miscellaneous functions/macros.
+\******************************************************************************/
+
+/* Get the error state of a MQ encoder. */
+#define	jpc_mqenc_error(enc) \
+	((enc)->err)
+
+/* Get the current encoder state. */
+void jpc_mqenc_getstate(jpc_mqenc_t *enc, jpc_mqencstate_t *state);
+
+/* Terminate the code. */
+int jpc_mqenc_flush(jpc_mqenc_t *enc, int termmode);
+
+/******************************************************************************\
+* Functions/macros for encoding bits.
+\******************************************************************************/
+
+/* Encode a bit. */
+#if !defined(DEBUG)
+#define	jpc_mqenc_putbit(enc, bit)	jpc_mqenc_putbit_macro(enc, bit)
+#else
+#define	jpc_mqenc_putbit(enc, bit)	jpc_mqenc_putbit_func(enc, bit)
+#endif
+
+/******************************************************************************\
+* Functions/macros for debugging.
+\******************************************************************************/
+
+int jpc_mqenc_dump(jpc_mqenc_t *mqenc, FILE *out);
+
+/******************************************************************************\
+* Implementation-specific details.
+\******************************************************************************/
+
+/* Note: This macro is included only to satisfy the needs of
+  the mqenc_putbit macro. */
+#define	jpc_mqenc_putbit_macro(enc, bit) \
+	(((*((enc)->curctx))->mps == (bit)) ? \
+	  (((enc)->areg -= (*(enc)->curctx)->qeval), \
+	  ((!((enc)->areg & 0x8000)) ? (jpc_mqenc_codemps2(enc)) : \
+	  ((enc)->creg += (*(enc)->curctx)->qeval))) : \
+	  jpc_mqenc_codelps(enc))
+
+/* Note: These function prototypes are included only to satisfy the
+  needs of the mqenc_putbit_macro macro.  Do not call any of these
+  functions directly. */
+int jpc_mqenc_codemps2(jpc_mqenc_t *enc);
+int jpc_mqenc_codelps(jpc_mqenc_t *enc);
+
+/* Note: This function prototype is included only to satisfy the needs of
+  the mqenc_putbit macro. */
+int jpc_mqenc_putbit_func(jpc_mqenc_t *enc, int bit);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c
new file mode 100644
index 00000000..1ed0dd90
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.c
@@ -0,0 +1,1125 @@
+/*
+ * 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__
+ */
+
+/*
+ * Quadrature Mirror-Image Filter Bank (QMFB) Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <assert.h>
+
+#include "jasper/jas_fix.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_math.h"
+
+#include "jpc_qmfb.h"
+#include "jpc_tsfb.h"
+#include "jpc_math.h"
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+static jpc_qmfb1d_t *jpc_qmfb1d_create(void);
+
+static int jpc_ft_getnumchans(jpc_qmfb1d_t *qmfb);
+static int jpc_ft_getanalfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters);
+static int jpc_ft_getsynfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters);
+static void jpc_ft_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x);
+static void jpc_ft_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x);
+
+static int jpc_ns_getnumchans(jpc_qmfb1d_t *qmfb);
+static int jpc_ns_getanalfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters);
+static int jpc_ns_getsynfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters);
+static void jpc_ns_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x);
+static void jpc_ns_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x);
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+jpc_qmfb1dops_t jpc_ft_ops = {
+	jpc_ft_getnumchans,
+	jpc_ft_getanalfilters,
+	jpc_ft_getsynfilters,
+	jpc_ft_analyze,
+	jpc_ft_synthesize
+};
+
+jpc_qmfb1dops_t jpc_ns_ops = {
+	jpc_ns_getnumchans,
+	jpc_ns_getanalfilters,
+	jpc_ns_getsynfilters,
+	jpc_ns_analyze,
+	jpc_ns_synthesize
+};
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+static void jpc_qmfb1d_setup(jpc_fix_t *startptr, int startind, int endind,
+  int intrastep, jpc_fix_t **lstartptr, int *lstartind, int *lendind,
+  jpc_fix_t **hstartptr, int *hstartind, int *hendind)
+{
+	*lstartind = JPC_CEILDIVPOW2(startind, 1);
+	*lendind = JPC_CEILDIVPOW2(endind, 1);
+	*hstartind = JPC_FLOORDIVPOW2(startind, 1);
+	*hendind = JPC_FLOORDIVPOW2(endind, 1);
+	*lstartptr = startptr;
+	*hstartptr = &startptr[(*lendind - *lstartind) * intrastep];
+}
+
+static void jpc_qmfb1d_split(jpc_fix_t *startptr, int startind, int endind,
+  register int step, jpc_fix_t *lstartptr, int lstartind, int lendind,
+  jpc_fix_t *hstartptr, int hstartind, int hendind)
+{
+#define QMFB_SPLITBUFSIZE 4096
+	jpc_fix_t splitbuf[QMFB_SPLITBUFSIZE];
+	jpc_fix_t *buf = splitbuf;
+	int llen;
+	int hlen;
+	int twostep;
+	jpc_fix_t *tmpptr;
+	register jpc_fix_t *ptr;
+	register jpc_fix_t *hptr;
+	register jpc_fix_t *lptr;
+	register int n;
+	int state;
+
+	twostep = step << 1;
+	llen = lendind - lstartind;
+	hlen = hendind - hstartind;
+
+#if defined(WIN32)
+	/* Get a buffer. */
+	if (bufsize > QMFB_SPLITBUFSIZE) {
+		if (!(buf = jas_malloc(bufsize * sizeof(jpc_fix_t)))) {
+			/* We have no choice but to commit suicide in this case. */
+			abort();
+		}
+	}
+#endif
+
+	if (hstartind < lstartind) {
+		/* The first sample in the input signal is to appear
+		  in the highpass subband signal. */
+		/* Copy the appropriate samples into the lowpass subband
+		  signal, saving any samples destined for the highpass subband
+		  signal as they are overwritten. */
+		tmpptr = buf;
+		ptr = &startptr[step];
+		lptr = lstartptr;
+		n = llen;
+		state = 1;
+		while (n-- > 0) {
+			if (state) {
+				*tmpptr = *lptr;
+				++tmpptr;
+			}
+			*lptr = *ptr;
+			ptr += twostep;
+			lptr += step;
+			state ^= 1;
+		}
+		/* Copy the appropriate samples into the highpass subband
+		  signal. */
+		/* Handle the nonoverwritten samples. */
+		hptr = &hstartptr[(hlen - 1) * step];
+		ptr = &startptr[(((llen + hlen - 1) >> 1) << 1) * step];
+		n = hlen - (tmpptr - buf);
+		while (n-- > 0) {
+			*hptr = *ptr;
+			hptr -= step;
+			ptr -= twostep;
+		}
+		/* Handle the overwritten samples. */
+		n = tmpptr - buf;
+		while (n-- > 0) {
+			--tmpptr;
+			*hptr = *tmpptr;
+			hptr -= step;
+		}
+	} else {
+		/* The first sample in the input signal is to appear
+		  in the lowpass subband signal. */
+		/* Copy the appropriate samples into the lowpass subband
+		  signal, saving any samples for the highpass subband
+		  signal as they are overwritten. */
+		state = 0;
+		ptr = startptr;
+		lptr = lstartptr;
+		tmpptr = buf;
+		n = llen;
+		while (n-- > 0) {
+			if (state) {
+				*tmpptr = *lptr;
+				++tmpptr;
+			}
+			*lptr = *ptr;
+			ptr += twostep;
+			lptr += step;
+			state ^= 1;
+		}
+		/* Copy the appropriate samples into the highpass subband
+		  signal. */
+		/* Handle the nonoverwritten samples. */
+		ptr = &startptr[((((llen + hlen) >> 1) << 1) - 1) * step];
+		hptr = &hstartptr[(hlen - 1) * step];
+		n = hlen - (tmpptr - buf);
+		while (n-- > 0) {
+			*hptr = *ptr;
+			ptr -= twostep;
+			hptr -= step;
+		}
+		/* Handle the overwritten samples. */
+		n = tmpptr - buf;
+		while (n-- > 0) {
+			--tmpptr;
+			*hptr = *tmpptr;
+			hptr -= step;
+		}
+	}
+
+#if defined(WIN32)
+	/* If the split buffer was allocated on the heap, free this memory. */
+	if (buf != splitbuf) {
+		jas_free(buf);
+	}
+#endif
+}
+
+static void jpc_qmfb1d_join(jpc_fix_t *startptr, int startind, int endind,
+  register int step, jpc_fix_t *lstartptr, int lstartind, int lendind,
+  jpc_fix_t *hstartptr, int hstartind, int hendind)
+{
+#define	QMFB_JOINBUFSIZE	4096
+	jpc_fix_t joinbuf[QMFB_JOINBUFSIZE];
+	jpc_fix_t *buf = joinbuf;
+	int llen;
+	int hlen;
+	int twostep;
+	jpc_fix_t *tmpptr;
+	register jpc_fix_t *ptr;
+	register jpc_fix_t *hptr;
+	register jpc_fix_t *lptr;
+	register int n;
+	int state;
+
+#if defined(WIN32)
+	/* Allocate memory for the join buffer from the heap. */
+	if (bufsize > QMFB_JOINBUFSIZE) {
+		if (!(buf = jas_malloc(bufsize * sizeof(jpc_fix_t)))) {
+			/* We have no choice but to commit suicide. */
+			abort();
+		}
+	}
+#endif
+
+	twostep = step << 1;
+	llen = lendind - lstartind;
+	hlen = hendind - hstartind;
+
+	if (hstartind < lstartind) {
+		/* The first sample in the highpass subband signal is to
+		  appear first in the output signal. */
+		/* Copy the appropriate samples into the first phase of the
+		  output signal. */
+		tmpptr = buf;
+		hptr = hstartptr;
+		ptr = startptr;
+		n = (llen + 1) >> 1;
+		while (n-- > 0) {
+			*tmpptr = *ptr;
+			*ptr = *hptr;
+			++tmpptr;
+			ptr += twostep;
+			hptr += step;
+		}
+		n = hlen - ((llen + 1) >> 1);
+		while (n-- > 0) {
+			*ptr = *hptr;
+			ptr += twostep;
+			hptr += step;
+		}
+		/* Copy the appropriate samples into the second phase of
+		  the output signal. */
+		ptr -= (lendind > hendind) ? (step) : (step + twostep);
+		state = !((llen - 1) & 1);
+		lptr = &lstartptr[(llen - 1) * step];
+		n = llen;
+		while (n-- > 0) {
+			if (state) {
+				--tmpptr;
+				*ptr = *tmpptr;
+			} else {
+				*ptr = *lptr;
+			}
+			lptr -= step;
+			ptr -= twostep;
+			state ^= 1;
+		}
+	} else {
+		/* The first sample in the lowpass subband signal is to
+		  appear first in the output signal. */
+		/* Copy the appropriate samples into the first phase of the
+		  output signal (corresponding to even indexed samples). */
+		lptr = &lstartptr[(llen - 1) * step];
+		ptr = &startptr[((llen - 1) << 1) * step];
+		n = llen >> 1;
+		tmpptr = buf;
+		while (n-- > 0) {
+			*tmpptr = *ptr;
+			*ptr = *lptr;
+			++tmpptr;
+			ptr -= twostep;
+			lptr -= step;
+		}
+		n = llen - (llen >> 1);
+		while (n-- > 0) {
+			*ptr = *lptr;
+			ptr -= twostep;
+			lptr -= step;
+		}
+		/* Copy the appropriate samples into the second phase of
+		  the output signal (corresponding to odd indexed
+		  samples). */
+		ptr = &startptr[step];
+		hptr = hstartptr;
+		state = !(llen & 1);
+		n = hlen;
+		while (n-- > 0) {
+			if (state) {
+				--tmpptr;
+				*ptr = *tmpptr;
+			} else {
+				*ptr = *hptr;
+			}
+			hptr += step;
+			ptr += twostep;
+			state ^= 1;
+		}
+	}
+
+#if defined(WIN32)
+	/* If the join buffer was allocated on the heap, free this memory. */
+	if (buf != joinbuf) {
+		jas_free(buf);
+	}
+#endif
+}
+
+/******************************************************************************\
+* Code for 5/3 transform.
+\******************************************************************************/
+
+static int jpc_ft_getnumchans(jpc_qmfb1d_t *qmfb)
+{
+	return 2;
+}
+
+static int jpc_ft_getanalfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters)
+{
+	abort();
+	return -1;
+}
+
+static int jpc_ft_getsynfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters)
+{
+	jas_seq_t *lf;
+	jas_seq_t *hf;
+
+	lf = 0;
+	hf = 0;
+
+	if (len > 1 || (!len)) {
+		if (!(lf = jas_seq_create(-1, 2))) {
+			goto error;
+		}
+		jas_seq_set(lf, -1, jpc_dbltofix(0.5));
+		jas_seq_set(lf, 0, jpc_dbltofix(1.0));
+		jas_seq_set(lf, 1, jpc_dbltofix(0.5));
+		if (!(hf = jas_seq_create(-1, 4))) {
+			goto error;
+		}
+		jas_seq_set(hf, -1, jpc_dbltofix(-0.125));
+		jas_seq_set(hf, 0, jpc_dbltofix(-0.25));
+		jas_seq_set(hf, 1, jpc_dbltofix(0.75));
+		jas_seq_set(hf, 2, jpc_dbltofix(-0.25));
+		jas_seq_set(hf, 3, jpc_dbltofix(-0.125));
+	} else if (len == 1) {
+		if (!(lf = jas_seq_create(0, 1))) {
+			goto error;
+		}
+		jas_seq_set(lf, 0, jpc_dbltofix(1.0));
+		if (!(hf = jas_seq_create(0, 1))) {
+			goto error;
+		}
+		jas_seq_set(hf, 0, jpc_dbltofix(2.0));
+	} else {
+		abort();
+	}
+
+	filters[0] = lf;
+	filters[1] = hf;
+
+	return 0;
+
+error:
+	if (lf) {
+		jas_seq_destroy(lf);
+	}
+	if (hf) {
+		jas_seq_destroy(hf);
+	}
+	return -1;
+}
+
+#define	NFT_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, pluseq) \
+{ \
+	register jpc_fix_t *lptr = (lstartptr); \
+	register jpc_fix_t *hptr = (hstartptr); \
+	register int n = (hendind) - (hstartind); \
+	if ((hstartind) < (lstartind)) { \
+		pluseq(*hptr, *lptr); \
+		hptr += (step); \
+		--n; \
+	} \
+	if ((hendind) >= (lendind)) { \
+		--n; \
+	} \
+	while (n-- > 0) { \
+		pluseq(*hptr, jpc_fix_asr(jpc_fix_add(*lptr, lptr[(step)]), 1)); \
+		hptr += (step); \
+		lptr += (step); \
+	} \
+	if ((hendind) >= (lendind)) { \
+		pluseq(*hptr, *lptr); \
+	} \
+}
+
+#define	NFT_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, pluseq) \
+{ \
+	register jpc_fix_t *lptr = (lstartptr); \
+	register jpc_fix_t *hptr = (hstartptr); \
+	register int n = (lendind) - (lstartind); \
+	if ((hstartind) >= (lstartind)) { \
+		pluseq(*lptr, *hptr); \
+		lptr += (step); \
+		--n; \
+	} \
+	if ((lendind) > (hendind)) { \
+		--n; \
+	} \
+	while (n-- > 0) { \
+		pluseq(*lptr, jpc_fix_asr(jpc_fix_add(*hptr, hptr[(step)]), 2)); \
+		lptr += (step); \
+		hptr += (step); \
+	} \
+	if ((lendind) > (hendind)) { \
+		pluseq(*lptr, *hptr); \
+	} \
+}
+
+#define	RFT_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, pmeqop) \
+{ \
+	register jpc_fix_t *lptr = (lstartptr); \
+	register jpc_fix_t *hptr = (hstartptr); \
+	register int n = (hendind) - (hstartind); \
+	if ((hstartind) < (lstartind)) { \
+		*hptr pmeqop *lptr; \
+		hptr += (step); \
+		--n; \
+	} \
+	if ((hendind) >= (lendind)) { \
+		--n; \
+	} \
+	while (n-- > 0) { \
+		*hptr pmeqop (*lptr + lptr[(step)]) >> 1; \
+		hptr += (step); \
+		lptr += (step); \
+	} \
+	if ((hendind) >= (lendind)) { \
+		*hptr pmeqop *lptr; \
+	} \
+}
+
+#define	RFT_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, pmeqop) \
+{ \
+	register jpc_fix_t *lptr = (lstartptr); \
+	register jpc_fix_t *hptr = (hstartptr); \
+	register int n = (lendind) - (lstartind); \
+	if ((hstartind) >= (lstartind)) { \
+		*lptr pmeqop ((*hptr << 1) + 2) >> 2; \
+		lptr += (step); \
+		--n; \
+	} \
+	if ((lendind) > (hendind)) { \
+		--n; \
+	} \
+	while (n-- > 0) { \
+		*lptr pmeqop ((*hptr + hptr[(step)]) + 2) >> 2; \
+		lptr += (step); \
+		hptr += (step); \
+	} \
+	if ((lendind) > (hendind)) { \
+		*lptr pmeqop ((*hptr << 1) + 2) >> 2; \
+	} \
+}
+
+static void jpc_ft_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x)
+{
+	jpc_fix_t *startptr;
+	int startind;
+	int endind;
+	jpc_fix_t *  lstartptr;
+	int   lstartind;
+	int   lendind;
+	jpc_fix_t *  hstartptr;
+	int   hstartind;
+	int   hendind;
+	int interstep;
+	int intrastep;
+	int numseq;
+
+	if (flags & JPC_QMFB1D_VERT) {
+		interstep = 1;
+		intrastep = jas_seq2d_rowstep(x);
+		numseq = jas_seq2d_width(x);
+		startind = jas_seq2d_ystart(x);
+		endind = jas_seq2d_yend(x);
+	} else {
+		interstep = jas_seq2d_rowstep(x);
+		intrastep = 1;
+		numseq = jas_seq2d_height(x);
+		startind = jas_seq2d_xstart(x);
+		endind = jas_seq2d_xend(x);
+	}
+
+	assert(startind < endind);
+
+	startptr = jas_seq2d_getref(x, jas_seq2d_xstart(x), jas_seq2d_ystart(x));
+	if (flags & JPC_QMFB1D_RITIMODE) {
+		while (numseq-- > 0) {
+			jpc_qmfb1d_setup(startptr, startind, endind, intrastep,
+			  &lstartptr, &lstartind, &lendind, &hstartptr,
+			  &hstartind, &hendind);
+			if (endind - startind > 1) {
+				jpc_qmfb1d_split(startptr, startind, endind,
+				  intrastep, lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind);
+				RFT_LIFT0(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep, -=);
+				RFT_LIFT1(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep, +=);
+			} else {
+				if (lstartind == lendind) {
+					*startptr <<= 1;
+				}
+			}
+			startptr += interstep;
+		}
+	} else {
+		while (numseq-- > 0) {
+			jpc_qmfb1d_setup(startptr, startind, endind, intrastep,
+			  &lstartptr, &lstartind, &lendind, &hstartptr,
+			  &hstartind, &hendind);
+			if (endind - startind > 1) {
+				jpc_qmfb1d_split(startptr, startind, endind,
+				  intrastep, lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind);
+				NFT_LIFT0(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_fix_minuseq);
+				NFT_LIFT1(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_fix_pluseq);
+			} else {
+				if (lstartind == lendind) {
+					*startptr = jpc_fix_asl(*startptr, 1);
+				}
+			}
+			startptr += interstep;
+		}
+	}
+}
+
+static void jpc_ft_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x)
+{
+	jpc_fix_t *startptr;
+	int startind;
+	int endind;
+	jpc_fix_t *lstartptr;
+	int lstartind;
+	int lendind;
+	jpc_fix_t *hstartptr;
+	int hstartind;
+	int hendind;
+	int interstep;
+	int intrastep;
+	int numseq;
+
+	if (flags & JPC_QMFB1D_VERT) {
+		interstep = 1;
+		intrastep = jas_seq2d_rowstep(x);
+		numseq = jas_seq2d_width(x);
+		startind = jas_seq2d_ystart(x);
+		endind = jas_seq2d_yend(x);
+	} else {
+		interstep = jas_seq2d_rowstep(x);
+		intrastep = 1;
+		numseq = jas_seq2d_height(x);
+		startind = jas_seq2d_xstart(x);
+		endind = jas_seq2d_xend(x);
+	}
+
+	assert(startind < endind);
+
+	startptr = jas_seq2d_getref(x, jas_seq2d_xstart(x), jas_seq2d_ystart(x));
+	if (flags & JPC_QMFB1D_RITIMODE) {
+		while (numseq-- > 0) {
+			jpc_qmfb1d_setup(startptr, startind, endind, intrastep,
+			  &lstartptr, &lstartind, &lendind, &hstartptr,
+			  &hstartind, &hendind);
+			if (endind - startind > 1) {
+				RFT_LIFT1(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep, -=);
+				RFT_LIFT0(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep, +=);
+				jpc_qmfb1d_join(startptr, startind, endind,
+				  intrastep, lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind);
+			} else {
+				if (lstartind == lendind) {
+					*startptr >>= 1;
+				}
+			}
+			startptr += interstep;
+		}
+	} else {
+		while (numseq-- > 0) {
+			jpc_qmfb1d_setup(startptr, startind, endind, intrastep,
+			  &lstartptr, &lstartind, &lendind, &hstartptr,
+			  &hstartind, &hendind);
+			if (endind - startind > 1) {
+				NFT_LIFT1(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_fix_minuseq);
+				NFT_LIFT0(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_fix_pluseq);
+				jpc_qmfb1d_join(startptr, startind, endind,
+				  intrastep, lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind);
+			} else {
+				if (lstartind == lendind) {
+					*startptr = jpc_fix_asr(*startptr, 1);
+				}
+			}
+			startptr += interstep;
+		}
+	}
+}
+
+/******************************************************************************\
+* Code for 9/7 transform.
+\******************************************************************************/
+
+static int jpc_ns_getnumchans(jpc_qmfb1d_t *qmfb)
+{
+	return 2;
+}
+
+static int jpc_ns_getanalfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters)
+{
+	abort();
+	return -1;
+}
+
+static int jpc_ns_getsynfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters)
+{
+	jas_seq_t *lf;
+	jas_seq_t *hf;
+
+	lf = 0;
+	hf = 0;
+
+	if (len > 1 || (!len)) {
+		if (!(lf = jas_seq_create(-3, 4))) {
+			goto error;
+		}
+		jas_seq_set(lf, -3, jpc_dbltofix(-0.09127176311424948));
+		jas_seq_set(lf, -2, jpc_dbltofix(-0.05754352622849957));
+		jas_seq_set(lf, -1, jpc_dbltofix(0.5912717631142470));
+		jas_seq_set(lf, 0, jpc_dbltofix(1.115087052456994));
+		jas_seq_set(lf, 1, jpc_dbltofix(0.5912717631142470));
+		jas_seq_set(lf, 2, jpc_dbltofix(-0.05754352622849957));
+		jas_seq_set(lf, 3, jpc_dbltofix(-0.09127176311424948));
+		if (!(hf = jas_seq_create(-3, 6))) {
+			goto error;
+		}
+		jas_seq_set(hf, -3, jpc_dbltofix(-0.02674875741080976 * 2.0));
+		jas_seq_set(hf, -2, jpc_dbltofix(-0.01686411844287495 * 2.0));
+		jas_seq_set(hf, -1, jpc_dbltofix(0.07822326652898785 * 2.0));
+		jas_seq_set(hf, 0, jpc_dbltofix(0.2668641184428723 * 2.0));
+		jas_seq_set(hf, 1, jpc_dbltofix(-0.6029490182363579 * 2.0));
+		jas_seq_set(hf, 2, jpc_dbltofix(0.2668641184428723 * 2.0));
+		jas_seq_set(hf, 3, jpc_dbltofix(0.07822326652898785 * 2.0));
+		jas_seq_set(hf, 4, jpc_dbltofix(-0.01686411844287495 * 2.0));
+		jas_seq_set(hf, 5, jpc_dbltofix(-0.02674875741080976 * 2.0));
+	} else if (len == 1) {
+		if (!(lf = jas_seq_create(0, 1))) {
+			goto error;
+		}
+		jas_seq_set(lf, 0, jpc_dbltofix(1.0));
+		if (!(hf = jas_seq_create(0, 1))) {
+			goto error;
+		}
+		jas_seq_set(hf, 0, jpc_dbltofix(2.0));
+	} else {
+		abort();
+	}
+
+	filters[0] = lf;
+	filters[1] = hf;
+
+	return 0;
+
+error:
+	if (lf) {
+		jas_seq_destroy(lf);
+	}
+	if (hf) {
+		jas_seq_destroy(hf);
+	}
+	return -1;
+}
+
+#define	NNS_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, alpha) \
+{ \
+	register jpc_fix_t *lptr = (lstartptr); \
+	register jpc_fix_t *hptr = (hstartptr); \
+	register int n = (hendind) - (hstartind); \
+	jpc_fix_t twoalpha = jpc_fix_mulbyint(alpha, 2); \
+	if ((hstartind) < (lstartind)) { \
+		jpc_fix_pluseq(*hptr, jpc_fix_mul(*lptr, (twoalpha))); \
+		hptr += (step); \
+		--n; \
+	} \
+	if ((hendind) >= (lendind)) { \
+		--n; \
+	} \
+	while (n-- > 0) { \
+		jpc_fix_pluseq(*hptr, jpc_fix_mul(jpc_fix_add(*lptr, lptr[(step)]), (alpha))); \
+		hptr += (step); \
+		lptr += (step); \
+	} \
+	if ((hendind) >= (lendind)) { \
+		jpc_fix_pluseq(*hptr, jpc_fix_mul(*lptr, (twoalpha))); \
+	} \
+}
+
+#define	NNS_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, alpha) \
+{ \
+	register jpc_fix_t *lptr = (lstartptr); \
+	register jpc_fix_t *hptr = (hstartptr); \
+	register int n = (lendind) - (lstartind); \
+	int twoalpha = jpc_fix_mulbyint(alpha, 2); \
+	if ((hstartind) >= (lstartind)) { \
+		jpc_fix_pluseq(*lptr, jpc_fix_mul(*hptr, (twoalpha))); \
+		lptr += (step); \
+		--n; \
+	} \
+	if ((lendind) > (hendind)) { \
+		--n; \
+	} \
+	while (n-- > 0) { \
+		jpc_fix_pluseq(*lptr, jpc_fix_mul(jpc_fix_add(*hptr, hptr[(step)]), (alpha))); \
+		lptr += (step); \
+		hptr += (step); \
+	} \
+	if ((lendind) > (hendind)) { \
+		jpc_fix_pluseq(*lptr, jpc_fix_mul(*hptr, (twoalpha))); \
+	} \
+}
+
+#define	NNS_SCALE(startptr, startind, endind, step, alpha) \
+{ \
+	register jpc_fix_t *ptr = (startptr); \
+	register int n = (endind) - (startind); \
+	while (n-- > 0) { \
+		jpc_fix_muleq(*ptr, alpha); \
+		ptr += (step); \
+	} \
+}
+
+static void jpc_ns_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x)
+{
+	jpc_fix_t *startptr;
+	int startind;
+	int endind;
+	jpc_fix_t *lstartptr;
+	int lstartind;
+	int lendind;
+	jpc_fix_t *hstartptr;
+	int hstartind;
+	int hendind;
+	int interstep;
+	int intrastep;
+	int numseq;
+
+	if (flags & JPC_QMFB1D_VERT) {
+		interstep = 1;
+		intrastep = jas_seq2d_rowstep(x);
+		numseq = jas_seq2d_width(x);
+		startind = jas_seq2d_ystart(x);
+		endind = jas_seq2d_yend(x);
+	} else {
+		interstep = jas_seq2d_rowstep(x);
+		intrastep = 1;
+		numseq = jas_seq2d_height(x);
+		startind = jas_seq2d_xstart(x);
+		endind = jas_seq2d_xend(x);
+	}
+
+	assert(startind < endind);
+
+	startptr = jas_seq2d_getref(x, jas_seq2d_xstart(x), jas_seq2d_ystart(x));
+	if (!(flags & JPC_QMFB1D_RITIMODE)) {
+		while (numseq-- > 0) {
+			jpc_qmfb1d_setup(startptr, startind, endind, intrastep,
+			  &lstartptr, &lstartind, &lendind, &hstartptr,
+			  &hstartind, &hendind);
+			if (endind - startind > 1) {
+				jpc_qmfb1d_split(startptr, startind, endind,
+				  intrastep, lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind);
+				NNS_LIFT0(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_dbltofix(-1.586134342));
+				NNS_LIFT1(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_dbltofix(-0.052980118));
+				NNS_LIFT0(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_dbltofix(0.882911075));
+				NNS_LIFT1(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_dbltofix(0.443506852));
+				NNS_SCALE(lstartptr, lstartind, lendind,
+				  intrastep, jpc_dbltofix(1.0/1.23017410558578));
+				NNS_SCALE(hstartptr, hstartind, hendind,
+				  intrastep, jpc_dbltofix(1.0/1.62578613134411));
+			} else {
+#if 0
+				if (lstartind == lendind) {
+					*startptr = jpc_fix_asl(*startptr, 1);
+				}
+#endif
+			}
+			startptr += interstep;
+		}
+	} else {
+		/* The reversible integer-to-integer mode is not supported
+		  for this transform. */
+		abort();
+	}
+}
+
+static void jpc_ns_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x)
+{
+	jpc_fix_t *startptr;
+	int startind;
+	int endind;
+	jpc_fix_t *lstartptr;
+	int lstartind;
+	int lendind;
+	jpc_fix_t *hstartptr;
+	int hstartind;
+	int hendind;
+	int interstep;
+	int intrastep;
+	int numseq;
+
+	if (flags & JPC_QMFB1D_VERT) {
+		interstep = 1;
+		intrastep = jas_seq2d_rowstep(x);
+		numseq = jas_seq2d_width(x);
+		startind = jas_seq2d_ystart(x);
+		endind = jas_seq2d_yend(x);
+	} else {
+		interstep = jas_seq2d_rowstep(x);
+		intrastep = 1;
+		numseq = jas_seq2d_height(x);
+		startind = jas_seq2d_xstart(x);
+		endind = jas_seq2d_xend(x);
+	}
+
+	assert(startind < endind);
+
+	startptr = jas_seq2d_getref(x, jas_seq2d_xstart(x), jas_seq2d_ystart(x));
+	if (!(flags & JPC_QMFB1D_RITIMODE)) {
+		while (numseq-- > 0) {
+			jpc_qmfb1d_setup(startptr, startind, endind, intrastep,
+			  &lstartptr, &lstartind, &lendind, &hstartptr,
+			  &hstartind, &hendind);
+			if (endind - startind > 1) {
+				NNS_SCALE(lstartptr, lstartind, lendind,
+				  intrastep, jpc_dbltofix(1.23017410558578));
+				NNS_SCALE(hstartptr, hstartind, hendind,
+				  intrastep, jpc_dbltofix(1.62578613134411));
+				NNS_LIFT1(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_dbltofix(-0.443506852));
+				NNS_LIFT0(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_dbltofix(-0.882911075));
+				NNS_LIFT1(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_dbltofix(0.052980118));
+				NNS_LIFT0(lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind, intrastep,
+				  jpc_dbltofix(1.586134342));
+				jpc_qmfb1d_join(startptr, startind, endind,
+				  intrastep, lstartptr, lstartind, lendind,
+				  hstartptr, hstartind, hendind);
+			} else {
+#if 0
+				if (lstartind == lendind) {
+					*startptr = jpc_fix_asr(*startptr, 1);
+				}
+#endif
+			}
+			startptr += interstep;
+		}
+	} else {
+		/* The reversible integer-to-integer mode is not supported
+		  for this transform. */
+		abort();
+	}
+}
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+jpc_qmfb1d_t *jpc_qmfb1d_make(int qmfbid)
+{
+	jpc_qmfb1d_t *qmfb;
+	if (!(qmfb = jpc_qmfb1d_create())) {
+		return 0;
+	}
+	switch (qmfbid) {
+	case JPC_QMFB1D_FT:
+		qmfb->ops = &jpc_ft_ops;
+		break;
+	case JPC_QMFB1D_NS:
+		qmfb->ops = &jpc_ns_ops;
+		break;
+	default:
+		jpc_qmfb1d_destroy(qmfb);
+		return 0;
+		break;
+	}
+	return qmfb;
+}
+
+static jpc_qmfb1d_t *jpc_qmfb1d_create()
+{
+	jpc_qmfb1d_t *qmfb;
+	if (!(qmfb = jas_malloc(sizeof(jpc_qmfb1d_t)))) {
+		return 0;
+	}
+	qmfb->ops = 0;
+	return qmfb;
+}
+
+jpc_qmfb1d_t *jpc_qmfb1d_copy(jpc_qmfb1d_t *qmfb)
+{
+	jpc_qmfb1d_t *newqmfb;
+
+	if (!(newqmfb = jpc_qmfb1d_create())) {
+		return 0;
+	}
+	newqmfb->ops = qmfb->ops;
+	return newqmfb;
+}
+
+void jpc_qmfb1d_destroy(jpc_qmfb1d_t *qmfb)
+{
+	jas_free(qmfb);
+}
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+void jpc_qmfb1d_getbands(jpc_qmfb1d_t *qmfb, int flags, uint_fast32_t xstart,
+  uint_fast32_t ystart, uint_fast32_t xend, uint_fast32_t yend, int maxbands,
+  int *numbandsptr, jpc_qmfb1dband_t *bands)
+{
+	int start;
+	int end;
+	if (flags & JPC_QMFB1D_VERT) {
+		start = ystart;
+		end = yend;
+	} else {
+		start = xstart;
+		end = xend;
+	}
+	assert(jpc_qmfb1d_getnumchans(qmfb) == 2);
+	assert(start <= end);
+	bands[0].start = JPC_CEILDIVPOW2(start, 1);
+	bands[0].end = JPC_CEILDIVPOW2(end, 1);
+	bands[0].locstart = start;
+	bands[0].locend = start + bands[0].end - bands[0].start;
+	bands[1].start = JPC_FLOORDIVPOW2(start, 1);
+	bands[1].end = JPC_FLOORDIVPOW2(end, 1);
+	bands[1].locstart = bands[0].locend;
+	bands[1].locend = bands[1].locstart + bands[1].end - bands[1].start;
+	assert(bands[1].locend == end);
+	*numbandsptr = 2;
+}
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+int jpc_qmfb1d_getnumchans(jpc_qmfb1d_t *qmfb)
+{
+	return (*qmfb->ops->getnumchans)(qmfb);
+}
+
+int jpc_qmfb1d_getanalfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters)
+{
+	return (*qmfb->ops->getanalfilters)(qmfb, len, filters);
+}
+
+int jpc_qmfb1d_getsynfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters)
+{
+	return (*qmfb->ops->getsynfilters)(qmfb, len, filters);
+}
+
+void jpc_qmfb1d_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x)
+{
+	(*qmfb->ops->analyze)(qmfb, flags, x);
+}
+
+void jpc_qmfb1d_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x)
+{
+	(*qmfb->ops->synthesize)(qmfb, flags, x);
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.h b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.h
new file mode 100644
index 00000000..e10b6c13
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.h
@@ -0,0 +1,235 @@
+/*
+ * 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__
+ */
+
+/*
+ * Quadrature Mirror-Image Filter Bank (QMFB) Routines
+ *
+ * $Id$
+ */
+
+#ifndef JPC_QMFB_H
+#define JPC_QMFB_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_seq.h"
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/* The maximum number of channels for a QMF bank. */
+#define	JPC_QMFB1D_MAXCHANS	2
+
+/* Select reversible integer-to-integer mode. */
+#define	JPC_QMFB1D_RITIMODE	1
+
+/* Vertical filtering. */
+#define	JPC_QMFB1D_VERT	0x10000
+
+/* QMFB IDs. */
+#define	JPC_QMFB1D_FT	1	/* 5/3 */
+#define	JPC_QMFB1D_NS	2	/* 9/7 */
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/* Forward declaration. */
+struct jpc_qmfb1dops_s;
+
+/* Band information. */
+
+typedef struct {
+
+	/* The starting index for the band in the downsampled domain. */
+	int start;
+
+	/* The ending index for the band in the downsampled domain. */
+	int end;
+
+	/* The location of the start of the band. */
+	int locstart;
+
+	/* The location of the end of the band. */
+	int locend;
+
+} jpc_qmfb1dband_t;
+
+/* QMF bank */
+
+typedef struct {
+
+	/* The operations for this QMFB. */
+	struct jpc_qmfb1dops_s *ops;
+
+} jpc_qmfb1d_t;
+
+/* QMFB operations. */
+
+typedef struct jpc_qmfb1dops_s {
+
+	/* The number of channels in the QMFB. */
+	int (*getnumchans)(jpc_qmfb1d_t *qmfb);
+
+	/* Get the analysis filters for this QMFB. */
+	int (*getanalfilters)(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters);
+
+	/* Get the synthesis filters for this QMFB. */
+	int (*getsynfilters)(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters);
+
+	/* Do analysis. */
+	void (*analyze)(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x);
+
+	/* Do synthesis. */
+	void (*synthesize)(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x);
+
+} jpc_qmfb1dops_t;
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Create a QMFB from a QMFB ID. */
+jpc_qmfb1d_t *jpc_qmfb1d_make(int qmfbid);
+
+/* Create a copy of a QMFB. */
+jpc_qmfb1d_t *jpc_qmfb1d_copy(jpc_qmfb1d_t *qmfb);
+
+/* Destroy a QMFB. */
+void jpc_qmfb1d_destroy(jpc_qmfb1d_t *qmfb);
+
+/* Get the number of channels for a QMFB. */
+int jpc_qmfb1d_getnumchans(jpc_qmfb1d_t *qmfb);
+
+/* Get the analysis filters for a QMFB. */
+int jpc_qmfb1d_getanalfilters(jpc_qmfb1d_t *qmfb, int len,
+  jas_seq2d_t **filters);
+
+/* Get the synthesis filters for a QMFB. */
+int jpc_qmfb1d_getsynfilters(jpc_qmfb1d_t *qmfb, int len,
+  jas_seq2d_t **filters);
+
+/* Get the bands for a QMFB. */
+void jpc_qmfb1d_getbands(jpc_qmfb1d_t *qmfb, int flags, uint_fast32_t xstart,
+  uint_fast32_t ystart, uint_fast32_t xend, uint_fast32_t yend, int maxbands,
+  int *numbandsptr, jpc_qmfb1dband_t *bands);
+
+/* Perform analysis. */
+void jpc_qmfb1d_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x);
+
+/* Perform synthesis. */
+void jpc_qmfb1d_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1cod.c b/converter/other/jpeg2000/libjasper/jpc/jpc_t1cod.c
new file mode 100644
index 00000000..650cb854
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1cod.c
@@ -0,0 +1,537 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_math.h"
+
+#include "jpc_bs.h"
+#include "jpc_dec.h"
+#include "jpc_cs.h"
+#include "jpc_mqcod.h"
+#include "jpc_t1cod.h"
+#include "jpc_tsfb.h"
+
+double jpc_pow2i(int n);
+
+/******************************************************************************\
+* Global data.
+\******************************************************************************/
+
+int jpc_zcctxnolut[4 * 256];
+int jpc_spblut[256];
+int jpc_scctxnolut[256];
+int jpc_magctxnolut[4096];
+
+jpc_fix_t jpc_signmsedec[1 << JPC_NMSEDEC_BITS];
+jpc_fix_t jpc_refnmsedec[1 << JPC_NMSEDEC_BITS];
+jpc_fix_t jpc_signmsedec0[1 << JPC_NMSEDEC_BITS];
+jpc_fix_t jpc_refnmsedec0[1 << JPC_NMSEDEC_BITS];
+
+jpc_mqctx_t jpc_mqctxs[JPC_NUMCTXS];
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+int JPC_PASSTYPE(int passno)
+{
+	int passtype;
+	switch (passno % 3) {
+	case 0:
+		passtype = JPC_CLNPASS;
+		break;
+	case 1:
+		passtype = JPC_SIGPASS;
+		break;
+	case 2:
+		passtype = JPC_REFPASS;
+		break;
+	default:
+		passtype = -1;
+		assert(0);
+		break;
+	}
+	return passtype;
+}
+
+int JPC_NOMINALGAIN(int qmfbid, int numlvls, int lvlno, int orient)
+{
+if (qmfbid == JPC_COX_INS) {
+	return 0;
+}
+	assert(qmfbid == JPC_COX_RFT);
+	if (lvlno == 0) {
+		assert(orient == JPC_TSFB_LL);
+		return 0;
+	} else {
+		switch (orient) {
+		case JPC_TSFB_LH:
+		case JPC_TSFB_HL:
+			return 1;
+			break;
+		case JPC_TSFB_HH:
+			return 2;
+			break;
+		}
+	}
+	abort();
+}
+
+/******************************************************************************\
+* Coding pass related functions.
+\******************************************************************************/
+
+int JPC_SEGTYPE(int passno, int firstpassno, int bypass)
+{
+	int passtype;
+	if (bypass) {
+		passtype = JPC_PASSTYPE(passno);
+		if (passtype == JPC_CLNPASS) {
+			return JPC_SEG_MQ;
+		}
+		return ((passno < firstpassno + 10) ? JPC_SEG_MQ : JPC_SEG_RAW);
+	} else {
+		return JPC_SEG_MQ;
+	}
+}
+
+int JPC_SEGPASSCNT(int passno, int firstpassno, int numpasses, int bypass, int termall)
+{
+	int ret;
+	int passtype;
+
+	if (termall) {
+		ret = 1;
+	} else if (bypass) {
+		if (passno < firstpassno + 10) {
+			ret = 10 - (passno - firstpassno);
+		} else {
+			passtype = JPC_PASSTYPE(passno);
+			switch (passtype) {
+			case JPC_SIGPASS:
+				ret = 2;
+				break;
+			case JPC_REFPASS:
+				ret = 1;
+				break;
+			case JPC_CLNPASS:
+				ret = 1;
+				break;
+			default:
+				ret = -1;
+				assert(0);
+				break;
+			}
+		}
+	} else {
+		ret = JPC_PREC * 3 - 2;
+	}
+	ret = JAS_MIN(ret, numpasses - passno);
+	return ret;
+}
+
+int JPC_ISTERMINATED(int passno, int firstpassno, int numpasses, int termall,
+  int lazy)
+{
+	int ret;
+	int n;
+	if (passno - firstpassno == numpasses - 1) {
+		ret = 1;
+	} else {
+		n = JPC_SEGPASSCNT(passno, firstpassno, numpasses, lazy, termall);
+		ret = (n <= 1) ? 1 : 0;
+	}
+
+	return ret;
+}
+
+/******************************************************************************\
+* Lookup table code.
+\******************************************************************************/
+
+static void jpc_initmqctxs(void)
+{
+	jpc_initctxs(jpc_mqctxs);
+}
+
+void jpc_initluts()
+{
+	int i;
+	int orient;
+	int refine;
+	float u;
+	float v;
+	float t;
+
+/* XXX - hack */
+jpc_initmqctxs();
+
+	for (orient = 0; orient < 4; ++orient) {
+		for (i = 0; i < 256; ++i) {
+			jpc_zcctxnolut[(orient << 8) | i] = jpc_getzcctxno(i, orient);
+		}
+	}
+
+	for (i = 0; i < 256; ++i) {
+		jpc_spblut[i] = jpc_getspb(i << 4);
+	}
+
+	for (i = 0; i < 256; ++i) {
+		jpc_scctxnolut[i] = jpc_getscctxno(i << 4);
+	}
+
+	for (refine = 0; refine < 2; ++refine) {
+		for (i = 0; i < 2048; ++i) {
+			jpc_magctxnolut[(refine << 11) + i] = jpc_getmagctxno((refine ? JPC_REFINE : 0) | i);
+		}
+	}
+
+	for (i = 0; i < (1 << JPC_NMSEDEC_BITS); ++i) {
+		t = i * jpc_pow2i(-JPC_NMSEDEC_FRACBITS);
+		u = t;
+		v = t - 1.5;
+		jpc_signmsedec[i] = jpc_dbltofix(floor((u * u - v * v) * jpc_pow2i(JPC_NMSEDEC_FRACBITS) + 0.5) / jpc_pow2i(JPC_NMSEDEC_FRACBITS));
+/* XXX - this calc is not correct */
+		jpc_signmsedec0[i] = jpc_dbltofix(floor((u * u) * jpc_pow2i(JPC_NMSEDEC_FRACBITS) + 0.5) / jpc_pow2i(JPC_NMSEDEC_FRACBITS));
+		u = t - 1.0;
+		if (i & (1 << (JPC_NMSEDEC_BITS - 1))) {
+			v = t - 1.5;
+		} else {
+			v = t - 0.5;
+		}
+		jpc_refnmsedec[i] = jpc_dbltofix(floor((u * u - v * v) * jpc_pow2i(JPC_NMSEDEC_FRACBITS) + 0.5) / jpc_pow2i(JPC_NMSEDEC_FRACBITS));
+/* XXX - this calc is not correct */
+		jpc_refnmsedec0[i] = jpc_dbltofix(floor((u * u) * jpc_pow2i(JPC_NMSEDEC_FRACBITS) + 0.5) / jpc_pow2i(JPC_NMSEDEC_FRACBITS));
+	}
+}
+
+jpc_fix_t jpc_getsignmsedec_func(jpc_fix_t x, int bitpos)
+{
+	jpc_fix_t y;
+	assert(!(x & (~JAS_ONES(bitpos + 1))));
+	y = jpc_getsignmsedec_macro(x, bitpos);
+	return y;
+}
+
+int jpc_getzcctxno(int f, int orient)
+{
+	int h;
+	int v;
+	int d;
+	int n;
+	int t;
+	int hv;
+
+	/* Avoid compiler warning. */
+	n = 0;
+
+	h = ((f & JPC_WSIG) != 0) + ((f & JPC_ESIG) != 0);
+	v = ((f & JPC_NSIG) != 0) + ((f & JPC_SSIG) != 0);
+	d = ((f & JPC_NWSIG) != 0) + ((f & JPC_NESIG) != 0) + ((f & JPC_SESIG) != 0) + ((f & JPC_SWSIG) != 0);
+	switch (orient) {
+	case JPC_TSFB_HL:
+		t = h;
+		h = v;
+		v = t;
+	case JPC_TSFB_LL:
+	case JPC_TSFB_LH:
+		if (!h) {
+			if (!v) {
+				if (!d) {
+					n = 0;
+				} else if (d == 1) {
+					n = 1;
+				} else {
+					n = 2;
+				}
+			} else if (v == 1) {
+				n = 3;
+			} else {
+				n = 4;
+			}
+		} else if (h == 1) {
+			if (!v) {
+				if (!d) {
+					n = 5;
+				} else {
+					n = 6;
+				}
+			} else {
+				n = 7;
+			}
+		} else {
+			n = 8;
+		}
+		break;
+	case JPC_TSFB_HH:
+		hv = h + v;
+		if (!d) {
+			if (!hv) {
+				n = 0;
+			} else if (hv == 1) {
+				n = 1;
+			} else {
+				n = 2;
+			}
+		} else if (d == 1) {
+			if (!hv) {
+				n = 3;
+			} else if (hv == 1) {
+				n = 4;
+			} else {
+				n = 5;
+			}
+		} else if (d == 2) {
+			if (!hv) {
+				n = 6;
+			} else {
+				n = 7;
+			}
+		} else {
+			n = 8;
+		}
+		break;
+	}
+	assert(n < JPC_NUMZCCTXS);
+	return JPC_ZCCTXNO + n;
+}
+
+int jpc_getspb(int f)
+{
+	int hc;
+	int vc;
+	int n;
+
+	hc = JAS_MIN(((f & (JPC_ESIG | JPC_ESGN)) == JPC_ESIG) + ((f & (JPC_WSIG | JPC_WSGN)) == JPC_WSIG), 1) -
+	  JAS_MIN(((f & (JPC_ESIG | JPC_ESGN)) == (JPC_ESIG | JPC_ESGN)) + ((f & (JPC_WSIG | JPC_WSGN)) == (JPC_WSIG | JPC_WSGN)), 1);
+	vc = JAS_MIN(((f & (JPC_NSIG | JPC_NSGN)) == JPC_NSIG) + ((f & (JPC_SSIG | JPC_SSGN)) == JPC_SSIG), 1) -
+	  JAS_MIN(((f & (JPC_NSIG | JPC_NSGN)) == (JPC_NSIG | JPC_NSGN)) + ((f & (JPC_SSIG | JPC_SSGN)) == (JPC_SSIG | JPC_SSGN)), 1);
+	if (!hc && !vc) {
+		n = 0;
+	} else {
+		n = (!(hc > 0 || (!hc && vc > 0)));
+	}
+	return n;
+}
+
+int jpc_getscctxno(int f)
+{
+	int hc;
+	int vc;
+	int n;
+
+	/* Avoid compiler warning. */
+	n = 0;
+
+	hc = JAS_MIN(((f & (JPC_ESIG | JPC_ESGN)) == JPC_ESIG) + ((f & (JPC_WSIG | JPC_WSGN)) == JPC_WSIG),
+	  1) - JAS_MIN(((f & (JPC_ESIG | JPC_ESGN)) == (JPC_ESIG | JPC_ESGN)) +
+	  ((f & (JPC_WSIG | JPC_WSGN)) == (JPC_WSIG | JPC_WSGN)), 1);
+	vc = JAS_MIN(((f & (JPC_NSIG | JPC_NSGN)) == JPC_NSIG) + ((f & (JPC_SSIG | JPC_SSGN)) == JPC_SSIG),
+	  1) - JAS_MIN(((f & (JPC_NSIG | JPC_NSGN)) == (JPC_NSIG | JPC_NSGN)) +
+	  ((f & (JPC_SSIG | JPC_SSGN)) == (JPC_SSIG | JPC_SSGN)), 1);
+	assert(hc >= -1 && hc <= 1 && vc >= -1 && vc <= 1);
+	if (hc < 0) {
+		hc = -hc;
+		vc = -vc;
+	}
+	if (!hc) {
+		if (vc == -1) {
+			n = 1;
+		} else if (!vc) {
+			n = 0;
+		} else {
+			n = 1;
+		}
+	} else if (hc == 1) {
+		if (vc == -1) {
+			n = 2;
+		} else if (!vc) {
+			n = 3;
+		} else {
+			n = 4;
+		}
+	}
+	assert(n < JPC_NUMSCCTXS);
+	return JPC_SCCTXNO + n;
+}
+
+int jpc_getmagctxno(int f)
+{
+	int n;
+
+	if (!(f & JPC_REFINE)) {
+		n = (f & (JPC_OTHSIGMSK)) ? 1 : 0;
+	} else {
+		n = 2;
+	}
+
+	assert(n < JPC_NUMMAGCTXS);
+	return JPC_MAGCTXNO + n;
+}
+
+void jpc_initctxs(jpc_mqctx_t *ctxs)
+{
+	jpc_mqctx_t *ctx;
+	int i;
+
+	ctx = ctxs;
+	for (i = 0; i < JPC_NUMCTXS; ++i) {
+		ctx->mps = 0;
+		switch (i) {
+		case JPC_UCTXNO:
+			ctx->ind = 46;
+			break;
+		case JPC_ZCCTXNO:
+			ctx->ind = 4;
+			break;
+		case JPC_AGGCTXNO:
+			ctx->ind = 3;
+			break;
+		default:
+			ctx->ind = 0;
+			break;
+		}
+		++ctx;
+	}
+}
+
+/* Calculate the real quantity exp2(n), where x is an integer. */
+double jpc_pow2i(int n)
+{
+	double x;
+	double a;
+
+	x = 1.0;
+	if (n < 0) {
+		a = 0.5;
+		n = -n;
+	} else {
+		a = 2.0;
+	}
+	while (--n >= 0) {
+		x *= a;
+	}
+	return x;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1cod.h b/converter/other/jpeg2000/libjasper/jpc/jpc_t1cod.h
new file mode 100644
index 00000000..3e061d20
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1cod.h
@@ -0,0 +1,344 @@
+/*
+ * 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$
+ */
+
+#ifndef JPC_T1COD_H
+#define JPC_T1COD_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_fix.h"
+#include "jasper/jas_math.h"
+
+#include "jpc_mqcod.h"
+#include "jpc_tsfb.h"
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+/* The number of bits used to index into various lookup tables. */
+#define JPC_NMSEDEC_BITS	7
+#define JPC_NMSEDEC_FRACBITS	(JPC_NMSEDEC_BITS - 1)
+
+/*
+ * Segment types.
+ */
+
+/* Invalid. */
+#define JPC_SEG_INVALID	0
+/* MQ. */
+#define JPC_SEG_MQ		1
+/* Raw. */
+#define JPC_SEG_RAW		2
+
+/* The nominal word size. */
+#define	JPC_PREC	32
+
+/* Tier-1 coding pass types. */
+#define	JPC_SIGPASS	0	/* significance */
+#define	JPC_REFPASS	1	/* refinement */
+#define	JPC_CLNPASS	2	/* cleanup */
+
+/*
+ * Per-sample state information for tier-1 coding.
+ */
+
+/* The northeast neighbour has been found to be significant. */
+#define	JPC_NESIG	0x0001
+/* The southeast neighbour has been found to be significant. */
+#define	JPC_SESIG	0x0002
+/* The southwest neighbour has been found to be significant. */
+#define	JPC_SWSIG	0x0004
+/* The northwest neighbour has been found to be significant. */
+#define	JPC_NWSIG	0x0008
+/* The north neighbour has been found to be significant. */
+#define	JPC_NSIG	0x0010
+/* The east neighbour has been found to be significant. */
+#define	JPC_ESIG	0x0020
+/* The south neighbour has been found to be significant. */
+#define	JPC_SSIG	0x0040
+/* The west neighbour has been found to be significant. */
+#define	JPC_WSIG	0x0080
+/* The significance mask for 8-connected neighbours. */
+#define	JPC_OTHSIGMSK \
+	(JPC_NSIG | JPC_NESIG | JPC_ESIG | JPC_SESIG | JPC_SSIG | JPC_SWSIG | JPC_WSIG | JPC_NWSIG)
+/* The significance mask for 4-connected neighbours. */
+#define	JPC_PRIMSIGMSK	(JPC_NSIG | JPC_ESIG | JPC_SSIG | JPC_WSIG)
+
+/* The north neighbour is negative in value. */
+#define	JPC_NSGN	0x0100
+/* The east neighbour is negative in value. */
+#define	JPC_ESGN	0x0200
+/* The south neighbour is negative in value. */
+#define	JPC_SSGN	0x0400
+/* The west neighbour is negative in value. */
+#define	JPC_WSGN	0x0800
+/* The sign mask for 4-connected neighbours. */
+#define	JPC_SGNMSK	(JPC_NSGN | JPC_ESGN | JPC_SSGN | JPC_WSGN)
+
+/* This sample has been found to be significant. */
+#define JPC_SIG		0x1000
+/* The sample has been refined. */
+#define	JPC_REFINE	0x2000
+/* This sample has been processed during the significance pass. */
+#define	JPC_VISIT	0x4000
+
+/* The number of aggregation contexts. */
+#define	JPC_NUMAGGCTXS	1
+/* The number of zero coding contexts. */
+#define	JPC_NUMZCCTXS	9
+/* The number of magnitude contexts. */
+#define	JPC_NUMMAGCTXS	3
+/* The number of sign coding contexts. */
+#define	JPC_NUMSCCTXS	5
+/* The number of uniform contexts. */
+#define	JPC_NUMUCTXS	1
+
+/* The context ID for the first aggregation context. */
+#define	JPC_AGGCTXNO	0
+/* The context ID for the first zero coding context. */
+#define	JPC_ZCCTXNO		(JPC_AGGCTXNO + JPC_NUMAGGCTXS)
+/* The context ID for the first magnitude context. */
+#define	JPC_MAGCTXNO	(JPC_ZCCTXNO + JPC_NUMZCCTXS)
+/* The context ID for the first sign coding context. */
+#define	JPC_SCCTXNO		(JPC_MAGCTXNO + JPC_NUMMAGCTXS)
+/* The context ID for the first uniform context. */
+#define	JPC_UCTXNO		(JPC_SCCTXNO + JPC_NUMSCCTXS)
+/* The total number of contexts. */
+#define	JPC_NUMCTXS		(JPC_UCTXNO + JPC_NUMUCTXS)
+
+/******************************************************************************\
+* External data.
+\******************************************************************************/
+
+/* These lookup tables are used by various macros/functions. */
+/* Do not access these lookup tables directly. */
+extern int jpc_zcctxnolut[];
+extern int jpc_spblut[];
+extern int jpc_scctxnolut[];
+extern int jpc_magctxnolut[];
+extern jpc_fix_t jpc_refnmsedec[];
+extern jpc_fix_t jpc_signmsedec[];
+extern jpc_fix_t jpc_refnmsedec0[];
+extern jpc_fix_t jpc_signmsedec0[];
+
+/* The initial settings for the MQ contexts. */
+extern jpc_mqctx_t jpc_mqctxs[];
+
+/******************************************************************************\
+* Functions and macros.
+\******************************************************************************/
+
+/* Initialize the MQ contexts. */
+void jpc_initctxs(jpc_mqctx_t *ctxs);
+
+/* Get the zero coding context. */
+int jpc_getzcctxno(int f, int orient);
+#define	JPC_GETZCCTXNO(f, orient) \
+	(jpc_zcctxnolut[((orient) << 8) | ((f) & JPC_OTHSIGMSK)])
+
+/* Get the sign prediction bit. */
+int jpc_getspb(int f);
+#define	JPC_GETSPB(f) \
+	(jpc_spblut[((f) & (JPC_PRIMSIGMSK | JPC_SGNMSK)) >> 4])
+
+/* Get the sign coding context. */
+int jpc_getscctxno(int f);
+#define	JPC_GETSCCTXNO(f) \
+	(jpc_scctxnolut[((f) & (JPC_PRIMSIGMSK | JPC_SGNMSK)) >> 4])
+
+/* Get the magnitude context. */
+int jpc_getmagctxno(int f);
+#define	JPC_GETMAGCTXNO(f) \
+	(jpc_magctxnolut[((f) & JPC_OTHSIGMSK) | ((((f) & JPC_REFINE) != 0) << 11)])
+
+/* Get the normalized MSE reduction for significance passes. */
+#define	JPC_GETSIGNMSEDEC(x, bitpos)	jpc_getsignmsedec_macro(x, bitpos)
+jpc_fix_t jpc_getsignmsedec_func(jpc_fix_t x, int bitpos);
+#define	jpc_getsignmsedec_macro(x, bitpos) \
+	((bitpos > JPC_NMSEDEC_FRACBITS) ? jpc_signmsedec[JPC_ASR(x, bitpos - JPC_NMSEDEC_FRACBITS) & JAS_ONES(JPC_NMSEDEC_BITS)] : \
+	  (jpc_signmsedec0[JPC_ASR(x, bitpos - JPC_NMSEDEC_FRACBITS) & JAS_ONES(JPC_NMSEDEC_BITS)]))
+
+/* Get the normalized MSE reduction for refinement passes. */
+#define	JPC_GETREFNMSEDEC(x, bitpos)	jpc_getrefnmsedec_macro(x, bitpos)
+jpc_fix_t jpc_refsignmsedec_func(jpc_fix_t x, int bitpos);
+#define	jpc_getrefnmsedec_macro(x, bitpos) \
+	((bitpos > JPC_NMSEDEC_FRACBITS) ? jpc_refnmsedec[JPC_ASR(x, bitpos - JPC_NMSEDEC_FRACBITS) & JAS_ONES(JPC_NMSEDEC_BITS)] : \
+	  (jpc_refnmsedec0[JPC_ASR(x, bitpos - JPC_NMSEDEC_FRACBITS) & JAS_ONES(JPC_NMSEDEC_BITS)]))
+
+/* Arithmetic shift right (with ability to shift left also). */
+#define	JPC_ASR(x, n) \
+	(((n) >= 0) ? ((x) >> (n)) : ((x) << (-(n))))
+
+/* Update the per-sample state information. */
+#define	JPC_UPDATEFLAGS4(fp, rowstep, s, vcausalflag) \
+{ \
+	register jpc_fix_t *np = (fp) - (rowstep); \
+	register jpc_fix_t *sp = (fp) + (rowstep); \
+	if ((vcausalflag)) { \
+		sp[-1] |= JPC_NESIG; \
+		sp[1] |= JPC_NWSIG; \
+		if (s) { \
+			*sp |= JPC_NSIG | JPC_NSGN; \
+			(fp)[-1] |= JPC_ESIG | JPC_ESGN; \
+			(fp)[1] |= JPC_WSIG | JPC_WSGN; \
+		} else { \
+			*sp |= JPC_NSIG; \
+			(fp)[-1] |= JPC_ESIG; \
+			(fp)[1] |= JPC_WSIG; \
+		} \
+	} else { \
+		np[-1] |= JPC_SESIG; \
+		np[1] |= JPC_SWSIG; \
+		sp[-1] |= JPC_NESIG; \
+		sp[1] |= JPC_NWSIG; \
+		if (s) { \
+			*np |= JPC_SSIG | JPC_SSGN; \
+			*sp |= JPC_NSIG | JPC_NSGN; \
+			(fp)[-1] |= JPC_ESIG | JPC_ESGN; \
+			(fp)[1] |= JPC_WSIG | JPC_WSGN; \
+		} else { \
+			*np |= JPC_SSIG; \
+			*sp |= JPC_NSIG; \
+			(fp)[-1] |= JPC_ESIG; \
+			(fp)[1] |= JPC_WSIG; \
+		} \
+	} \
+}
+
+/* Initialize the lookup tables used by the codec. */
+void jpc_initluts(void);
+
+/* Get the nominal gain associated with a particular band. */
+int JPC_NOMINALGAIN(int qmfbid, int numlvls, int lvlno, int orient);
+
+/* Get the coding pass type. */
+int JPC_PASSTYPE(int passno);
+
+/* Get the segment type. */
+int JPC_SEGTYPE(int passno, int firstpassno, int bypass);
+
+/* Get the number of coding passess in the segment. */
+int JPC_SEGPASSCNT(int passno, int firstpassno, int numpasses, int bypass,
+  int termall);
+
+/* Is the coding pass terminated? */
+int JPC_ISTERMINATED(int passno, int firstpassno, int numpasses, int termall,
+  int lazy);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c
new file mode 100644
index 00000000..01a54ea8
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.c
@@ -0,0 +1,954 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tier 1 Decoder
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "jasper/jas_fix.h"
+#include "jasper/jas_stream.h"
+#include "jasper/jas_math.h"
+
+#include "jpc_bs.h"
+#include "jpc_mqdec.h"
+#include "jpc_t1dec.h"
+#include "jpc_t1cod.h"
+#include "jpc_dec.h"
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+static int jpc_dec_decodecblk(jpc_dec_t *dec, jpc_dec_tile_t *tile, jpc_dec_tcomp_t *tcomp, jpc_dec_band_t *band,
+  jpc_dec_cblk_t *cblk, int dopartial, int maxlyrs);
+static int dec_sigpass(jpc_dec_t *dec, jpc_mqdec_t *mqdec, int bitpos, int orient,
+  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data);
+static int dec_rawsigpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos,
+  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data);
+static int dec_refpass(jpc_dec_t *dec, jpc_mqdec_t *mqdec, int bitpos, int vcausalflag,
+  jas_matrix_t *flags, jas_matrix_t *data);
+static int dec_rawrefpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos,
+  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data);
+static int dec_clnpass(jpc_dec_t *dec, jpc_mqdec_t *mqdec, int bitpos, int orient,
+  int vcausalflag, int segsymflag, jas_matrix_t *flags, jas_matrix_t *data);
+
+#if defined(DEBUG)
+static long t1dec_cnt = 0;
+#endif
+
+#if !defined(DEBUG)
+#define	JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename) \
+	((v) = jpc_mqdec_getbit(mqdec))
+#else
+#define	JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename) \
+{ \
+	(v) = jpc_mqdec_getbit(mqdec); \
+	if (jas_getdbglevel() >= 100) { \
+		fprintf(stderr, "index = %ld; passtype = %s; symtype = %s; sym = %d\n", t1dec_cnt, passtypename, symtypename, v); \
+		++t1dec_cnt; \
+	} \
+}
+#endif
+#define	JPC_T1D_GETBITNOSKEW(mqdec, v, passtypename, symtypename) \
+	JPC_T1D_GETBIT(mqdec, v, passtypename, symtypename)
+
+#if !defined(DEBUG)
+#define	JPC_T1D_RAWGETBIT(bitstream, v, passtypename, symtypename) \
+	((v) = jpc_bitstream_getbit(bitstream))
+#else
+#define	JPC_T1D_RAWGETBIT(bitstream, v, passtypename, symtypename) \
+{ \
+	(v) = jpc_bitstream_getbit(bitstream); \
+	if (jas_getdbglevel() >= 100) { \
+		fprintf(stderr, "index = %ld; passtype = %s; symtype = %s; sym = %d\n", t1dec_cnt, passtypename, symtypename, v); \
+		++t1dec_cnt; \
+	} \
+}
+#endif
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+int jpc_dec_decodecblks(jpc_dec_t *dec, jpc_dec_tile_t *tile)
+{
+	jpc_dec_tcomp_t *tcomp;
+	int compcnt;
+	jpc_dec_rlvl_t *rlvl;
+	int rlvlcnt;
+	jpc_dec_band_t *band;
+	int bandcnt;
+	jpc_dec_prc_t *prc;
+	int prccnt;
+	jpc_dec_cblk_t *cblk;
+	int cblkcnt;
+
+	for (compcnt = dec->numcomps, tcomp = tile->tcomps; compcnt > 0;
+	  --compcnt, ++tcomp) {
+		for (rlvlcnt = tcomp->numrlvls, rlvl = tcomp->rlvls;
+		  rlvlcnt > 0; --rlvlcnt, ++rlvl) {
+			if (!rlvl->bands) {
+				continue;
+			}
+			for (bandcnt = rlvl->numbands, band = rlvl->bands;
+			  bandcnt > 0; --bandcnt, ++band) {
+				if (!band->data) {
+					continue;
+				}
+				for (prccnt = rlvl->numprcs, prc = band->prcs;
+				  prccnt > 0; --prccnt, ++prc) {
+					if (!prc->cblks) {
+						continue;
+					}
+					for (cblkcnt = prc->numcblks,
+					  cblk = prc->cblks; cblkcnt > 0;
+					  --cblkcnt, ++cblk) {
+						if (jpc_dec_decodecblk(dec, tile, tcomp,
+						  band, cblk, 1, JPC_MAXLYRS)) {
+							return -1;
+						}
+					}
+				}
+
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int jpc_dec_decodecblk(jpc_dec_t *dec, jpc_dec_tile_t *tile, jpc_dec_tcomp_t *tcomp, jpc_dec_band_t *band,
+  jpc_dec_cblk_t *cblk, int dopartial, int maxlyrs)
+{
+	jpc_dec_seg_t *seg;
+	int i;
+	int bpno;
+	int passtype;
+	int ret;
+	int compno;
+	int filldata;
+	int fillmask;
+	jpc_dec_ccp_t *ccp;
+
+	compno = tcomp - tile->tcomps;
+
+	if (!cblk->flags) {
+		/* Note: matrix is assumed to be zeroed */
+		if (!(cblk->flags = jas_matrix_create(jas_matrix_numrows(cblk->data) +
+		  2, jas_matrix_numcols(cblk->data) + 2))) {
+			return -1;
+		}
+	}
+
+	seg = cblk->segs.head;
+	while (seg && (seg != cblk->curseg || dopartial) && (maxlyrs < 0 ||
+	  seg->lyrno < maxlyrs)) {
+		assert(seg->numpasses >= seg->maxpasses || dopartial);
+		assert(seg->stream);
+		jas_stream_rewind(seg->stream);
+		jas_stream_setrwcount(seg->stream, 0);
+		if (seg->type == JPC_SEG_MQ) {
+			if (!cblk->mqdec) {
+				if (!(cblk->mqdec = jpc_mqdec_create(JPC_NUMCTXS, 0))) {
+					return -1;
+				}
+				jpc_mqdec_setctxs(cblk->mqdec, JPC_NUMCTXS, jpc_mqctxs);
+			}
+			jpc_mqdec_setinput(cblk->mqdec, seg->stream);
+			jpc_mqdec_init(cblk->mqdec);
+		} else {
+			assert(seg->type == JPC_SEG_RAW);
+			if (!cblk->nulldec) {
+				if (!(cblk->nulldec = jpc_bitstream_sopen(seg->stream, "r"))) {
+					assert(0);
+				}
+			}
+		}
+
+
+		for (i = 0; i < seg->numpasses; ++i) {
+			if (cblk->numimsbs > band->numbps) {
+				ccp = &tile->cp->ccps[compno];
+				if (ccp->roishift <= 0) {
+					fprintf(stderr, "warning: corrupt code stream\n");
+				} else {
+					if (cblk->numimsbs < ccp->roishift - band->numbps) {
+						fprintf(stderr, "warning: corrupt code stream\n");
+					}
+				}
+			}
+			bpno = band->roishift + band->numbps - 1 - (cblk->numimsbs +
+			  (seg->passno + i - cblk->firstpassno + 2) / 3);
+if (bpno < 0) {
+	goto premature_exit;
+}
+#if 1
+			passtype = (seg->passno + i + 2) % 3;
+#else
+			passtype = JPC_PASSTYPE(seg->passno + i + 2);
+#endif
+			assert(bpno >= 0 && bpno < 31);
+			switch (passtype) {
+			case JPC_SIGPASS:
+				ret = (seg->type == JPC_SEG_MQ) ? dec_sigpass(dec,
+				  cblk->mqdec, bpno, band->orient,
+				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+				  cblk->flags, cblk->data) :
+				  dec_rawsigpass(dec, cblk->nulldec, bpno,
+				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+				  cblk->flags, cblk->data);
+				break;
+			case JPC_REFPASS:
+				ret = (seg->type == JPC_SEG_MQ) ?
+				  dec_refpass(dec, cblk->mqdec, bpno,
+				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+				  cblk->flags, cblk->data) :
+				  dec_rawrefpass(dec, cblk->nulldec, bpno,
+				  (tile->cp->ccps[compno].cblkctx & JPC_COX_VSC) != 0,
+				  cblk->flags, cblk->data);
+				break;
+			case JPC_CLNPASS:
+				assert(seg->type == JPC_SEG_MQ);
+				ret = dec_clnpass(dec, cblk->mqdec, bpno,
+				  band->orient, (tile->cp->ccps[compno].cblkctx &
+				  JPC_COX_VSC) != 0, (tile->cp->ccps[compno].cblkctx &
+				  JPC_COX_SEGSYM) != 0, cblk->flags,
+				  cblk->data);
+				break;
+			default:
+				ret = -1;
+				break;
+			}
+			/* Do we need to reset after each coding pass? */
+			if (tile->cp->ccps[compno].cblkctx & JPC_COX_RESET) {
+				jpc_mqdec_setctxs(cblk->mqdec, JPC_NUMCTXS, jpc_mqctxs);
+			}
+
+			if (ret) {
+				fprintf(stderr, "coding pass failed passtype=%d segtype=%d\n", passtype, seg->type);
+				return -1;
+			}
+
+		}
+
+		if (seg->type == JPC_SEG_MQ) {
+/* Note: dont destroy mq decoder because context info will be lost */
+		} else {
+			assert(seg->type == JPC_SEG_RAW);
+			if (tile->cp->ccps[compno].cblkctx & JPC_COX_PTERM) {
+				fillmask = 0x7f;
+				filldata = 0x2a;
+			} else {
+				fillmask = 0;
+				filldata = 0;
+			}
+			if ((ret = jpc_bitstream_inalign(cblk->nulldec, fillmask,
+			  filldata)) < 0) {
+				return -1;
+			} else if (ret > 0) {
+				fprintf(stderr, "warning: bad termination pattern detected\n");
+			}
+			jpc_bitstream_close(cblk->nulldec);
+			cblk->nulldec = 0;
+		}
+
+		cblk->curseg = seg->next;
+		jpc_seglist_remove(&cblk->segs, seg);
+		jpc_seg_destroy(seg);
+		seg = cblk->curseg;
+	}
+
+	assert(dopartial ? (!cblk->curseg) : 1);
+
+premature_exit:
+	return 0;
+}
+
+/******************************************************************************\
+* Code for significance pass.
+\******************************************************************************/
+
+#define	jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf, orient, mqdec, vcausalflag) \
+{ \
+	int f; \
+	int v; \
+	f = *(fp); \
+	if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
+		jpc_mqdec_setcurctx((mqdec), JPC_GETZCCTXNO(f, (orient))); \
+		JPC_T1D_GETBIT((mqdec), v, "SIG", "ZC"); \
+		if (v) { \
+			jpc_mqdec_setcurctx((mqdec), JPC_GETSCCTXNO(f)); \
+			JPC_T1D_GETBIT((mqdec), v, "SIG", "SC"); \
+			v ^= JPC_GETSPB(f); \
+			JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
+			*(fp) |= JPC_SIG; \
+			*(dp) = (v) ? (-(oneplushalf)) : (oneplushalf); \
+		} \
+		*(fp) |= JPC_VISIT; \
+	} \
+}
+
+static int dec_sigpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos, int orient,
+  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data)
+{
+	int i;
+	int j;
+	int one;
+	int half;
+	int oneplushalf;
+	int vscanlen;
+	int width;
+	int height;
+	jpc_fix_t *fp;
+	int frowstep;
+	int fstripestep;
+	jpc_fix_t *fstripestart;
+	jpc_fix_t *fvscanstart;
+	jpc_fix_t *dp;
+	int drowstep;
+	int dstripestep;
+	jpc_fix_t *dstripestart;
+	jpc_fix_t *dvscanstart;
+	int k;
+
+	width = jas_matrix_numcols(data);
+	height = jas_matrix_numrows(data);
+	frowstep = jas_matrix_rowstep(flags);
+	drowstep = jas_matrix_rowstep(data);
+	fstripestep = frowstep << 2;
+	dstripestep = drowstep << 2;
+
+	one = 1 << bitpos;
+	half = one >> 1;
+	oneplushalf = one | half;
+
+	fstripestart = jas_matrix_getref(flags, 1, 1);
+	dstripestart = jas_matrix_getref(data, 0, 0);
+	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+	  dstripestart += dstripestep) {
+		fvscanstart = fstripestart;
+		dvscanstart = dstripestart;
+		vscanlen = JAS_MIN(i, 4);
+		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+			fp = fvscanstart;
+			dp = dvscanstart;
+			k = vscanlen;
+
+			/* Process first sample in vertical scan. */
+			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+			  orient, mqdec, vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process second sample in vertical scan. */
+			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+			  orient, mqdec, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process third sample in vertical scan. */
+			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+			  orient, mqdec, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process fourth sample in vertical scan. */
+			jpc_sigpass_step(fp, frowstep, dp, bitpos, oneplushalf,
+			  orient, mqdec, 0);
+		}
+	}
+	return 0;
+}
+
+#define	jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf, in, vcausalflag) \
+{ \
+	jpc_fix_t f = *(fp); \
+	jpc_fix_t v; \
+	if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
+		JPC_T1D_RAWGETBIT(in, v, "SIG", "ZC"); \
+		if (v < 0) { \
+			return -1; \
+		} \
+		if (v) { \
+			JPC_T1D_RAWGETBIT(in, v, "SIG", "SC"); \
+			if (v < 0) { \
+				return -1; \
+			} \
+			JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
+			*(fp) |= JPC_SIG; \
+			*(dp) = v ? (-oneplushalf) : (oneplushalf); \
+		} \
+		*(fp) |= JPC_VISIT; \
+	} \
+}
+
+static int dec_rawsigpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos, int vcausalflag,
+  jas_matrix_t *flags, jas_matrix_t *data)
+{
+	int i;
+	int j;
+	int k;
+	int one;
+	int half;
+	int oneplushalf;
+	int vscanlen;
+	int width;
+	int height;
+	jpc_fix_t *fp;
+	int frowstep;
+	int fstripestep;
+	jpc_fix_t *fstripestart;
+	jpc_fix_t *fvscanstart;
+	jpc_fix_t *dp;
+	int drowstep;
+	int dstripestep;
+	jpc_fix_t *dstripestart;
+	jpc_fix_t *dvscanstart;
+
+	width = jas_matrix_numcols(data);
+	height = jas_matrix_numrows(data);
+	frowstep = jas_matrix_rowstep(flags);
+	drowstep = jas_matrix_rowstep(data);
+	fstripestep = frowstep << 2;
+	dstripestep = drowstep << 2;
+
+	one = 1 << bitpos;
+	half = one >> 1;
+	oneplushalf = one | half;
+
+	fstripestart = jas_matrix_getref(flags, 1, 1);
+	dstripestart = jas_matrix_getref(data, 0, 0);
+	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+	  dstripestart += dstripestep) {
+		fvscanstart = fstripestart;
+		dvscanstart = dstripestart;
+		vscanlen = JAS_MIN(i, 4);
+		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+			fp = fvscanstart;
+			dp = dvscanstart;
+			k = vscanlen;
+
+			/* Process first sample in vertical scan. */
+			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+			  in, vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process second sample in vertical scan. */
+			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+			  in, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process third sample in vertical scan. */
+			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+			  in, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process fourth sample in vertical scan. */
+			jpc_rawsigpass_step(fp, frowstep, dp, oneplushalf,
+			  in, 0);
+
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************\
+* Code for refinement pass.
+\******************************************************************************/
+
+#define	jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, vcausalflag) \
+{ \
+	int v; \
+	int t; \
+	if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
+		jpc_mqdec_setcurctx((mqdec), JPC_GETMAGCTXNO(*(fp))); \
+		JPC_T1D_GETBITNOSKEW((mqdec), v, "REF", "MR"); \
+		t = (v ? (poshalf) : (neghalf)); \
+		*(dp) += (*(dp) < 0) ? (-t) : t; \
+		*(fp) |= JPC_REFINE; \
+	} \
+}
+
+static int dec_refpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos,
+  int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data)
+{
+	int i;
+	int j;
+	int vscanlen;
+	int width;
+	int height;
+	int one;
+	int poshalf;
+	int neghalf;
+	jpc_fix_t *fp;
+	int frowstep;
+	int fstripestep;
+	jpc_fix_t *fstripestart;
+	jpc_fix_t *fvscanstart;
+	jpc_fix_t *dp;
+	int drowstep;
+	int dstripestep;
+	jpc_fix_t *dstripestart;
+	jpc_fix_t *dvscanstart;
+	int k;
+
+	width = jas_matrix_numcols(data);
+	height = jas_matrix_numrows(data);
+	frowstep = jas_matrix_rowstep(flags);
+	drowstep = jas_matrix_rowstep(data);
+	fstripestep = frowstep << 2;
+	dstripestep = drowstep << 2;
+
+	one = 1 << bitpos;
+	poshalf = one >> 1;
+	neghalf = (bitpos > 0) ? (-poshalf) : (-1);
+
+	fstripestart = jas_matrix_getref(flags, 1, 1);
+	dstripestart = jas_matrix_getref(data, 0, 0);
+	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+	  dstripestart += dstripestep) {
+		fvscanstart = fstripestart;
+		dvscanstart = dstripestart;
+		vscanlen = JAS_MIN(i, 4);
+		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+			fp = fvscanstart;
+			dp = dvscanstart;
+			k = vscanlen;
+
+			/* Process first sample in vertical scan. */
+			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec,
+			  vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process second sample in vertical scan. */
+			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process third sample in vertical scan. */
+			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process fourth sample in vertical scan. */
+			jpc_refpass_step(fp, dp, poshalf, neghalf, mqdec, 0);
+		}
+	}
+
+	return 0;
+}
+
+#define	jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, vcausalflag) \
+{ \
+	jpc_fix_t v; \
+	jpc_fix_t t; \
+	if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
+		JPC_T1D_RAWGETBIT(in, v, "REF", "MAGREF"); \
+		if (v < 0) { \
+			return -1; \
+		} \
+		t = (v ? poshalf : neghalf); \
+		*(dp) += (*(dp) < 0) ? (-t) : t; \
+		*(fp) |= JPC_REFINE; \
+	} \
+}
+
+static int dec_rawrefpass(jpc_dec_t *dec, jpc_bitstream_t *in, int bitpos, int vcausalflag,
+  jas_matrix_t *flags, jas_matrix_t *data)
+{
+	int i;
+	int j;
+	int k;
+	int vscanlen;
+	int width;
+	int height;
+	int one;
+	int poshalf;
+	int neghalf;
+	jpc_fix_t *fp;
+	int frowstep;
+	int fstripestep;
+	jpc_fix_t *fstripestart;
+	jpc_fix_t *fvscanstart;
+	jpc_fix_t *dp;
+	int drowstep;
+	int dstripestep;
+	jpc_fix_t *dstripestart;
+	jpc_fix_t *dvscanstart;
+
+	width = jas_matrix_numcols(data);
+	height = jas_matrix_numrows(data);
+	frowstep = jas_matrix_rowstep(flags);
+	drowstep = jas_matrix_rowstep(data);
+	fstripestep = frowstep << 2;
+	dstripestep = drowstep << 2;
+
+	one = 1 << bitpos;
+	poshalf = one >> 1;
+	neghalf = (bitpos > 0) ? (-poshalf) : (-1);
+
+	fstripestart = jas_matrix_getref(flags, 1, 1);
+	dstripestart = jas_matrix_getref(data, 0, 0);
+	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+	  dstripestart += dstripestep) {
+		fvscanstart = fstripestart;
+		dvscanstart = dstripestart;
+		vscanlen = JAS_MIN(i, 4);
+		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+			fp = fvscanstart;
+			dp = dvscanstart;
+			k = vscanlen;
+
+			/* Process first sample in vertical scan. */
+			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in,
+			  vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process second sample in vertical scan. */
+			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process third sample in vertical scan. */
+			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process fourth sample in vertical scan. */
+			jpc_rawrefpass_step(fp, dp, poshalf, neghalf, in, 0);
+		}
+	}
+	return 0;
+}
+
+/******************************************************************************\
+* Code for cleanup pass.
+\******************************************************************************/
+
+#define	jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient, mqdec, flabel, plabel, vcausalflag) \
+{ \
+	int v; \
+flabel \
+	if (!((f) & (JPC_SIG | JPC_VISIT))) { \
+		jpc_mqdec_setcurctx((mqdec), JPC_GETZCCTXNO((f), (orient))); \
+		JPC_T1D_GETBIT((mqdec), v, "CLN", "ZC"); \
+		if (v) { \
+plabel \
+			/* Coefficient is significant. */ \
+			jpc_mqdec_setcurctx((mqdec), JPC_GETSCCTXNO(f)); \
+			JPC_T1D_GETBIT((mqdec), v, "CLN", "SC"); \
+			v ^= JPC_GETSPB(f); \
+			*(dp) = (v) ? (-(oneplushalf)) : (oneplushalf); \
+			JPC_UPDATEFLAGS4((fp), (frowstep), v, (vcausalflag)); \
+			*(fp) |= JPC_SIG; \
+		} \
+	} \
+	/* XXX - Is this correct?  Can aggregation cause some VISIT bits not to be reset?  Check. */ \
+	*(fp) &= ~JPC_VISIT; \
+}
+
+static int dec_clnpass(jpc_dec_t *dec, register jpc_mqdec_t *mqdec, int bitpos, int orient,
+  int vcausalflag, int segsymflag, jas_matrix_t *flags, jas_matrix_t *data)
+{
+	int i;
+	int j;
+	int k;
+	int vscanlen;
+	int v;
+	int half;
+	int runlen;
+	int f;
+	int width;
+	int height;
+	int one;
+	int oneplushalf;
+
+	jpc_fix_t *fp;
+	int frowstep;
+	int fstripestep;
+	jpc_fix_t *fstripestart;
+	jpc_fix_t *fvscanstart;
+
+	jpc_fix_t *dp;
+	int drowstep;
+	int dstripestep;
+	jpc_fix_t *dstripestart;
+	jpc_fix_t *dvscanstart;
+
+	one = 1 << bitpos;
+	half = one >> 1;
+	oneplushalf = one | half;
+
+	width = jas_matrix_numcols(data);
+	height = jas_matrix_numrows(data);
+
+	frowstep = jas_matrix_rowstep(flags);
+	drowstep = jas_matrix_rowstep(data);
+	fstripestep = frowstep << 2;
+	dstripestep = drowstep << 2;
+
+	fstripestart = jas_matrix_getref(flags, 1, 1);
+	dstripestart = jas_matrix_getref(data, 0, 0);
+	for (i = 0; i < height; i += 4, fstripestart += fstripestep,
+	  dstripestart += dstripestep) {
+		fvscanstart = fstripestart;
+		dvscanstart = dstripestart;
+		vscanlen = JAS_MIN(4, height - i);
+		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+			fp = fvscanstart;
+			if (vscanlen >= 4 && (!((*fp) & (JPC_SIG | JPC_VISIT |
+			  JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) & (JPC_SIG |
+			  JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) &
+			  (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep,
+			  !((*fp) & (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK)))) {
+
+				jpc_mqdec_setcurctx(mqdec, JPC_AGGCTXNO);
+				JPC_T1D_GETBIT(mqdec, v, "CLN", "AGG");
+				if (!v) {
+					continue;
+				}
+				jpc_mqdec_setcurctx(mqdec, JPC_UCTXNO);
+				JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "RL");
+				runlen = v;
+				JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "RL");
+				runlen = (runlen << 1) | v;
+				f = *(fp = fvscanstart + frowstep * runlen);
+				dp = dvscanstart + drowstep * runlen;
+				k = vscanlen - runlen;
+				switch (runlen) {
+				case 0:
+					goto clnpass_partial0;
+					break;
+				case 1:
+					goto clnpass_partial1;
+					break;
+				case 2:
+					goto clnpass_partial2;
+					break;
+				case 3:
+					goto clnpass_partial3;
+					break;
+				}
+			} else {
+				f = *(fp = fvscanstart);
+				dp = dvscanstart;
+				k = vscanlen;
+				goto clnpass_full0;
+			}
+
+			/* Process first sample in vertical scan. */
+			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+			  mqdec, clnpass_full0:, clnpass_partial0:,
+			  vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process second sample in vertical scan. */
+			f = *fp;
+			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+				mqdec, ;, clnpass_partial1:, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process third sample in vertical scan. */
+			f = *fp;
+			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+				mqdec, ;, clnpass_partial2:, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			/* Process fourth sample in vertical scan. */
+			f = *fp;
+			jpc_clnpass_step(f, fp, frowstep, dp, oneplushalf, orient,
+				mqdec, ;, clnpass_partial3:, 0);
+		}
+	}
+
+	if (segsymflag) {
+		int segsymval;
+		segsymval = 0;
+		jpc_mqdec_setcurctx(mqdec, JPC_UCTXNO);
+		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+		segsymval = (segsymval << 1) | (v & 1);
+		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+		segsymval = (segsymval << 1) | (v & 1);
+		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+		segsymval = (segsymval << 1) | (v & 1);
+		JPC_T1D_GETBITNOSKEW(mqdec, v, "CLN", "SEGSYM");
+		segsymval = (segsymval << 1) | (v & 1);
+		if (segsymval != 0xa) {
+			fprintf(stderr, "warning: bad segmentation symbol\n");
+		}
+	}
+
+	return 0;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h
new file mode 100644
index 00000000..e28a1f57
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.h
@@ -0,0 +1,137 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tier 1 Decoder
+ *
+ * $Id$
+ */
+
+#ifndef JPC_T1DEC_H
+#define JPC_T1DEC_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jpc_dec.h"
+#include "jpc_mqdec.h"
+#include "jpc_t1cod.h"
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Decode all of the code blocks for a particular tile. */
+int jpc_dec_decodecblks(jpc_dec_t *dec, jpc_dec_tile_t *tile);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.c
new file mode 100644
index 00000000..8aa024a9
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.c
@@ -0,0 +1,1008 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tier 1 Encoder
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "jasper/jas_fix.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_math.h"
+
+#include "jpc_t1enc.h"
+#include "jpc_t1cod.h"
+#include "jpc_enc.h"
+#include "jpc_cod.h"
+#include "jpc_math.h"
+
+static int jpc_encsigpass(jpc_mqenc_t *mqenc, int bitpos, int orient, int,
+  jas_matrix_t *flags, jas_matrix_t *data, int term, long *nmsedec);
+
+static int jpc_encrefpass(jpc_mqenc_t *mqenc, int bitpos, int, jas_matrix_t *flags,
+  jas_matrix_t *data, int term, long *nmsedec);
+
+static int jpc_encclnpass(jpc_mqenc_t *mqenc, int bitpos, int orient, int,
+  int, jas_matrix_t *flags, jas_matrix_t *data, int term, long *nmsedec);
+
+static int jpc_encrawsigpass(jpc_bitstream_t *out, int bitpos, int,
+  jas_matrix_t *flags, jas_matrix_t *data, int term, long *nmsedec);
+
+static int jpc_encrawrefpass(jpc_bitstream_t *out, int bitpos, int,
+  jas_matrix_t *flags, jas_matrix_t *data, int term, long *nmsedec);
+
+/******************************************************************************\
+* Code for encoding code blocks.
+\******************************************************************************/
+
+/* Encode all of the code blocks associated with the current tile. */
+int jpc_enc_enccblks(jpc_enc_t *enc)
+{
+	jpc_enc_tcmpt_t *tcmpt;
+	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;
+	int i;
+	int j;
+	int mx;
+	int bmx;
+	int v;
+	jpc_enc_tile_t *tile;
+	uint_fast32_t prcno;
+	jpc_enc_prc_t *prc;
+
+	tile = enc->curtile;
+
+	endcomps = &tile->tcmpts[tile->numtcmpts];
+	for (tcmpt = tile->tcmpts; tcmpt != endcomps; ++tcmpt) {
+		endlvls = &tcmpt->rlvls[tcmpt->numrlvls];
+		for (lvl = tcmpt->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;
+					}
+					bmx = 0;
+					endcblks = &prc->cblks[prc->numcblks];
+					for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
+						mx = 0;
+						for (i = 0; i < jas_matrix_numrows(cblk->data); ++i) {
+							for (j = 0; j < jas_matrix_numcols(cblk->data); ++j) {
+								v = abs(jas_matrix_get(cblk->data, i, j));
+								if (v > mx) {
+									mx = v;
+								}
+							}
+						}
+						if (mx > bmx) {
+							bmx = mx;
+						}
+						cblk->numbps = JAS_MAX(jpc_firstone(mx) + 1 - JPC_NUMEXTRABITS, 0);
+					}
+
+					for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
+						cblk->numimsbs = band->numbps - cblk->numbps;
+						assert(cblk->numimsbs >= 0);
+					}
+
+					for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
+						if (jpc_enc_enccblk(enc, cblk->stream, tcmpt, band, cblk)) {
+							return -1;
+						}
+					}
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static int getthebyte(jas_stream_t *in, long off)
+{
+	int c;
+	long oldpos;
+	oldpos = jas_stream_tell(in);
+	assert(oldpos >= 0);
+	jas_stream_seek(in, off, SEEK_SET);
+	c = jas_stream_peekc(in);
+	jas_stream_seek(in, oldpos, SEEK_SET);
+	return c;
+}
+
+/* Encode a single code block. */
+int jpc_enc_enccblk(jpc_enc_t *enc, jas_stream_t *out, jpc_enc_tcmpt_t *tcmpt, jpc_enc_band_t *band, jpc_enc_cblk_t *cblk)
+{
+	jpc_enc_pass_t *pass;
+	jpc_enc_pass_t *endpasses;
+	int bitpos;
+	int n;
+	int adjust;
+	int ret;
+	int passtype;
+	int t;
+	jpc_bitstream_t *bout;
+	jpc_enc_pass_t *termpass;
+	jpc_enc_rlvl_t *rlvl;
+	int vcausal;
+	int segsym;
+	int termmode;
+	int c;
+
+	bout = 0;
+	rlvl = band->rlvl;
+
+	cblk->stream = jas_stream_memopen(0, 0);
+	assert(cblk->stream);
+	cblk->mqenc = jpc_mqenc_create(JPC_NUMCTXS, cblk->stream);
+	assert(cblk->mqenc);
+	jpc_mqenc_setctxs(cblk->mqenc, JPC_NUMCTXS, jpc_mqctxs);
+
+	cblk->numpasses = (cblk->numbps > 0) ? (3 * cblk->numbps - 2) : 0;
+	if (cblk->numpasses > 0) {
+		cblk->passes = jas_malloc(cblk->numpasses * sizeof(jpc_enc_pass_t));
+		assert(cblk->passes);
+	} else {
+		cblk->passes = 0;
+	}
+	endpasses = &cblk->passes[cblk->numpasses];
+	for (pass = cblk->passes; pass != endpasses; ++pass) {
+		pass->start = 0;
+		pass->end = 0;
+		pass->term = JPC_ISTERMINATED(pass - cblk->passes, 0, cblk->numpasses, (tcmpt->cblksty & JPC_COX_TERMALL) != 0, (tcmpt->cblksty & JPC_COX_LAZY) != 0);
+		pass->type = JPC_SEGTYPE(pass - cblk->passes, 0, (tcmpt->cblksty & JPC_COX_LAZY) != 0);
+		pass->lyrno = -1;
+if (pass == endpasses - 1) {
+assert(pass->term == 1);
+	pass->term = 1;
+}
+	}
+
+	cblk->flags = jas_matrix_create(jas_matrix_numrows(cblk->data) + 2,
+	  jas_matrix_numcols(cblk->data) + 2);
+	assert(cblk->flags);
+
+
+	bitpos = cblk->numbps - 1;
+	pass = cblk->passes;
+	n = cblk->numpasses;
+	while (--n >= 0) {
+
+		if (pass->type == JPC_SEG_MQ) {
+			/* NOP */
+		} else {
+			assert(pass->type == JPC_SEG_RAW);
+			if (!bout) {
+				bout = jpc_bitstream_sopen(cblk->stream, "w");
+				assert(bout);
+			}
+		}
+
+#if 1
+		passtype = (pass - cblk->passes + 2) % 3;
+#else
+		passtype = JPC_PASSTYPE(pass - cblk->passes + 2);
+#endif
+		pass->start = jas_stream_tell(cblk->stream);
+#if 0
+assert(jas_stream_tell(cblk->stream) == jas_stream_getrwcount(cblk->stream));
+#endif
+		assert(bitpos >= 0);
+		vcausal = (tcmpt->cblksty & JPC_COX_VSC) != 0;
+		segsym = (tcmpt->cblksty & JPC_COX_SEGSYM) != 0;
+		if (pass->term) {
+			termmode = ((tcmpt->cblksty & JPC_COX_PTERM) ?
+			  JPC_MQENC_PTERM : JPC_MQENC_DEFTERM) + 1;
+		} else {
+			termmode = 0;
+		}
+		switch (passtype) {
+		case JPC_SIGPASS:
+			ret = (pass->type == JPC_SEG_MQ) ? jpc_encsigpass(cblk->mqenc,
+			  bitpos, band->orient, vcausal, cblk->flags,
+			  cblk->data, termmode, &pass->nmsedec) :
+			  jpc_encrawsigpass(bout, bitpos, vcausal, cblk->flags,
+			  cblk->data, termmode, &pass->nmsedec);
+			break;
+		case JPC_REFPASS:
+			ret = (pass->type == JPC_SEG_MQ) ? jpc_encrefpass(cblk->mqenc,
+			  bitpos, vcausal, cblk->flags, cblk->data, termmode,
+			  &pass->nmsedec) : jpc_encrawrefpass(bout, bitpos,
+			  vcausal, cblk->flags, cblk->data, termmode,
+			  &pass->nmsedec);
+			break;
+		case JPC_CLNPASS:
+			assert(pass->type == JPC_SEG_MQ);
+			ret = jpc_encclnpass(cblk->mqenc, bitpos, band->orient,
+			  vcausal, segsym, cblk->flags, cblk->data, termmode,
+			  &pass->nmsedec);
+			break;
+		default:
+			assert(0);
+			break;
+		}
+
+		if (pass->type == JPC_SEG_MQ) {
+			if (pass->term) {
+				jpc_mqenc_init(cblk->mqenc);
+			}
+			jpc_mqenc_getstate(cblk->mqenc, &pass->mqencstate);
+			pass->end = jas_stream_tell(cblk->stream);
+			if (tcmpt->cblksty & JPC_COX_RESET) {
+				jpc_mqenc_setctxs(cblk->mqenc, JPC_NUMCTXS, jpc_mqctxs);
+			}
+		} else {
+			if (pass->term) {
+				if (jpc_bitstream_pending(bout)) {
+					jpc_bitstream_outalign(bout, 0x2a);
+				}
+				jpc_bitstream_close(bout);
+				bout = 0;
+				pass->end = jas_stream_tell(cblk->stream);
+			} else {
+				pass->end = jas_stream_tell(cblk->stream) +
+				  jpc_bitstream_pending(bout);
+/* NOTE - This will not work.  need to adjust by # of pending output bytes */
+			}
+		}
+#if 0
+/* XXX - This assertion fails sometimes when various coding modes are used.
+This seems to be harmless, but why does it happen at all? */
+assert(jas_stream_tell(cblk->stream) == jas_stream_getrwcount(cblk->stream));
+#endif
+
+		pass->wmsedec = jpc_fixtodbl(band->rlvl->tcmpt->synweight) *
+		  jpc_fixtodbl(band->rlvl->tcmpt->synweight) *
+		  jpc_fixtodbl(band->synweight) *
+		  jpc_fixtodbl(band->synweight) *
+		  jpc_fixtodbl(band->absstepsize) * jpc_fixtodbl(band->absstepsize) *
+		  ((double) (1 << bitpos)) * ((double)(1 << bitpos)) *
+		  jpc_fixtodbl(pass->nmsedec);
+		pass->cumwmsedec = pass->wmsedec;
+		if (pass != cblk->passes) {
+			pass->cumwmsedec += pass[-1].cumwmsedec;
+		}
+		if (passtype == JPC_CLNPASS) {
+			--bitpos;
+		}
+		++pass;
+	}
+
+#if 0
+dump_passes(cblk->passes, cblk->numpasses, cblk);
+#endif
+
+	n = 0;
+	endpasses = &cblk->passes[cblk->numpasses];
+	for (pass = cblk->passes; pass != endpasses; ++pass) {
+		if (pass->start < n) {
+			pass->start = n;
+		}
+		if (pass->end < n) {
+			pass->end = n;
+		}
+		if (!pass->term) {
+			termpass = pass;
+			while (termpass - pass < cblk->numpasses &&
+			  !termpass->term) {
+				++termpass;
+			}
+			if (pass->type == JPC_SEG_MQ) {
+				t = (pass->mqencstate.lastbyte == 0xff) ? 1 : 0;
+				if (pass->mqencstate.ctreg >= 5) {
+					adjust = 4 + t;
+				} else {
+					adjust = 5 + t;
+				}
+				pass->end += adjust;
+			}
+			if (pass->end > termpass->end) {
+				pass->end = termpass->end;
+			}
+			if ((c = getthebyte(cblk->stream, pass->end - 1)) == EOF) {
+				abort();
+			}
+			if (c == 0xff) {
+				++pass->end;
+			}
+			n = JAS_MAX(n, pass->end);
+		} else {
+			n = JAS_MAX(n, pass->end);
+		}
+	}
+
+#if 0
+dump_passes(cblk->passes, cblk->numpasses, cblk);
+#endif
+
+	if (bout) {
+		jpc_bitstream_close(bout);
+	}
+
+	return 0;
+}
+
+/******************************************************************************\
+* Code for significance pass.
+\******************************************************************************/
+
+#define	sigpass_step(fp, frowstep, dp, bitpos, one, nmsedec, orient, mqenc, vcausalflag) \
+{ \
+	int f; \
+	int v; \
+	f = *(fp); \
+	if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
+		v = (abs(*(dp)) & (one)) ? 1 : 0; \
+		jpc_mqenc_setcurctx(mqenc, JPC_GETZCCTXNO(f, (orient))); \
+		jpc_mqenc_putbit(mqenc, v); \
+		if (v) { \
+			*(nmsedec) += JPC_GETSIGNMSEDEC(abs(*(dp)), (bitpos) + JPC_NUMEXTRABITS); \
+			v = ((*(dp) < 0) ? 1 : 0); \
+			jpc_mqenc_setcurctx(mqenc, JPC_GETSCCTXNO(f)); \
+			jpc_mqenc_putbit(mqenc, v ^ JPC_GETSPB(f)); \
+			JPC_UPDATEFLAGS4(fp, frowstep, v, vcausalflag); \
+			*(fp) |= JPC_SIG; \
+		} \
+		*(fp) |= JPC_VISIT; \
+	} \
+}
+
+static int jpc_encsigpass(jpc_mqenc_t *mqenc, int bitpos, int orient, int vcausalflag,
+  jas_matrix_t *flags, jas_matrix_t *data, int term, long *nmsedec)
+{
+	int i;
+	int j;
+	int one;
+	int vscanlen;
+	int width;
+	int height;
+	int frowstep;
+	int drowstep;
+	int fstripestep;
+	int dstripestep;
+	jpc_fix_t *fstripestart;
+	jpc_fix_t *dstripestart;
+	jpc_fix_t *fp;
+	jpc_fix_t *dp;
+	jpc_fix_t *fvscanstart;
+	jpc_fix_t *dvscanstart;
+	int k;
+
+	*nmsedec = 0;
+	width = jas_matrix_numcols(data);
+	height = jas_matrix_numrows(data);
+	frowstep = jas_matrix_rowstep(flags);
+	drowstep = jas_matrix_rowstep(data);
+	fstripestep = frowstep << 2;
+	dstripestep = drowstep << 2;
+
+	one = 1 << (bitpos + JPC_NUMEXTRABITS);
+
+	fstripestart = jas_matrix_getref(flags, 1, 1);
+	dstripestart = jas_matrix_getref(data, 0, 0);
+	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+	  dstripestart += dstripestep) {
+		fvscanstart = fstripestart;
+		dvscanstart = dstripestart;
+		vscanlen = JAS_MIN(i, 4);
+		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+			fp = fvscanstart;
+			dp = dvscanstart;
+			k = vscanlen;
+
+			sigpass_step(fp, frowstep, dp, bitpos, one,
+			  nmsedec, orient, mqenc, vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			sigpass_step(fp, frowstep, dp, bitpos, one,
+			  nmsedec, orient, mqenc, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			sigpass_step(fp, frowstep, dp, bitpos, one,
+			  nmsedec, orient, mqenc, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			sigpass_step(fp, frowstep, dp, bitpos, one,
+			  nmsedec, orient, mqenc, 0);
+
+		}
+	}
+
+	if (term) {
+		jpc_mqenc_flush(mqenc, term - 1);
+	}
+
+	return jpc_mqenc_error(mqenc) ? (-1) : 0;
+}
+
+#define	rawsigpass_step(fp, frowstep, dp, bitpos, one, nmsedec, out, vcausalflag) \
+{ \
+	jpc_fix_t f = *(fp); \
+	jpc_fix_t v; \
+	if ((f & JPC_OTHSIGMSK) && !(f & (JPC_SIG | JPC_VISIT))) { \
+		v = (abs(*(dp)) & (one)) ? 1 : 0; \
+		if ((jpc_bitstream_putbit((out), v)) == EOF) { \
+			return -1; \
+		} \
+		if (v) { \
+			*(nmsedec) += JPC_GETSIGNMSEDEC(abs(*(dp)), (bitpos) + JPC_NUMEXTRABITS); \
+			v = ((*(dp) < 0) ? 1 : 0); \
+			if (jpc_bitstream_putbit(out, v) == EOF) { \
+				return -1; \
+			} \
+			JPC_UPDATEFLAGS4(fp, frowstep, v, vcausalflag); \
+			*(fp) |= JPC_SIG; \
+		} \
+		*(fp) |= JPC_VISIT; \
+	} \
+}
+
+static int jpc_encrawsigpass(jpc_bitstream_t *out, int bitpos, int vcausalflag, jas_matrix_t *flags,
+  jas_matrix_t *data, int term, long *nmsedec)
+{
+	int i;
+	int j;
+	int k;
+	int one;
+	int vscanlen;
+	int width;
+	int height;
+	int frowstep;
+	int drowstep;
+	int fstripestep;
+	int dstripestep;
+	jpc_fix_t *fstripestart;
+	jpc_fix_t *dstripestart;
+	jpc_fix_t *fp;
+	jpc_fix_t *dp;
+	jpc_fix_t *fvscanstart;
+	jpc_fix_t *dvscanstart;
+
+	*nmsedec = 0;
+	width = jas_matrix_numcols(data);
+	height = jas_matrix_numrows(data);
+	frowstep = jas_matrix_rowstep(flags);
+	drowstep = jas_matrix_rowstep(data);
+	fstripestep = frowstep << 2;
+	dstripestep = drowstep << 2;
+
+	one = 1 << (bitpos + JPC_NUMEXTRABITS);
+
+	fstripestart = jas_matrix_getref(flags, 1, 1);
+	dstripestart = jas_matrix_getref(data, 0, 0);
+	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+	  dstripestart += dstripestep) {
+		fvscanstart = fstripestart;
+		dvscanstart = dstripestart;
+		vscanlen = JAS_MIN(i, 4);
+		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+			fp = fvscanstart;
+			dp = dvscanstart;
+			k = vscanlen;
+
+			rawsigpass_step(fp, frowstep, dp, bitpos, one,
+			  nmsedec, out, vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			rawsigpass_step(fp, frowstep, dp, bitpos, one,
+			  nmsedec, out, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			rawsigpass_step(fp, frowstep, dp, bitpos, one,
+			  nmsedec, out, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+			rawsigpass_step(fp, frowstep, dp, bitpos, one,
+			  nmsedec, out, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+
+		}
+	}
+
+	if (term) {
+		jpc_bitstream_outalign(out, 0x2a);
+	}
+
+	return 0;
+}
+
+/******************************************************************************\
+* Code for refinement pass.
+\******************************************************************************/
+
+#define	refpass_step(fp, dp, bitpos, one, nmsedec, mqenc, vcausalflag) \
+{ \
+	int v; \
+	if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
+		(d) = *(dp); \
+		*(nmsedec) += JPC_GETREFNMSEDEC(abs(d), (bitpos) + JPC_NUMEXTRABITS); \
+		jpc_mqenc_setcurctx((mqenc), JPC_GETMAGCTXNO(*(fp))); \
+		v = (abs(d) & (one)) ? 1 : 0; \
+		jpc_mqenc_putbit((mqenc), v); \
+		*(fp) |= JPC_REFINE; \
+	} \
+}
+
+static int jpc_encrefpass(jpc_mqenc_t *mqenc, int bitpos, int vcausalflag, jas_matrix_t *flags, jas_matrix_t *data,
+  int term, long *nmsedec)
+{
+	int i;
+	int j;
+	int one;
+	int vscanlen;
+	int d;
+	int width;
+	int height;
+	int frowstep;
+	int drowstep;
+	int fstripestep;
+	int dstripestep;
+	jpc_fix_t *fstripestart;
+	jpc_fix_t *dstripestart;
+	jpc_fix_t *fvscanstart;
+	jpc_fix_t *dvscanstart;
+	jpc_fix_t *dp;
+	jpc_fix_t *fp;
+int k;
+
+	*nmsedec = 0;
+	width = jas_matrix_numcols(data);
+	height = jas_matrix_numrows(data);
+	frowstep = jas_matrix_rowstep(flags);
+	drowstep = jas_matrix_rowstep(data);
+	fstripestep = frowstep << 2;
+	dstripestep = drowstep << 2;
+
+	one = 1 << (bitpos + JPC_NUMEXTRABITS);
+
+	fstripestart = jas_matrix_getref(flags, 1, 1);
+	dstripestart = jas_matrix_getref(data, 0, 0);
+	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+	  dstripestart += dstripestep) {
+		fvscanstart = fstripestart;
+		dvscanstart = dstripestart;
+		vscanlen = JAS_MIN(i, 4);
+		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+			fp = fvscanstart;
+			dp = dvscanstart;
+			k = vscanlen;
+
+			refpass_step(fp, dp, bitpos, one, nmsedec,
+			  mqenc, vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			refpass_step(fp, dp, bitpos, one, nmsedec,
+			  mqenc, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			refpass_step(fp, dp, bitpos, one, nmsedec,
+			  mqenc, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			refpass_step(fp, dp, bitpos, one, nmsedec,
+			  mqenc, 0);
+
+		}
+	}
+
+	if (term) {
+		jpc_mqenc_flush(mqenc, term - 1);
+	}
+
+	return jpc_mqenc_error(mqenc) ? (-1) : 0;
+}
+
+#define	rawrefpass_step(fp, dp, bitpos, one, nmsedec, out, vcausalflag) \
+{ \
+	jpc_fix_t d; \
+	jpc_fix_t v; \
+	if (((*(fp)) & (JPC_SIG | JPC_VISIT)) == JPC_SIG) { \
+		d = *(dp); \
+		*(nmsedec) += JPC_GETREFNMSEDEC(abs(d), (bitpos) + JPC_NUMEXTRABITS); \
+		v = (abs(d) & (one)) ? 1 : 0; \
+		if (jpc_bitstream_putbit((out), v) == EOF) { \
+			return -1; \
+		} \
+		*(fp) |= JPC_REFINE; \
+	} \
+}
+
+static int jpc_encrawrefpass(jpc_bitstream_t *out, int bitpos, int vcausalflag, jas_matrix_t *flags,
+  jas_matrix_t *data, int term, long *nmsedec)
+{
+	int i;
+	int j;
+	int k;
+	int one;
+	int vscanlen;
+	int width;
+	int height;
+	int frowstep;
+	int drowstep;
+	int fstripestep;
+	int dstripestep;
+	jpc_fix_t *fstripestart;
+	jpc_fix_t *dstripestart;
+	jpc_fix_t *fvscanstart;
+	jpc_fix_t *dvscanstart;
+	jpc_fix_t *dp;
+	jpc_fix_t *fp;
+
+	*nmsedec = 0;
+	width = jas_matrix_numcols(data);
+	height = jas_matrix_numrows(data);
+	frowstep = jas_matrix_rowstep(flags);
+	drowstep = jas_matrix_rowstep(data);
+	fstripestep = frowstep << 2;
+	dstripestep = drowstep << 2;
+
+	one = 1 << (bitpos + JPC_NUMEXTRABITS);
+
+	fstripestart = jas_matrix_getref(flags, 1, 1);
+	dstripestart = jas_matrix_getref(data, 0, 0);
+	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+	  dstripestart += dstripestep) {
+		fvscanstart = fstripestart;
+		dvscanstart = dstripestart;
+		vscanlen = JAS_MIN(i, 4);
+		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+			fp = fvscanstart;
+			dp = dvscanstart;
+			k = vscanlen;
+
+			rawrefpass_step(fp, dp, bitpos, one, nmsedec,
+			  out, vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			rawrefpass_step(fp, dp, bitpos, one, nmsedec,
+			  out, vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			rawrefpass_step(fp, dp, bitpos, one, nmsedec,
+			  out, vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			rawrefpass_step(fp, dp, bitpos, one, nmsedec,
+			  out, vcausalflag);
+
+		}
+	}
+
+	if (term) {
+		jpc_bitstream_outalign(out, 0x2a);
+	}
+
+	return 0;
+}
+
+/******************************************************************************\
+* Code for cleanup pass.
+\******************************************************************************/
+
+#define	clnpass_step(fp, frowstep, dp, bitpos, one, orient, nmsedec, mqenc, label1, label2, vcausalflag) \
+{ \
+	int f; \
+	int v; \
+label1 \
+	f = *(fp); \
+	if (!(f & (JPC_SIG | JPC_VISIT))) { \
+		jpc_mqenc_setcurctx(mqenc, JPC_GETZCCTXNO(f, (orient))); \
+		v = (abs(*(dp)) & (one)) ? 1 : 0; \
+		jpc_mqenc_putbit((mqenc), v); \
+		if (v) { \
+label2 \
+			f = *(fp); \
+			/* Coefficient is significant. */ \
+			*(nmsedec) += JPC_GETSIGNMSEDEC(abs(*(dp)), (bitpos) + JPC_NUMEXTRABITS); \
+			jpc_mqenc_setcurctx((mqenc), JPC_GETSCCTXNO(f)); \
+			v = ((*(dp) < 0) ? 1 : 0); \
+			jpc_mqenc_putbit((mqenc), v ^ JPC_GETSPB(f)); \
+			JPC_UPDATEFLAGS4((fp), (frowstep), v, vcausalflag); \
+			*(fp) |= JPC_SIG; \
+		} \
+	} \
+	*(fp) &= ~JPC_VISIT; \
+}
+
+static int jpc_encclnpass(jpc_mqenc_t *mqenc, int bitpos, int orient, int vcausalflag, int segsymflag, jas_matrix_t *flags,
+  jas_matrix_t *data, int term, long *nmsedec)
+{
+	int i;
+	int j;
+	int k;
+	int vscanlen;
+	int v;
+	int runlen;
+	jpc_fix_t *fp;
+	int width;
+	int height;
+	jpc_fix_t *dp;
+	int one;
+	int frowstep;
+	int drowstep;
+	int fstripestep;
+	int dstripestep;
+	jpc_fix_t *fstripestart;
+	jpc_fix_t *dstripestart;
+	jpc_fix_t *fvscanstart;
+	jpc_fix_t *dvscanstart;
+
+	*nmsedec = 0;
+	width = jas_matrix_numcols(data);
+	height = jas_matrix_numrows(data);
+	frowstep = jas_matrix_rowstep(flags);
+	drowstep = jas_matrix_rowstep(data);
+	fstripestep = frowstep << 2;
+	dstripestep = drowstep << 2;
+
+	one = 1 << (bitpos + JPC_NUMEXTRABITS);
+
+	fstripestart = jas_matrix_getref(flags, 1, 1);
+	dstripestart = jas_matrix_getref(data, 0, 0);
+	for (i = height; i > 0; i -= 4, fstripestart += fstripestep,
+	  dstripestart += dstripestep) {
+		fvscanstart = fstripestart;
+		dvscanstart = dstripestart;
+		vscanlen = JAS_MIN(i, 4);
+		for (j = width; j > 0; --j, ++fvscanstart, ++dvscanstart) {
+
+			fp = fvscanstart;
+			if (vscanlen >= 4 && !((*fp) & (JPC_SIG | JPC_VISIT |
+			  JPC_OTHSIGMSK)) && (fp += frowstep, !((*fp) & (JPC_SIG |
+			  JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep, !((*fp) &
+			  (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK))) && (fp += frowstep,
+			  !((*fp) & (JPC_SIG | JPC_VISIT | JPC_OTHSIGMSK)))) {
+				dp = dvscanstart;
+				for (k = 0; k < vscanlen; ++k) {
+					v = (abs(*dp) & one) ? 1 : 0;
+					if (v) {
+						break;
+					}
+					dp += drowstep;
+				}
+				runlen = k;
+				if (runlen >= 4) {
+					jpc_mqenc_setcurctx(mqenc, JPC_AGGCTXNO);
+					jpc_mqenc_putbit(mqenc, 0);
+					continue;
+				}
+				jpc_mqenc_setcurctx(mqenc, JPC_AGGCTXNO);
+				jpc_mqenc_putbit(mqenc, 1);
+				jpc_mqenc_setcurctx(mqenc, JPC_UCTXNO);
+				jpc_mqenc_putbit(mqenc, runlen >> 1);
+				jpc_mqenc_putbit(mqenc, runlen & 1);
+				fp = fvscanstart + frowstep * runlen;
+				dp = dvscanstart + drowstep * runlen;
+				k = vscanlen - runlen;
+				switch (runlen) {
+				case 0:
+					goto clnpass_partial0;
+					break;
+				case 1:
+					goto clnpass_partial1;
+					break;
+				case 2:
+					goto clnpass_partial2;
+					break;
+				case 3:
+					goto clnpass_partial3;
+					break;
+				}
+			} else {
+				runlen = 0;
+				fp = fvscanstart;
+				dp = dvscanstart;
+				k = vscanlen;
+				goto clnpass_full0;
+			}
+			clnpass_step(fp, frowstep, dp, bitpos, one,
+			  orient, nmsedec, mqenc, clnpass_full0:, clnpass_partial0:, vcausalflag);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			clnpass_step(fp, frowstep, dp, bitpos, one,
+				orient, nmsedec, mqenc, ;, clnpass_partial1:, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			clnpass_step(fp, frowstep, dp, bitpos, one,
+				orient, nmsedec, mqenc, ;, clnpass_partial2:, 0);
+			if (--k <= 0) {
+				continue;
+			}
+			fp += frowstep;
+			dp += drowstep;
+			clnpass_step(fp, frowstep, dp, bitpos, one,
+				orient, nmsedec, mqenc, ;, clnpass_partial3:, 0);
+		}
+	}
+
+	if (segsymflag) {
+		jpc_mqenc_setcurctx(mqenc, JPC_UCTXNO);
+		jpc_mqenc_putbit(mqenc, 1);
+		jpc_mqenc_putbit(mqenc, 0);
+		jpc_mqenc_putbit(mqenc, 1);
+		jpc_mqenc_putbit(mqenc, 0);
+	}
+
+	if (term) {
+		jpc_mqenc_flush(mqenc, term - 1);
+	}
+
+	return jpc_mqenc_error(mqenc) ? (-1) : 0;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.h b/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.h
new file mode 100644
index 00000000..9ce5ed27
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.h
@@ -0,0 +1,142 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tier 1 Encoder
+ *
+ * $Id$
+ */
+
+#ifndef JPC_T1ENC_H
+#define JPC_T1ENC_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_seq.h"
+
+#include "jpc_enc.h"
+#include "jpc_t1cod.h"
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Encode all of the code blocks. */
+int jpc_enc_enccblks(jpc_enc_t *enc);
+
+/* Encode a single code block. */
+int jpc_enc_enccblk(jpc_enc_t *enc, jas_stream_t *out, jpc_enc_tcmpt_t *comp,
+  jpc_enc_band_t *band, jpc_enc_cblk_t *cblk);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.c b/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.c
new file mode 100644
index 00000000..a9ca0dc1
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.c
@@ -0,0 +1,733 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tier-2 Coding Library
+ *
+ * $Id$
+ */
+
+#include "jasper/jas_math.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_math.h"
+
+#include "jpc_cs.h"
+#include "jpc_t2cod.h"
+#include "jpc_math.h"
+
+static int jpc_pi_nextlrcp(jpc_pi_t *pi);
+static int jpc_pi_nextrlcp(jpc_pi_t *pi);
+static int jpc_pi_nextrpcl(jpc_pi_t *pi);
+static int jpc_pi_nextpcrl(jpc_pi_t *pi);
+static int jpc_pi_nextcprl(jpc_pi_t *pi);
+
+int jpc_pi_next(jpc_pi_t *pi)
+{
+	jpc_pchg_t *pchg;
+	int ret;
+
+
+	for (;;) {
+
+		pi->valid = false;
+
+		if (!pi->pchg) {
+			++pi->pchgno;
+			pi->compno = 0;
+			pi->rlvlno = 0;
+			pi->prcno = 0;
+			pi->lyrno = 0;
+			pi->prgvolfirst = true;
+			if (pi->pchgno < jpc_pchglist_numpchgs(pi->pchglist)) {
+				pi->pchg = jpc_pchglist_get(pi->pchglist, pi->pchgno);
+			} else if (pi->pchgno == jpc_pchglist_numpchgs(pi->pchglist)) {
+				pi->pchg = &pi->defaultpchg;
+			} else {
+				return 1;
+			}
+		}
+
+		pchg = pi->pchg;
+		switch (pchg->prgord) {
+		case JPC_COD_LRCPPRG:
+			ret = jpc_pi_nextlrcp(pi);
+			break;
+		case JPC_COD_RLCPPRG:
+			ret = jpc_pi_nextrlcp(pi);
+			break;
+		case JPC_COD_RPCLPRG:
+			ret = jpc_pi_nextrpcl(pi);
+			break;
+		case JPC_COD_PCRLPRG:
+			ret = jpc_pi_nextpcrl(pi);
+			break;
+		case JPC_COD_CPRLPRG:
+			ret = jpc_pi_nextcprl(pi);
+			break;
+		default:
+			ret = -1;
+			break;
+		}
+		if (!ret) {
+			pi->valid = true;
+			++pi->pktno;
+			return 0;
+		}
+		pi->pchg = 0;
+	}
+}
+
+static int jpc_pi_nextlrcp(register jpc_pi_t *pi)
+{
+	jpc_pchg_t *pchg;
+	int *prclyrno;
+
+	pchg = pi->pchg;
+	if (!pi->prgvolfirst) {
+		prclyrno = &pi->pirlvl->prclyrnos[pi->prcno];
+		goto skip;
+	} else {
+		pi->prgvolfirst = false;
+	}
+
+	for (pi->lyrno = 0; pi->lyrno < pi->numlyrs && pi->lyrno <
+	  pchg->lyrnoend; ++pi->lyrno) {
+		for (pi->rlvlno = pchg->rlvlnostart; pi->rlvlno < pi->maxrlvls &&
+		  pi->rlvlno < pchg->rlvlnoend; ++pi->rlvlno) {
+			for (pi->compno = pchg->compnostart, pi->picomp =
+			  &pi->picomps[pi->compno]; pi->compno < pi->numcomps
+			  && pi->compno < pchg->compnoend; ++pi->compno,
+			  ++pi->picomp) {
+				if (pi->rlvlno >= pi->picomp->numrlvls) {
+					continue;
+				}
+				pi->pirlvl = &pi->picomp->pirlvls[pi->rlvlno];
+				for (pi->prcno = 0, prclyrno =
+				  pi->pirlvl->prclyrnos; pi->prcno <
+				  pi->pirlvl->numprcs; ++pi->prcno,
+				  ++prclyrno) {
+					if (pi->lyrno >= *prclyrno) {
+						*prclyrno = pi->lyrno;
+						++(*prclyrno);
+						return 0;
+					}
+skip:
+					;
+				}
+			}
+		}
+	}
+	return 1;
+}
+
+static int jpc_pi_nextrlcp(register jpc_pi_t *pi)
+{
+	jpc_pchg_t *pchg;
+	int *prclyrno;
+
+	pchg = pi->pchg;
+	if (!pi->prgvolfirst) {
+		assert(pi->prcno < pi->pirlvl->numprcs);
+		prclyrno = &pi->pirlvl->prclyrnos[pi->prcno];
+		goto skip;
+	} else {
+		pi->prgvolfirst = 0;
+	}
+
+	for (pi->rlvlno = pchg->rlvlnostart; pi->rlvlno < pi->maxrlvls &&
+	  pi->rlvlno < pchg->rlvlnoend; ++pi->rlvlno) {
+		for (pi->lyrno = 0; pi->lyrno < pi->numlyrs && pi->lyrno <
+		  pchg->lyrnoend; ++pi->lyrno) {
+			for (pi->compno = pchg->compnostart, pi->picomp =
+			  &pi->picomps[pi->compno]; pi->compno < pi->numcomps &&
+			  pi->compno < pchg->compnoend; ++pi->compno, ++pi->picomp) {
+				if (pi->rlvlno >= pi->picomp->numrlvls) {
+					continue;
+				}
+				pi->pirlvl = &pi->picomp->pirlvls[pi->rlvlno];
+				for (pi->prcno = 0, prclyrno = pi->pirlvl->prclyrnos;
+				  pi->prcno < pi->pirlvl->numprcs; ++pi->prcno, ++prclyrno) {
+					if (pi->lyrno >= *prclyrno) {
+						*prclyrno = pi->lyrno;
+						++(*prclyrno);
+						return 0;
+					}
+skip:
+					;
+				}
+			}
+		}
+	}
+	return 1;
+}
+
+static int jpc_pi_nextrpcl(register jpc_pi_t *pi)
+{
+	int rlvlno;
+	jpc_pirlvl_t *pirlvl;
+	jpc_pchg_t *pchg;
+	int prchind;
+	int prcvind;
+	int *prclyrno;
+	int compno;
+	jpc_picomp_t *picomp;
+	int xstep;
+	int ystep;
+	uint_fast32_t r;
+	uint_fast32_t rpx;
+	uint_fast32_t rpy;
+	uint_fast32_t trx0;
+	uint_fast32_t try0;
+
+	pchg = pi->pchg;
+	if (!pi->prgvolfirst) {
+		goto skip;
+	} else {
+		pi->xstep = 0;
+		pi->ystep = 0;
+		for (compno = 0, picomp = pi->picomps; compno < pi->numcomps;
+		  ++compno, ++picomp) {
+			for (rlvlno = 0, pirlvl = picomp->pirlvls; rlvlno <
+			  picomp->numrlvls; ++rlvlno, ++pirlvl) {
+				xstep = picomp->hsamp * (1 << (pirlvl->prcwidthexpn +
+				  picomp->numrlvls - rlvlno - 1));
+				ystep = picomp->vsamp * (1 << (pirlvl->prcheightexpn +
+				  picomp->numrlvls - rlvlno - 1));
+				pi->xstep = (!pi->xstep) ? xstep : JAS_MIN(pi->xstep, xstep);
+				pi->ystep = (!pi->ystep) ? ystep : JAS_MIN(pi->ystep, ystep);
+			}
+		}
+		pi->prgvolfirst = 0;
+	}
+
+	for (pi->rlvlno = pchg->rlvlnostart; pi->rlvlno < pchg->rlvlnoend &&
+	  pi->rlvlno < pi->maxrlvls; ++pi->rlvlno) {
+		for (pi->y = pi->ystart; pi->y < pi->yend; pi->y +=
+		  pi->ystep - (pi->y % pi->ystep)) {
+			for (pi->x = pi->xstart; pi->x < pi->xend; pi->x +=
+			  pi->xstep - (pi->x % pi->xstep)) {
+				for (pi->compno = pchg->compnostart,
+				  pi->picomp = &pi->picomps[pi->compno];
+				  pi->compno < pchg->compnoend && pi->compno <
+				  pi->numcomps; ++pi->compno, ++pi->picomp) {
+					if (pi->rlvlno >= pi->picomp->numrlvls) {
+						continue;
+					}
+					pi->pirlvl = &pi->picomp->pirlvls[pi->rlvlno];
+					if (pi->pirlvl->numprcs == 0) {
+						continue;
+					}
+					r = pi->picomp->numrlvls - 1 - pi->rlvlno;
+					rpx = r + pi->pirlvl->prcwidthexpn;
+					rpy = r + pi->pirlvl->prcheightexpn;
+					trx0 = JPC_CEILDIV(pi->xstart, pi->picomp->hsamp << r);
+					try0 = JPC_CEILDIV(pi->ystart, pi->picomp->vsamp << r);
+					if (((pi->x == pi->xstart && ((trx0 << r) % (1 << rpx)))
+					  || !(pi->x % (1 << rpx))) &&
+					  ((pi->y == pi->ystart && ((try0 << r) % (1 << rpy)))
+					  || !(pi->y % (1 << rpy)))) {
+						prchind = JPC_FLOORDIVPOW2(JPC_CEILDIV(pi->x, pi->picomp->hsamp
+						  << r), pi->pirlvl->prcwidthexpn) - JPC_FLOORDIVPOW2(trx0,
+						  pi->pirlvl->prcwidthexpn);
+						prcvind = JPC_FLOORDIVPOW2(JPC_CEILDIV(pi->y, pi->picomp->vsamp
+						  << r), pi->pirlvl->prcheightexpn) - JPC_FLOORDIVPOW2(try0,
+						  pi->pirlvl->prcheightexpn);
+						pi->prcno = prcvind * pi->pirlvl->numhprcs + prchind;
+
+						assert(pi->prcno < pi->pirlvl->numprcs);
+						for (pi->lyrno = 0; pi->lyrno <
+						  pi->numlyrs && pi->lyrno < pchg->lyrnoend; ++pi->lyrno) {
+							prclyrno = &pi->pirlvl->prclyrnos[pi->prcno];
+							if (pi->lyrno >= *prclyrno) {
+								++(*prclyrno);
+								return 0;
+							}
+skip:
+							;
+						}
+					}
+				}
+			}
+		}
+	}
+	return 1;
+}
+
+static int jpc_pi_nextpcrl(register jpc_pi_t *pi)
+{
+	int rlvlno;
+	jpc_pirlvl_t *pirlvl;
+	jpc_pchg_t *pchg;
+	int prchind;
+	int prcvind;
+	int *prclyrno;
+	int compno;
+	jpc_picomp_t *picomp;
+	int xstep;
+	int ystep;
+	uint_fast32_t trx0;
+	uint_fast32_t try0;
+	uint_fast32_t r;
+	uint_fast32_t rpx;
+	uint_fast32_t rpy;
+
+	pchg = pi->pchg;
+	if (!pi->prgvolfirst) {
+		goto skip;
+	} else {
+		pi->xstep = 0;
+		pi->ystep = 0;
+		for (compno = 0, picomp = pi->picomps; compno < pi->numcomps;
+		  ++compno, ++picomp) {
+			for (rlvlno = 0, pirlvl = picomp->pirlvls; rlvlno <
+			  picomp->numrlvls; ++rlvlno, ++pirlvl) {
+				xstep = picomp->hsamp * (1 <<
+				  (pirlvl->prcwidthexpn + picomp->numrlvls -
+				  rlvlno - 1));
+				ystep = picomp->vsamp * (1 <<
+				  (pirlvl->prcheightexpn + picomp->numrlvls -
+				  rlvlno - 1));
+				pi->xstep = (!pi->xstep) ? xstep :
+				  JAS_MIN(pi->xstep, xstep);
+				pi->ystep = (!pi->ystep) ? ystep :
+				  JAS_MIN(pi->ystep, ystep);
+			}
+		}
+		pi->prgvolfirst = 0;
+	}
+
+	for (pi->y = pi->ystart; pi->y < pi->yend; pi->y += pi->ystep -
+	  (pi->y % pi->ystep)) {
+		for (pi->x = pi->xstart; pi->x < pi->xend; pi->x += pi->xstep -
+		  (pi->x % pi->xstep)) {
+			for (pi->compno = pchg->compnostart, pi->picomp =
+			  &pi->picomps[pi->compno]; pi->compno < pi->numcomps
+			  && pi->compno < pchg->compnoend; ++pi->compno,
+			  ++pi->picomp) {
+				for (pi->rlvlno = pchg->rlvlnostart,
+				  pi->pirlvl = &pi->picomp->pirlvls[pi->rlvlno];
+				  pi->rlvlno < pi->picomp->numrlvls &&
+				  pi->rlvlno < pchg->rlvlnoend; ++pi->rlvlno,
+				  ++pi->pirlvl) {
+					if (pi->pirlvl->numprcs == 0) {
+						continue;
+					}
+					r = pi->picomp->numrlvls - 1 - pi->rlvlno;
+					trx0 = JPC_CEILDIV(pi->xstart, pi->picomp->hsamp << r);
+					try0 = JPC_CEILDIV(pi->ystart, pi->picomp->vsamp << r);
+					rpx = r + pi->pirlvl->prcwidthexpn;
+					rpy = r + pi->pirlvl->prcheightexpn;
+					if (((pi->x == pi->xstart && ((trx0 << r) % (1 << rpx))) ||
+					  !(pi->x % (pi->picomp->hsamp << rpx))) &&
+					  ((pi->y == pi->ystart && ((try0 << r) % (1 << rpy))) ||
+					  !(pi->y % (pi->picomp->vsamp << rpy)))) {
+						prchind = JPC_FLOORDIVPOW2(JPC_CEILDIV(pi->x, pi->picomp->hsamp
+						  << r), pi->pirlvl->prcwidthexpn) - JPC_FLOORDIVPOW2(trx0,
+						  pi->pirlvl->prcwidthexpn);
+						prcvind = JPC_FLOORDIVPOW2(JPC_CEILDIV(pi->y, pi->picomp->vsamp
+						  << r), pi->pirlvl->prcheightexpn) - JPC_FLOORDIVPOW2(try0,
+						  pi->pirlvl->prcheightexpn);
+						pi->prcno = prcvind * pi->pirlvl->numhprcs + prchind;
+						assert(pi->prcno < pi->pirlvl->numprcs);
+						for (pi->lyrno = 0; pi->lyrno < pi->numlyrs &&
+						  pi->lyrno < pchg->lyrnoend; ++pi->lyrno) {
+							prclyrno = &pi->pirlvl->prclyrnos[pi->prcno];
+							if (pi->lyrno >= *prclyrno) {
+								++(*prclyrno);
+								return 0;
+							}
+skip:
+							;
+						}
+					}
+				}
+			}
+		}
+	}
+	return 1;
+}
+
+static int jpc_pi_nextcprl(register jpc_pi_t *pi)
+{
+	int rlvlno;
+	jpc_pirlvl_t *pirlvl;
+	jpc_pchg_t *pchg;
+	int prchind;
+	int prcvind;
+	int *prclyrno;
+	uint_fast32_t trx0;
+	uint_fast32_t try0;
+	uint_fast32_t r;
+	uint_fast32_t rpx;
+	uint_fast32_t rpy;
+
+	pchg = pi->pchg;
+	if (!pi->prgvolfirst) {
+		goto skip;
+	} else {
+		pi->prgvolfirst = 0;
+	}
+
+	for (pi->compno = pchg->compnostart, pi->picomp =
+	  &pi->picomps[pi->compno]; pi->compno < pchg->compnoend; ++pi->compno,
+	  ++pi->picomp) {
+		pirlvl = pi->picomp->pirlvls;
+		pi->xstep = pi->picomp->hsamp * (1 << (pirlvl->prcwidthexpn +
+		  pi->picomp->numrlvls - 1));
+		pi->ystep = pi->picomp->vsamp * (1 << (pirlvl->prcheightexpn +
+		  pi->picomp->numrlvls - 1));
+		for (rlvlno = 1, pirlvl = &pi->picomp->pirlvls[1];
+		  rlvlno < pi->picomp->numrlvls; ++rlvlno, ++pirlvl) {
+			pi->xstep = JAS_MIN(pi->xstep, pi->picomp->hsamp * (1 <<
+			  (pirlvl->prcwidthexpn + pi->picomp->numrlvls -
+			  rlvlno - 1)));
+			pi->ystep = JAS_MIN(pi->ystep, pi->picomp->vsamp * (1 <<
+			  (pirlvl->prcheightexpn + pi->picomp->numrlvls -
+			  rlvlno - 1)));
+		}
+		for (pi->y = pi->ystart; pi->y < pi->yend;
+		  pi->y += pi->ystep - (pi->y % pi->ystep)) {
+			for (pi->x = pi->xstart; pi->x < pi->xend;
+			  pi->x += pi->xstep - (pi->x % pi->xstep)) {
+				for (pi->rlvlno = pchg->rlvlnostart,
+				  pi->pirlvl = &pi->picomp->pirlvls[pi->rlvlno];
+				  pi->rlvlno < pi->picomp->numrlvls && pi->rlvlno <
+				  pchg->rlvlnoend; ++pi->rlvlno, ++pi->pirlvl) {
+					if (pi->pirlvl->numprcs == 0) {
+						continue;
+					}
+					r = pi->picomp->numrlvls - 1 - pi->rlvlno;
+					trx0 = JPC_CEILDIV(pi->xstart, pi->picomp->hsamp << r);
+					try0 = JPC_CEILDIV(pi->ystart, pi->picomp->vsamp << r);
+					rpx = r + pi->pirlvl->prcwidthexpn;
+					rpy = r + pi->pirlvl->prcheightexpn;
+					if (((pi->x == pi->xstart && ((trx0 << r) % (1 << rpx))) ||
+					  !(pi->x % (pi->picomp->hsamp << rpx))) &&
+					  ((pi->y == pi->ystart && ((try0 << r) % (1 << rpy))) ||
+					  !(pi->y % (pi->picomp->vsamp << rpy)))) {
+						prchind = JPC_FLOORDIVPOW2(JPC_CEILDIV(pi->x, pi->picomp->hsamp
+						  << r), pi->pirlvl->prcwidthexpn) - JPC_FLOORDIVPOW2(trx0,
+						  pi->pirlvl->prcwidthexpn);
+						prcvind = JPC_FLOORDIVPOW2(JPC_CEILDIV(pi->y, pi->picomp->vsamp
+						  << r), pi->pirlvl->prcheightexpn) - JPC_FLOORDIVPOW2(try0,
+						  pi->pirlvl->prcheightexpn);
+						pi->prcno = prcvind *
+						  pi->pirlvl->numhprcs +
+						  prchind;
+						assert(pi->prcno <
+						  pi->pirlvl->numprcs);
+						for (pi->lyrno = 0; pi->lyrno <
+						  pi->numlyrs && pi->lyrno < pchg->lyrnoend; ++pi->lyrno) {
+							prclyrno = &pi->pirlvl->prclyrnos[pi->prcno];
+							if (pi->lyrno >= *prclyrno) {
+								++(*prclyrno);
+								return 0;
+							}
+skip:
+							;
+						}
+					}
+				}
+			}
+		}
+	}
+	return 1;
+}
+
+static void pirlvl_destroy(jpc_pirlvl_t *rlvl)
+{
+	if (rlvl->prclyrnos) {
+		jas_free(rlvl->prclyrnos);
+	}
+}
+
+static void jpc_picomp_destroy(jpc_picomp_t *picomp)
+{
+	int rlvlno;
+	jpc_pirlvl_t *pirlvl;
+	if (picomp->pirlvls) {
+		for (rlvlno = 0, pirlvl = picomp->pirlvls; rlvlno <
+		  picomp->numrlvls; ++rlvlno, ++pirlvl) {
+			pirlvl_destroy(pirlvl);
+		}
+		jas_free(picomp->pirlvls);
+	}
+}
+
+void jpc_pi_destroy(jpc_pi_t *pi)
+{
+	jpc_picomp_t *picomp;
+	int compno;
+	if (pi->picomps) {
+		for (compno = 0, picomp = pi->picomps; compno < pi->numcomps;
+		  ++compno, ++picomp) {
+			jpc_picomp_destroy(picomp);
+		}
+		jas_free(pi->picomps);
+	}
+	if (pi->pchglist) {
+		jpc_pchglist_destroy(pi->pchglist);
+	}
+	jas_free(pi);
+}
+
+jpc_pi_t *jpc_pi_create0(void)
+{
+	jpc_pi_t *pi;
+	if (!(pi = jas_malloc(sizeof(jpc_pi_t)))) {
+		return 0;
+	}
+	pi->picomps = 0;
+	pi->pchgno = 0;
+	if (!(pi->pchglist = jpc_pchglist_create())) {
+		jas_free(pi);
+		return 0;
+	}
+	return pi;
+}
+
+int jpc_pi_addpchg(jpc_pi_t *pi, jpc_pocpchg_t *pchg)
+{
+	return jpc_pchglist_insert(pi->pchglist, -1, pchg);
+}
+
+jpc_pchglist_t *jpc_pchglist_create(void)
+{
+	jpc_pchglist_t *pchglist;
+	if (!(pchglist = jas_malloc(sizeof(jpc_pchglist_t)))) {
+		return 0;
+	}
+	pchglist->numpchgs = 0;
+	pchglist->maxpchgs = 0;
+	pchglist->pchgs = 0;
+	return pchglist;
+}
+
+int jpc_pchglist_insert(jpc_pchglist_t *pchglist, int pchgno, jpc_pchg_t *pchg)
+{
+	int i;
+	int newmaxpchgs;
+	jpc_pchg_t **newpchgs;
+	if (pchgno < 0) {
+		pchgno = pchglist->numpchgs;
+	}
+	if (pchglist->numpchgs >= pchglist->maxpchgs) {
+		newmaxpchgs = pchglist->maxpchgs + 128;
+		if (!(newpchgs = jas_realloc(pchglist->pchgs, newmaxpchgs * sizeof(jpc_pchg_t *)))) {
+			return -1;
+		}
+		pchglist->maxpchgs = newmaxpchgs;
+		pchglist->pchgs = newpchgs;
+	}
+	for (i = pchglist->numpchgs; i > pchgno; --i) {
+		pchglist->pchgs[i] = pchglist->pchgs[i - 1];
+	}
+	pchglist->pchgs[pchgno] = pchg;
+	++pchglist->numpchgs;
+	return 0;
+}
+
+jpc_pchg_t *jpc_pchglist_remove(jpc_pchglist_t *pchglist, int pchgno)
+{
+	int i;
+	jpc_pchg_t *pchg;
+	assert(pchgno < pchglist->numpchgs);
+	pchg = pchglist->pchgs[pchgno];
+	for (i = pchgno + 1; i < pchglist->numpchgs; ++i) {
+		pchglist->pchgs[i - 1] = pchglist->pchgs[i];
+	}
+	--pchglist->numpchgs;
+	return pchg;
+}
+
+jpc_pchg_t *jpc_pchg_copy(jpc_pchg_t *pchg)
+{
+	jpc_pchg_t *newpchg;
+	if (!(newpchg = jas_malloc(sizeof(jpc_pchg_t)))) {
+		return 0;
+	}
+	*newpchg = *pchg;
+	return newpchg;
+}
+
+jpc_pchglist_t *jpc_pchglist_copy(jpc_pchglist_t *pchglist)
+{
+	jpc_pchglist_t *newpchglist;
+	jpc_pchg_t *newpchg;
+	int pchgno;
+	if (!(newpchglist = jpc_pchglist_create())) {
+		return 0;
+	}
+	for (pchgno = 0; pchgno < pchglist->numpchgs; ++pchgno) {
+		if (!(newpchg = jpc_pchg_copy(pchglist->pchgs[pchgno])) ||
+		  jpc_pchglist_insert(newpchglist, -1, newpchg)) {
+			jpc_pchglist_destroy(newpchglist);
+			return 0;
+		}
+	}
+	return newpchglist;
+}
+
+void jpc_pchglist_destroy(jpc_pchglist_t *pchglist)
+{
+	int pchgno;
+	if (pchglist->pchgs) {
+		for (pchgno = 0; pchgno < pchglist->numpchgs; ++pchgno) {
+			jpc_pchg_destroy(pchglist->pchgs[pchgno]);
+		}
+		jas_free(pchglist->pchgs);
+	}
+	jas_free(pchglist);
+}
+
+void jpc_pchg_destroy(jpc_pchg_t *pchg)
+{
+	jas_free(pchg);
+}
+
+jpc_pchg_t *jpc_pchglist_get(jpc_pchglist_t *pchglist, int pchgno)
+{
+	return pchglist->pchgs[pchgno];
+}
+
+int jpc_pchglist_numpchgs(jpc_pchglist_t *pchglist)
+{
+	return pchglist->numpchgs;
+}
+
+int jpc_pi_init(jpc_pi_t *pi)
+{
+	int compno;
+	int rlvlno;
+	int prcno;
+	jpc_picomp_t *picomp;
+	jpc_pirlvl_t *pirlvl;
+	int *prclyrno;
+
+	pi->prgvolfirst = 0;
+	pi->valid = 0;
+	pi->pktno = -1;
+	pi->pchgno = -1;
+	pi->pchg = 0;
+
+	for (compno = 0, picomp = pi->picomps; compno < pi->numcomps;
+	  ++compno, ++picomp) {
+		for (rlvlno = 0, pirlvl = picomp->pirlvls; rlvlno <
+		  picomp->numrlvls; ++rlvlno, ++pirlvl) {
+			for (prcno = 0, prclyrno = pirlvl->prclyrnos;
+			  prcno < pirlvl->numprcs; ++prcno, ++prclyrno) {
+				*prclyrno = 0;
+			}
+		}
+	}
+	return 0;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h b/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h
new file mode 100644
index 00000000..05f41b9e
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.h
@@ -0,0 +1,348 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tier-2 Coding Library
+ *
+ * $Id$
+ */
+
+#ifndef JPC_T2COD_H
+#define	JPC_T2COD_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jpc_cs.h"
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+/* Progression change list. */
+
+typedef struct {
+
+	/* The number of progression changes. */
+	int numpchgs;
+
+	/* The maximum number of progression changes that can be accomodated
+	  without growing the progression change array. */
+	int maxpchgs;
+
+	/* The progression changes. */
+	jpc_pchg_t **pchgs;
+
+} jpc_pchglist_t;
+
+/* Packet iterator per-resolution-level information. */
+
+typedef struct {
+
+	/* The number of precincts. */
+	int numprcs;
+
+	/* The last layer processed for each precinct. */
+	int *prclyrnos;
+
+	/* The precinct width exponent. */
+	int prcwidthexpn;
+
+	/* The precinct height exponent. */
+	int prcheightexpn;
+
+	/* The number of precincts spanning the resolution level in the horizontal
+	  direction. */
+	int numhprcs;
+
+} jpc_pirlvl_t;
+
+/* Packet iterator per-component information. */
+
+typedef struct {
+
+	/* The number of resolution levels. */
+	int numrlvls;
+
+	/* The per-resolution-level information. */
+	jpc_pirlvl_t *pirlvls;
+
+	/* The horizontal sampling period. */
+	int hsamp;
+
+	/* The vertical sampling period. */
+	int vsamp;
+
+} jpc_picomp_t;
+
+/* Packet iterator class. */
+
+typedef struct {
+
+	/* The number of layers. */
+	int numlyrs;
+
+	/* The number of resolution levels. */
+	int maxrlvls;
+
+	/* The number of components. */
+	int numcomps;
+
+	/* The per-component information. */
+	jpc_picomp_t *picomps;
+
+	/* The current component. */
+	jpc_picomp_t *picomp;
+
+	/* The current resolution level. */
+	jpc_pirlvl_t *pirlvl;
+
+	/* The number of the current component. */
+	int compno;
+
+	/* The number of the current resolution level. */
+	int rlvlno;
+
+	/* The number of the current precinct. */
+	int prcno;
+
+	/* The number of the current layer. */
+	int lyrno;
+
+	/* The x-coordinate of the current position. */
+	int x;
+
+	/* The y-coordinate of the current position. */
+	int y;
+
+	/* The horizontal step size. */
+	int xstep;
+
+	/* The vertical step size. */
+	int ystep;
+
+	/* The x-coordinate of the top-left corner of the tile on the reference
+	  grid. */
+	int xstart;
+
+	/* The y-coordinate of the top-left corner of the tile on the reference
+	  grid. */
+	int ystart;
+
+	/* The x-coordinate of the bottom-right corner of the tile on the
+	  reference grid (plus one). */
+	int xend;
+
+	/* The y-coordinate of the bottom-right corner of the tile on the
+	  reference grid (plus one). */
+	int yend;
+
+	/* The current progression change. */
+	jpc_pchg_t *pchg;
+
+	/* The progression change list. */
+	jpc_pchglist_t *pchglist;
+
+	/* The progression to use in the absense of explicit specification. */
+	jpc_pchg_t defaultpchg;
+
+	/* The current progression change number. */
+	int pchgno;
+
+	/* Is this the first time in the current progression volume? */
+	bool prgvolfirst;
+
+	/* Is the current iterator value valid? */
+	bool valid;
+
+	/* The current packet number. */
+	int pktno;
+
+} jpc_pi_t;
+
+/******************************************************************************\
+* Functions/macros for packet iterators.
+\******************************************************************************/
+
+/* Create a packet iterator. */
+jpc_pi_t *jpc_pi_create0(void);
+
+/* Destroy a packet iterator. */
+void jpc_pi_destroy(jpc_pi_t *pi);
+
+/* Add a progression change to a packet iterator. */
+int jpc_pi_addpchg(jpc_pi_t *pi, jpc_pocpchg_t *pchg);
+
+/* Prepare a packet iterator for iteration. */
+int jpc_pi_init(jpc_pi_t *pi);
+
+/* Set the iterator to the first packet. */
+int jpc_pi_begin(jpc_pi_t *pi);
+
+/* Proceed to the next packet in sequence. */
+int jpc_pi_next(jpc_pi_t *pi);
+
+/* Get the index of the current packet. */
+#define	jpc_pi_getind(pi)	((pi)->pktno)
+
+/* Get the component number of the current packet. */
+#define jpc_pi_cmptno(pi)	(assert(pi->valid), (pi)->compno)
+
+/* Get the resolution level of the current packet. */
+#define jpc_pi_rlvlno(pi)	(assert(pi->valid), (pi)->rlvlno)
+
+/* Get the layer number of the current packet. */
+#define jpc_pi_lyrno(pi)	(assert(pi->valid), (pi)->lyrno)
+
+/* Get the precinct number of the current packet. */
+#define jpc_pi_prcno(pi)	(assert(pi->valid), (pi)->prcno)
+
+/* Get the progression order for the current packet. */
+#define jpc_pi_prg(pi)	(assert(pi->valid), (pi)->pchg->prgord)
+
+/******************************************************************************\
+* Functions/macros for progression change lists.
+\******************************************************************************/
+
+/* Create a progression change list. */
+jpc_pchglist_t *jpc_pchglist_create(void);
+
+/* Destroy a progression change list. */
+void jpc_pchglist_destroy(jpc_pchglist_t *pchglist);
+
+/* Insert a new element into a progression change list. */
+int jpc_pchglist_insert(jpc_pchglist_t *pchglist, int pchgno, jpc_pchg_t *pchg);
+
+/* Remove an element from a progression change list. */
+jpc_pchg_t *jpc_pchglist_remove(jpc_pchglist_t *pchglist, int pchgno);
+
+/* Get an element from a progression change list. */
+jpc_pchg_t *jpc_pchglist_get(jpc_pchglist_t *pchglist, int pchgno);
+
+/* Copy a progression change list. */
+jpc_pchglist_t *jpc_pchglist_copy(jpc_pchglist_t *pchglist);
+
+/* Get the number of elements in a progression change list. */
+int jpc_pchglist_numpchgs(jpc_pchglist_t *pchglist);
+
+/******************************************************************************\
+* Functions/macros for progression changes.
+\******************************************************************************/
+
+/* Destroy a progression change. */
+void jpc_pchg_destroy(jpc_pchg_t *pchg);
+
+/* Copy a progression change. */
+jpc_pchg_t *jpc_pchg_copy(jpc_pchg_t *pchg);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t2dec.c b/converter/other/jpeg2000/libjasper/jpc/jpc_t2dec.c
new file mode 100644
index 00000000..9aaaa55c
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t2dec.c
@@ -0,0 +1,626 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tier 2 Decoder
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "jasper/jas_types.h"
+#include "jasper/jas_fix.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_math.h"
+#include "jasper/jas_stream.h"
+#include "jasper/jas_debug.h"
+
+#include "jpc_bs.h"
+#include "jpc_dec.h"
+#include "jpc_cs.h"
+#include "jpc_mqdec.h"
+#include "jpc_t2dec.h"
+#include "jpc_t1cod.h"
+#include "jpc_math.h"
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+long jpc_dec_lookahead(jas_stream_t *in);
+static int jpc_getcommacode(jpc_bitstream_t *in);
+static int jpc_getnumnewpasses(jpc_bitstream_t *in);
+static int jpc_dec_decodepkt(jpc_dec_t *dec, jas_stream_t *pkthdrstream, jas_stream_t *in, int compno, int lvlno,
+  int prcno, int lyrno);
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+static int jpc_getcommacode(jpc_bitstream_t *in)
+{
+	int n;
+	int v;
+
+	n = 0;
+	for (;;) {
+		if ((v = jpc_bitstream_getbit(in)) < 0) {
+			return -1;
+		}
+		if (jpc_bitstream_eof(in)) {
+			return -1;
+		}
+		if (!v) {
+			break;
+		}
+		++n;
+	}
+
+	return n;
+}
+
+static int jpc_getnumnewpasses(jpc_bitstream_t *in)
+{
+	int n;
+
+	if ((n = jpc_bitstream_getbit(in)) > 0) {
+		if ((n = jpc_bitstream_getbit(in)) > 0) {
+			if ((n = jpc_bitstream_getbits(in, 2)) == 3) {
+				if ((n = jpc_bitstream_getbits(in, 5)) == 31) {
+					if ((n = jpc_bitstream_getbits(in, 7)) >= 0) {
+						n += 36 + 1;
+					}
+				} else if (n >= 0) {
+					n += 5 + 1;
+				}
+			} else if (n >= 0) {
+				n += 2 + 1;
+			}
+		} else if (!n) {
+			n += 2;
+		}
+	} else if (!n) {
+		++n;
+	}
+
+	return n;
+}
+
+static int jpc_dec_decodepkt(jpc_dec_t *dec, jas_stream_t *pkthdrstream, jas_stream_t *in, int compno, int rlvlno,
+  int prcno, int lyrno)
+{
+	jpc_bitstream_t *inb;
+	jpc_dec_tcomp_t *tcomp;
+	jpc_dec_rlvl_t *rlvl;
+	jpc_dec_band_t *band;
+	jpc_dec_cblk_t *cblk;
+	int n;
+	int m;
+	int i;
+	jpc_tagtreenode_t *leaf;
+	int included;
+	int ret;
+	int numnewpasses;
+	jpc_dec_seg_t *seg;
+	int len;
+	int present;
+	int savenumnewpasses;
+	int mycounter;
+	jpc_ms_t *ms;
+	jpc_dec_tile_t *tile;
+	jpc_dec_ccp_t *ccp;
+	jpc_dec_cp_t *cp;
+	int bandno;
+	jpc_dec_prc_t *prc;
+	int usedcblkcnt;
+	int cblkno;
+	uint_fast32_t bodylen;
+	bool discard;
+	int passno;
+	int maxpasses;
+	int hdrlen;
+	int hdroffstart;
+	int hdroffend;
+
+	discard = (lyrno >= dec->maxlyrs);
+
+	tile = dec->curtile;
+	cp = tile->cp;
+	ccp = &cp->ccps[compno];
+
+	/*
+	 * Decode the packet header.
+	 */
+
+	/* Decode the SOP marker segment if present. */
+	if (cp->csty & JPC_COD_SOP) {
+		if (jpc_dec_lookahead(in) == JPC_MS_SOP) {
+			if (!(ms = jpc_getms(in, dec->cstate))) {
+				return -1;
+			}
+			if (jpc_ms_gettype(ms) != JPC_MS_SOP) {
+				jpc_ms_destroy(ms);
+				fprintf(stderr, "missing SOP marker segment\n");
+				return -1;
+			}
+			jpc_ms_destroy(ms);
+		}
+	}
+
+hdroffstart = jas_stream_getrwcount(pkthdrstream);
+
+	if (!(inb = jpc_bitstream_sopen(pkthdrstream, "r"))) {
+		return -1;
+	}
+
+	if ((present = jpc_bitstream_getbit(inb)) < 0) {
+		return 1;
+	}
+	JAS_DBGLOG(10, ("\n", present));
+	JAS_DBGLOG(10, ("present=%d ", present));
+
+	/* Is the packet non-empty? */
+	if (present) {
+		/* The packet is non-empty. */
+		tcomp = &tile->tcomps[compno];
+		rlvl = &tcomp->rlvls[rlvlno];
+		bodylen = 0;
+		for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
+		  ++bandno, ++band) {
+			if (!band->data) {
+				continue;
+			}
+			prc = &band->prcs[prcno];
+			if (!prc->cblks) {
+				continue;
+			}
+			usedcblkcnt = 0;
+			for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
+			  ++cblkno, ++cblk) {
+				++usedcblkcnt;
+				if (!cblk->numpasses) {
+					leaf = jpc_tagtree_getleaf(prc->incltagtree, usedcblkcnt - 1);
+					if ((included = jpc_tagtree_decode(prc->incltagtree, leaf, lyrno + 1, inb)) < 0) {
+						return -1;
+					}
+				} else {
+					if ((included = jpc_bitstream_getbit(inb)) < 0) {
+						return -1;
+					}
+				}
+				JAS_DBGLOG(10, ("\n"));
+				JAS_DBGLOG(10, ("included=%d ", included));
+				if (!included) {
+					continue;
+				}
+				if (!cblk->numpasses) {
+					i = 1;
+					leaf = jpc_tagtree_getleaf(prc->numimsbstagtree, usedcblkcnt - 1);
+					for (;;) {
+						if ((ret = jpc_tagtree_decode(prc->numimsbstagtree, leaf, i, inb)) < 0) {
+							return -1;
+						}
+						if (ret) {
+							break;
+						}
+						++i;
+					}
+					cblk->numimsbs = i - 1;
+					cblk->firstpassno = cblk->numimsbs * 3;
+				}
+				if ((numnewpasses = jpc_getnumnewpasses(inb)) < 0) {
+					return -1;
+				}
+				JAS_DBGLOG(10, ("numnewpasses=%d ", numnewpasses));
+				seg = cblk->curseg;
+				savenumnewpasses = numnewpasses;
+				mycounter = 0;
+				if (numnewpasses > 0) {
+					if ((m = jpc_getcommacode(inb)) < 0) {
+						return -1;
+					}
+					cblk->numlenbits += m;
+					JAS_DBGLOG(10, ("increment=%d ", m));
+					while (numnewpasses > 0) {
+						passno = cblk->firstpassno + cblk->numpasses + mycounter;
+	/* XXX - the maxpasses is not set precisely but this doesn't matter... */
+						maxpasses = JPC_SEGPASSCNT(passno, cblk->firstpassno, 10000, (ccp->cblkctx & JPC_COX_LAZY) != 0, (ccp->cblkctx & JPC_COX_TERMALL) != 0);
+						if (!discard && !seg) {
+							if (!(seg = jpc_seg_alloc())) {
+								return -1;
+							}
+							jpc_seglist_insert(&cblk->segs, cblk->segs.tail, seg);
+							if (!cblk->curseg) {
+								cblk->curseg = seg;
+							}
+							seg->passno = passno;
+							seg->type = JPC_SEGTYPE(seg->passno, cblk->firstpassno, (ccp->cblkctx & JPC_COX_LAZY) != 0);
+							seg->maxpasses = maxpasses;
+						}
+						n = JAS_MIN(numnewpasses, maxpasses);
+						mycounter += n;
+						numnewpasses -= n;
+						if ((len = jpc_bitstream_getbits(inb, cblk->numlenbits + jpc_floorlog2(n))) < 0) {
+							return -1;
+						}
+						JAS_DBGLOG(10, ("len=%d ", len));
+						if (!discard) {
+							seg->lyrno = lyrno;
+							seg->numpasses += n;
+							seg->cnt = len;
+							seg = seg->next;
+						}
+						bodylen += len;
+					}
+				}
+				cblk->numpasses += savenumnewpasses;
+			}
+		}
+
+		jpc_bitstream_inalign(inb, 0, 0);
+
+	} else {
+		if (jpc_bitstream_inalign(inb, 0x7f, 0)) {
+			fprintf(stderr, "alignment failed\n");
+			return -1;
+		}
+	}
+	jpc_bitstream_close(inb);
+
+	hdroffend = jas_stream_getrwcount(pkthdrstream);
+	hdrlen = hdroffend - hdroffstart;
+	if (jas_getdbglevel() >= 5) {
+		fprintf(stderr, "hdrlen=%lu bodylen=%lu \n", (unsigned long) hdrlen,
+		  (unsigned long) bodylen);
+	}
+
+	if (cp->csty & JPC_COD_EPH) {
+		if (jpc_dec_lookahead(pkthdrstream) == JPC_MS_EPH) {
+			if (!(ms = jpc_getms(pkthdrstream, dec->cstate))) {
+				fprintf(stderr, "cannot get (EPH) marker segment\n");
+				return -1;
+			}
+			if (jpc_ms_gettype(ms) != JPC_MS_EPH) {
+				jpc_ms_destroy(ms);
+				fprintf(stderr, "missing EPH marker segment\n");
+				return -1;
+			}
+			jpc_ms_destroy(ms);
+		}
+	}
+
+	/* decode the packet body. */
+
+	if (jas_getdbglevel() >= 1) {
+		fprintf(stderr, "packet body offset=%06ld\n", (long) jas_stream_getrwcount(in));
+	}
+
+	if (!discard) {
+		tcomp = &tile->tcomps[compno];
+		rlvl = &tcomp->rlvls[rlvlno];
+		for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
+		  ++bandno, ++band) {
+			if (!band->data) {
+				continue;
+			}
+			prc = &band->prcs[prcno];
+			if (!prc->cblks) {
+				continue;
+			}
+			for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
+			  ++cblkno, ++cblk) {
+				seg = cblk->curseg;
+				while (seg) {
+					if (!seg->stream) {
+						if (!(seg->stream = jas_stream_memopen(0, 0))) {
+							return -1;
+						}
+					}
+#if 0
+fprintf(stderr, "lyrno=%02d, compno=%02d, lvlno=%02d, prcno=%02d, bandno=%02d, cblkno=%02d, passno=%02d numpasses=%02d cnt=%d numbps=%d, numimsbs=%d\n", lyrno, compno, rlvlno, prcno, band - rlvl->bands, cblk - prc->cblks, seg->passno, seg->numpasses, seg->cnt, band->numbps, cblk->numimsbs);
+#endif
+					if (seg->cnt > 0) {
+						if (jpc_getdata(in, seg->stream, seg->cnt) < 0) {
+							return -1;
+						}
+						seg->cnt = 0;
+					}
+					if (seg->numpasses >= seg->maxpasses) {
+						cblk->curseg = seg->next;
+					}
+					seg = seg->next;
+				}
+			}
+		}
+	} else {
+		if (jas_stream_gobble(in, bodylen) != bodylen) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/********************************************************************************************/
+/********************************************************************************************/
+
+int jpc_dec_decodepkts(jpc_dec_t *dec, jas_stream_t *pkthdrstream, jas_stream_t *in)
+{
+	jpc_dec_tile_t *tile;
+	jpc_pi_t *pi;
+	int ret;
+
+	tile = dec->curtile;
+	pi = tile->pi;
+	for (;;) {
+if (!tile->pkthdrstream || jas_stream_peekc(tile->pkthdrstream) == EOF) {
+		switch (jpc_dec_lookahead(in)) {
+		case JPC_MS_EOC:
+		case JPC_MS_SOT:
+			return 0;
+			break;
+		case JPC_MS_SOP:
+		case JPC_MS_EPH:
+		case 0:
+			break;
+		default:
+			return -1;
+			break;
+		}
+}
+		if ((ret = jpc_pi_next(pi))) {
+			return ret;
+		}
+if (dec->maxpkts >= 0 && dec->numpkts >= dec->maxpkts) {
+	fprintf(stderr, "warning: stopping decode prematurely as requested\n");
+	return 0;
+}
+		if (jas_getdbglevel() >= 1) {
+			fprintf(stderr, "packet offset=%08ld prg=%d cmptno=%02d "
+			  "rlvlno=%02d prcno=%03d lyrno=%02d\n", (long)
+			  jas_stream_getrwcount(in), jpc_pi_prg(pi), jpc_pi_cmptno(pi),
+			  jpc_pi_rlvlno(pi), jpc_pi_prcno(pi), jpc_pi_lyrno(pi));
+		}
+		if (jpc_dec_decodepkt(dec, pkthdrstream, in, jpc_pi_cmptno(pi), jpc_pi_rlvlno(pi),
+		  jpc_pi_prcno(pi), jpc_pi_lyrno(pi))) {
+			return -1;
+		}
+++dec->numpkts;
+	}
+
+	return 0;
+}
+
+jpc_pi_t *jpc_dec_pi_create(jpc_dec_t *dec, jpc_dec_tile_t *tile)
+{
+	jpc_pi_t *pi;
+	int compno;
+	jpc_picomp_t *picomp;
+	jpc_pirlvl_t *pirlvl;
+	jpc_dec_tcomp_t *tcomp;
+	int rlvlno;
+	jpc_dec_rlvl_t *rlvl;
+	int prcno;
+	int *prclyrno;
+	jpc_dec_cmpt_t *cmpt;
+
+	if (!(pi = jpc_pi_create0())) {
+		return 0;
+	}
+	pi->numcomps = dec->numcomps;
+	if (!(pi->picomps = jas_malloc(pi->numcomps * sizeof(jpc_picomp_t)))) {
+		jpc_pi_destroy(pi);
+		return 0;
+	}
+	for (compno = 0, picomp = pi->picomps; compno < pi->numcomps; ++compno,
+	  ++picomp) {
+		picomp->pirlvls = 0;
+	}
+
+	for (compno = 0, tcomp = tile->tcomps, picomp = pi->picomps;
+	  compno < pi->numcomps; ++compno, ++tcomp, ++picomp) {
+		picomp->numrlvls = tcomp->numrlvls;
+		if (!(picomp->pirlvls = jas_malloc(picomp->numrlvls *
+		  sizeof(jpc_pirlvl_t)))) {
+			jpc_pi_destroy(pi);
+			return 0;
+		}
+		for (rlvlno = 0, pirlvl = picomp->pirlvls; rlvlno <
+		  picomp->numrlvls; ++rlvlno, ++pirlvl) {
+			pirlvl->prclyrnos = 0;
+		}
+		for (rlvlno = 0, pirlvl = picomp->pirlvls, rlvl = tcomp->rlvls;
+		  rlvlno < picomp->numrlvls; ++rlvlno, ++pirlvl, ++rlvl) {
+/* XXX sizeof(long) should be sizeof different type */
+			pirlvl->numprcs = rlvl->numprcs;
+			if (!(pirlvl->prclyrnos = jas_malloc(pirlvl->numprcs *
+			  sizeof(long)))) {
+				jpc_pi_destroy(pi);
+				return 0;
+			}
+		}
+	}
+
+	pi->maxrlvls = 0;
+	for (compno = 0, tcomp = tile->tcomps, picomp = pi->picomps, cmpt =
+	  dec->cmpts; compno < pi->numcomps; ++compno, ++tcomp, ++picomp,
+	  ++cmpt) {
+		picomp->hsamp = cmpt->hstep;
+		picomp->vsamp = cmpt->vstep;
+		for (rlvlno = 0, pirlvl = picomp->pirlvls, rlvl = tcomp->rlvls;
+		  rlvlno < picomp->numrlvls; ++rlvlno, ++pirlvl, ++rlvl) {
+			pirlvl->prcwidthexpn = rlvl->prcwidthexpn;
+			pirlvl->prcheightexpn = rlvl->prcheightexpn;
+			for (prcno = 0, prclyrno = pirlvl->prclyrnos;
+			  prcno < pirlvl->numprcs; ++prcno, ++prclyrno) {
+				*prclyrno = 0;
+			}
+			pirlvl->numhprcs = rlvl->numhprcs;
+		}
+		if (pi->maxrlvls < tcomp->numrlvls) {
+			pi->maxrlvls = tcomp->numrlvls;
+		}
+	}
+
+	pi->numlyrs = tile->cp->numlyrs;
+	pi->xstart = tile->xstart;
+	pi->ystart = tile->ystart;
+	pi->xend = tile->xend;
+	pi->yend = tile->yend;
+
+	pi->picomp = 0;
+	pi->pirlvl = 0;
+	pi->x = 0;
+	pi->y = 0;
+	pi->compno = 0;
+	pi->rlvlno = 0;
+	pi->prcno = 0;
+	pi->lyrno = 0;
+	pi->xstep = 0;
+	pi->ystep = 0;
+
+	pi->pchgno = -1;
+
+	pi->defaultpchg.prgord = tile->cp->prgord;
+	pi->defaultpchg.compnostart = 0;
+	pi->defaultpchg.compnoend = pi->numcomps;
+	pi->defaultpchg.rlvlnostart = 0;
+	pi->defaultpchg.rlvlnoend = pi->maxrlvls;
+	pi->defaultpchg.lyrnoend = pi->numlyrs;
+	pi->pchg = 0;
+
+	pi->valid = 0;
+
+	return pi;
+}
+
+long jpc_dec_lookahead(jas_stream_t *in)
+{
+	uint_fast16_t x;
+	if (jpc_getuint16(in, &x)) {
+		return -1;
+	}
+	if (jas_stream_ungetc(in, x & 0xff) == EOF ||
+	  jas_stream_ungetc(in, x >> 8) == EOF) {
+		return -1;
+	}
+	if (x >= JPC_MS_INMIN && x <= JPC_MS_INMAX) {
+		return x;
+	}
+	return 0;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t2dec.h b/converter/other/jpeg2000/libjasper/jpc/jpc_t2dec.h
new file mode 100644
index 00000000..923d7c1a
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t2dec.h
@@ -0,0 +1,144 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tier 2 Decoder
+ *
+ * $Id$
+ */
+
+#ifndef JPC_T2DEC_H
+#define JPC_T2DEC_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_fix.h"
+#include "jasper/jas_stream.h"
+
+#include "jpc_bs.h"
+#include "jpc_dec.h"
+#include "jpc_mqdec.h"
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Decode the packets for a tile-part. */
+int jpc_dec_decodepkts(jpc_dec_t *dec, jas_stream_t *pkthdrstream,
+  jas_stream_t *in);
+
+/* Create a packet iterator for the decoder. */
+jpc_pi_t *jpc_dec_pi_create(jpc_dec_t *dec, jpc_dec_tile_t *tile);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t2enc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_t2enc.c
new file mode 100644
index 00000000..1444dc7b
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t2enc.c
@@ -0,0 +1,704 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tier 2 Encoder
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "jasper/jas_fix.h"
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_math.h"
+#include "jasper/jas_debug.h"
+
+#include "jpc_flt.h"
+#include "jpc_t2enc.h"
+#include "jpc_t2cod.h"
+#include "jpc_tagtree.h"
+#include "jpc_enc.h"
+#include "jpc_math.h"
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+static int jpc_putcommacode(jpc_bitstream_t *out, int n)
+{
+	assert(n >= 0);
+
+	while (--n >= 0) {
+		if (jpc_bitstream_putbit(out, 1) == EOF) {
+			return -1;
+		}
+	}
+	if (jpc_bitstream_putbit(out, 0) == EOF) {
+		return -1;
+	}
+	return 0;
+}
+
+static int jpc_putnumnewpasses(jpc_bitstream_t *out, int n)
+{
+	int ret;
+
+	if (n <= 0) {
+		return -1;
+	} else if (n == 1) {
+		ret = jpc_bitstream_putbit(out, 0);
+	} else if (n == 2) {
+		ret = jpc_bitstream_putbits(out, 2, 2);
+	} else if (n <= 5) {
+		ret = jpc_bitstream_putbits(out, 4, 0xc | (n - 3));
+	} else if (n <= 36) {
+		ret = jpc_bitstream_putbits(out, 9, 0x1e0 | (n - 6));
+	} else if (n <= 164) {
+		ret = jpc_bitstream_putbits(out, 16, 0xff80 | (n - 37));
+	} else {
+		/* The standard has no provision for encoding a larger value.
+		In practice, however, it is highly unlikely that this
+		limitation will ever be encountered. */
+		return -1;
+	}
+
+	return (ret != EOF) ? 0 : (-1);
+}
+
+int jpc_enc_encpkts(jpc_enc_t *enc, jas_stream_t *out)
+{
+	jpc_enc_tile_t *tile;
+	jpc_pi_t *pi;
+
+	tile = enc->curtile;
+
+	jpc_init_t2state(enc, 0);
+	pi = tile->pi;
+	jpc_pi_init(pi);
+
+	if (!jpc_pi_next(pi)) {
+		for (;;) {
+			if (jpc_enc_encpkt(enc, out, jpc_pi_cmptno(pi), jpc_pi_rlvlno(pi),
+			  jpc_pi_prcno(pi), jpc_pi_lyrno(pi))) {
+				return -1;
+			}
+			if (jpc_pi_next(pi)) {
+				break;
+			}
+		}
+	}
+	
+	return 0;
+}
+
+int jpc_enc_encpkt(jpc_enc_t *enc, jas_stream_t *out, int compno, int lvlno, int prcno, int lyrno)
+{
+	jpc_enc_tcmpt_t *comp;
+	jpc_enc_rlvl_t *lvl;
+	jpc_enc_band_t *band;
+	jpc_enc_band_t *endbands;
+	jpc_enc_cblk_t *cblk;
+	jpc_enc_cblk_t *endcblks;
+	jpc_bitstream_t *outb;
+	jpc_enc_pass_t *pass;
+	jpc_enc_pass_t *startpass;
+	jpc_enc_pass_t *lastpass;
+	jpc_enc_pass_t *endpass;
+	jpc_enc_pass_t *endpasses;
+	int i;
+	int included;
+	int ret;
+	jpc_tagtreenode_t *leaf;
+	int n;
+	int t1;
+	int t2;
+	int adjust;
+	int maxadjust;
+	int datalen;
+	int numnewpasses;
+	int passcount;
+	jpc_enc_tile_t *tile;
+	jpc_enc_prc_t *prc;
+	jpc_enc_cp_t *cp;
+	jpc_ms_t *ms;
+
+	tile = enc->curtile;
+	cp = enc->cp;
+
+	if (cp->tcp.csty & JPC_COD_SOP) {
+		if (!(ms = jpc_ms_create(JPC_MS_SOP))) {
+			return -1;
+		}
+		ms->parms.sop.seqno = jpc_pi_getind(tile->pi);
+		if (jpc_putms(out, enc->cstate, ms)) {
+			return -1;
+		}
+		jpc_ms_destroy(ms);
+	}
+
+	outb = jpc_bitstream_sopen(out, "w+");
+	assert(outb);
+
+	if (jpc_bitstream_putbit(outb, 1) == EOF) {
+		return -1;
+	}
+	JAS_DBGLOG(10, ("\n"));
+	JAS_DBGLOG(10, ("present. "));
+
+	comp = &tile->tcmpts[compno];
+	lvl = &comp->rlvls[lvlno];
+	endbands = &lvl->bands[lvl->numbands];
+	for (band = lvl->bands; band != endbands; ++band) {
+		if (!band->data) {
+			continue;
+		}
+		prc = &band->prcs[prcno];
+		if (!prc->cblks) {
+			continue;
+		}
+
+		endcblks = &prc->cblks[prc->numcblks];
+		for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
+			if (!lyrno) {
+				leaf = jpc_tagtree_getleaf(prc->nlibtree, cblk - prc->cblks);
+				jpc_tagtree_setvalue(prc->nlibtree, leaf, cblk->numimsbs);
+			}
+			pass = cblk->curpass;
+			included = (pass && pass->lyrno == lyrno);
+			if (included && (!cblk->numencpasses)) {
+				assert(pass->lyrno == lyrno);
+				leaf = jpc_tagtree_getleaf(prc->incltree,
+				  cblk - prc->cblks);
+				jpc_tagtree_setvalue(prc->incltree, leaf, pass->lyrno);
+			}
+		}
+
+		endcblks = &prc->cblks[prc->numcblks];
+		for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
+			pass = cblk->curpass;
+			included = (pass && pass->lyrno == lyrno);
+			if (!cblk->numencpasses) {
+				leaf = jpc_tagtree_getleaf(prc->incltree,
+				  cblk - prc->cblks);
+				if (jpc_tagtree_encode(prc->incltree, leaf, lyrno
+				  + 1, outb) < 0) {
+					return -1;
+				}
+			} else {
+				if (jpc_bitstream_putbit(outb, included) == EOF) {
+					return -1;
+				}
+			}
+			JAS_DBGLOG(10, ("included=%d ", included));
+			if (!included) {
+				continue;
+			}
+			if (!cblk->numencpasses) {
+				i = 1;
+				leaf = jpc_tagtree_getleaf(prc->nlibtree, cblk - prc->cblks);
+				for (;;) {
+					if ((ret = jpc_tagtree_encode(prc->nlibtree, leaf, i, outb)) < 0) {
+						return -1;
+					}
+					if (ret) {
+						break;
+					}
+					++i;
+				}
+				assert(leaf->known_ && i == leaf->value_ + 1);
+			}
+
+			endpasses = &cblk->passes[cblk->numpasses];
+			startpass = pass;
+			endpass = startpass;
+			while (endpass != endpasses && endpass->lyrno == lyrno){
+				++endpass;
+			}
+			numnewpasses = endpass - startpass;
+			if (jpc_putnumnewpasses(outb, numnewpasses)) {
+				return -1;
+			}
+			JAS_DBGLOG(10, ("numnewpasses=%d ", numnewpasses));
+
+			lastpass = endpass - 1;
+			n = startpass->start;
+			passcount = 1;
+			maxadjust = 0;
+			for (pass = startpass; pass != endpass; ++pass) {
+				if (pass->term || pass == lastpass) {
+					datalen = pass->end - n;
+					t1 = jpc_firstone(datalen) + 1;
+					t2 = cblk->numlenbits + jpc_floorlog2(passcount);
+					adjust = JAS_MAX(t1 - t2, 0);
+					maxadjust = JAS_MAX(adjust, maxadjust);
+					n += datalen;
+					passcount = 1;
+				} else {
+					++passcount;
+				}
+			}
+			if (jpc_putcommacode(outb, maxadjust)) {
+				return -1;
+			}
+			cblk->numlenbits += maxadjust;
+
+			lastpass = endpass - 1;
+			n = startpass->start;
+			passcount = 1;
+			for (pass = startpass; pass != endpass; ++pass) {
+				if (pass->term || pass == lastpass) {
+					datalen = pass->end - n;
+assert(jpc_firstone(datalen) < cblk->numlenbits + jpc_floorlog2(passcount));
+					if (jpc_bitstream_putbits(outb, cblk->numlenbits + jpc_floorlog2(passcount), datalen) == EOF) {
+						return -1;
+					}
+					n += datalen;
+					passcount = 1;
+				} else {
+					++passcount;
+				}
+			}
+		}
+	}
+
+	jpc_bitstream_outalign(outb, 0);
+	jpc_bitstream_close(outb);
+
+	if (cp->tcp.csty & JPC_COD_EPH) {
+		if (!(ms = jpc_ms_create(JPC_MS_EPH))) {
+			return -1;
+		}
+		jpc_putms(out, enc->cstate, ms);
+		jpc_ms_destroy(ms);
+	}
+
+	comp = &tile->tcmpts[compno];
+	lvl = &comp->rlvls[lvlno];
+	endbands = &lvl->bands[lvl->numbands];
+	for (band = lvl->bands; band != endbands; ++band) {
+		if (!band->data) {
+			continue;
+		}
+		prc = &band->prcs[prcno];
+		if (!prc->cblks) {
+			continue;
+		}
+		endcblks = &prc->cblks[prc->numcblks];
+		for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
+			pass = cblk->curpass;
+
+			if (!pass) {
+				continue;
+			}
+			if (pass->lyrno != lyrno) {
+				assert(pass->lyrno < 0 || pass->lyrno > lyrno);
+				continue;
+			}
+
+			endpasses = &cblk->passes[cblk->numpasses];
+			startpass = pass;
+			endpass = startpass;
+			while (endpass != endpasses && endpass->lyrno == lyrno){
+				++endpass;
+			}
+			lastpass = endpass - 1;
+			numnewpasses = endpass - startpass;
+
+			jas_stream_seek(cblk->stream, startpass->start, SEEK_SET);
+			assert(jas_stream_tell(cblk->stream) == startpass->start);
+			if (jas_stream_copy(out, cblk->stream, lastpass->end - startpass->start)) {
+				return -1;
+			}
+			cblk->curpass = (endpass != endpasses) ? endpass : 0;
+			cblk->numencpasses += numnewpasses;
+
+		}
+	}
+
+	return 0;
+}
+
+void jpc_save_t2state(jpc_enc_t *enc)
+{
+/* stream pos in embedded T1 stream may be wrong since not saved/restored! */
+
+	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_tile_t *tile;
+	uint_fast32_t prcno;
+	jpc_enc_prc_t *prc;
+
+	tile = enc->curtile;
+
+	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;
+					}
+					jpc_tagtree_copy(prc->savincltree, prc->incltree);
+					jpc_tagtree_copy(prc->savnlibtree, prc->nlibtree);
+					endcblks = &prc->cblks[prc->numcblks];
+					for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
+						cblk->savedcurpass = cblk->curpass;
+						cblk->savednumencpasses = cblk->numencpasses;
+						cblk->savednumlenbits = cblk->numlenbits;
+					}
+				}
+			}
+		}
+	}
+
+}
+
+void jpc_restore_t2state(jpc_enc_t *enc)
+{
+
+	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_tile_t *tile;
+	uint_fast32_t prcno;
+	jpc_enc_prc_t *prc;
+
+	tile = enc->curtile;
+
+	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;
+					}
+					jpc_tagtree_copy(prc->incltree, prc->savincltree);
+					jpc_tagtree_copy(prc->nlibtree, prc->savnlibtree);
+					endcblks = &prc->cblks[prc->numcblks];
+					for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
+						cblk->curpass = cblk->savedcurpass;
+						cblk->numencpasses = cblk->savednumencpasses;
+						cblk->numlenbits = cblk->savednumlenbits;
+					}
+				}
+			}
+		}
+	}
+}
+
+void jpc_init_t2state(jpc_enc_t *enc, int raflag)
+{
+/* It is assumed that band->numbps and cblk->numbps precomputed */
+
+	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_tagtreenode_t *leaf;
+	jpc_enc_tile_t *tile;
+	uint_fast32_t prcno;
+	jpc_enc_prc_t *prc;
+
+	tile = enc->curtile;
+
+	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;
+					}
+					jpc_tagtree_reset(prc->incltree);
+					jpc_tagtree_reset(prc->nlibtree);
+					endcblks = &prc->cblks[prc->numcblks];
+					for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
+						if (jas_stream_rewind(cblk->stream)) {
+							assert(0);
+						}
+						cblk->curpass = (cblk->numpasses > 0) ? cblk->passes : 0;
+						cblk->numencpasses = 0;
+						cblk->numlenbits = 3;
+						cblk->numimsbs = band->numbps - cblk->numbps;
+						assert(cblk->numimsbs >= 0);
+						leaf = jpc_tagtree_getleaf(prc->nlibtree, cblk - prc->cblks);
+						jpc_tagtree_setvalue(prc->nlibtree, leaf, cblk->numimsbs);
+
+						if (raflag) {
+							endpasses = &cblk->passes[cblk->numpasses];
+							for (pass = cblk->passes; pass != endpasses; ++pass) {
+								pass->lyrno = -1;
+								pass->lyrno = 0;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+}
+
+jpc_pi_t *jpc_enc_pi_create(jpc_enc_cp_t *cp, jpc_enc_tile_t *tile)
+{
+	jpc_pi_t *pi;
+	int compno;
+	jpc_picomp_t *picomp;
+	jpc_pirlvl_t *pirlvl;
+	jpc_enc_tcmpt_t *tcomp;
+	int rlvlno;
+	jpc_enc_rlvl_t *rlvl;
+	int prcno;
+	int *prclyrno;
+
+	if (!(pi = jpc_pi_create0())) {
+		return 0;
+	}
+	pi->pktno = -1;
+	pi->numcomps = cp->numcmpts;
+	if (!(pi->picomps = jas_malloc(pi->numcomps * sizeof(jpc_picomp_t)))) {
+		jpc_pi_destroy(pi);
+		return 0;
+	}
+	for (compno = 0, picomp = pi->picomps; compno < pi->numcomps; ++compno,
+	  ++picomp) {
+		picomp->pirlvls = 0;
+	}
+
+	for (compno = 0, tcomp = tile->tcmpts, picomp = pi->picomps;
+	  compno < pi->numcomps; ++compno, ++tcomp, ++picomp) {
+		picomp->numrlvls = tcomp->numrlvls;
+		if (!(picomp->pirlvls = jas_malloc(picomp->numrlvls *
+		  sizeof(jpc_pirlvl_t)))) {
+			jpc_pi_destroy(pi);
+			return 0;
+		}
+		for (rlvlno = 0, pirlvl = picomp->pirlvls; rlvlno <
+		  picomp->numrlvls; ++rlvlno, ++pirlvl) {
+			pirlvl->prclyrnos = 0;
+		}
+		for (rlvlno = 0, pirlvl = picomp->pirlvls, rlvl = tcomp->rlvls;
+		  rlvlno < picomp->numrlvls; ++rlvlno, ++pirlvl, ++rlvl) {
+/* XXX sizeof(long) should be sizeof different type */
+			pirlvl->numprcs = rlvl->numprcs;
+			if (rlvl->numprcs) {
+				if (!(pirlvl->prclyrnos = jas_malloc(pirlvl->numprcs *
+				  sizeof(long)))) {
+					jpc_pi_destroy(pi);
+					return 0;
+				}
+			} else {
+				pirlvl->prclyrnos = 0;
+			}
+		}
+	}
+
+	pi->maxrlvls = 0;
+	for (compno = 0, tcomp = tile->tcmpts, picomp = pi->picomps;
+	  compno < pi->numcomps; ++compno, ++tcomp, ++picomp) {
+		picomp->hsamp = cp->ccps[compno].sampgrdstepx;
+		picomp->vsamp = cp->ccps[compno].sampgrdstepy;
+		for (rlvlno = 0, pirlvl = picomp->pirlvls, rlvl = tcomp->rlvls;
+		  rlvlno < picomp->numrlvls; ++rlvlno, ++pirlvl, ++rlvl) {
+			pirlvl->prcwidthexpn = rlvl->prcwidthexpn;
+			pirlvl->prcheightexpn = rlvl->prcheightexpn;
+			for (prcno = 0, prclyrno = pirlvl->prclyrnos;
+			  prcno < pirlvl->numprcs; ++prcno, ++prclyrno) {
+				*prclyrno = 0;
+			}
+			pirlvl->numhprcs = rlvl->numhprcs;
+		}
+		if (pi->maxrlvls < tcomp->numrlvls) {
+			pi->maxrlvls = tcomp->numrlvls;
+		}
+	}
+
+	pi->numlyrs = tile->numlyrs;
+	pi->xstart = tile->tlx;
+	pi->ystart = tile->tly;
+	pi->xend = tile->brx;
+	pi->yend = tile->bry;
+
+	pi->picomp = 0;
+	pi->pirlvl = 0;
+	pi->x = 0;
+	pi->y = 0;
+	pi->compno = 0;
+	pi->rlvlno = 0;
+	pi->prcno = 0;
+	pi->lyrno = 0;
+	pi->xstep = 0;
+	pi->ystep = 0;
+
+	pi->pchgno = -1;
+
+	pi->defaultpchg.prgord = tile->prg;
+	pi->defaultpchg.compnostart = 0;
+	pi->defaultpchg.compnoend = pi->numcomps;
+	pi->defaultpchg.rlvlnostart = 0;
+	pi->defaultpchg.rlvlnoend = pi->maxrlvls;
+	pi->defaultpchg.lyrnoend = pi->numlyrs;
+	pi->pchg = 0;
+
+	pi->valid = 0;
+
+	return pi;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_t2enc.h b/converter/other/jpeg2000/libjasper/jpc/jpc_t2enc.h
new file mode 100644
index 00000000..e97f8c06
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_t2enc.h
@@ -0,0 +1,155 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tier 2 Encoder
+ *
+ * $Id$
+ */
+
+#ifndef JPC_T2ENC_H
+#define JPC_T2ENC_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "jpc_enc.h"
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Encode the packets for a tile. */
+int jpc_enc_encpkts(jpc_enc_t *enc, jas_stream_t *out);
+
+/* Encode the specified packet. */
+int jpc_enc_encpkt(jpc_enc_t *enc, jas_stream_t *out, int compno, int lvlno,
+  int prcno, int lyrno);
+
+/* Save the tier-2 coding state. */
+void jpc_save_t2state(jpc_enc_t *enc);
+
+/* Restore the tier-2 coding state. */
+void jpc_restore_t2state(jpc_enc_t *enc);
+
+/* Initialize the tier-2 coding state. */
+void jpc_init_t2state(jpc_enc_t *enc, int raflag);
+
+/* Create a packet iterator for the encoder. */
+jpc_pi_t *jpc_enc_pi_create(jpc_enc_cp_t *cp, jpc_enc_tile_t *tile);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_tagtree.c b/converter/other/jpeg2000/libjasper/jpc/jpc_tagtree.c
new file mode 100644
index 00000000..2b13fcf1
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_tagtree.c
@@ -0,0 +1,426 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tag Tree Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <limits.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "jasper/jas_malloc.h"
+
+#include "jpc_tagtree.h"
+
+/******************************************************************************\
+* Code for creating and destroying tag trees.
+\******************************************************************************/
+
+static jpc_tagtree_t *jpc_tagtree_alloc(void)
+{
+	jpc_tagtree_t *tree;
+
+	if (!(tree = jas_malloc(sizeof(jpc_tagtree_t)))) {
+		return 0;
+	}
+	tree->numleafsh_ = 0;
+	tree->numleafsv_ = 0;
+	tree->numnodes_ = 0;
+	tree->nodes_ = 0;
+
+	return tree;
+}
+
+/* Create a tag tree. */
+
+jpc_tagtree_t *jpc_tagtree_create(int numleafsh, int numleafsv)
+{
+	int nplh[JPC_TAGTREE_MAXDEPTH];
+	int nplv[JPC_TAGTREE_MAXDEPTH];
+	jpc_tagtreenode_t *node;
+	jpc_tagtreenode_t *parentnode;
+	jpc_tagtreenode_t *parentnode0;
+	jpc_tagtree_t *tree;
+	int i;
+	int j;
+	int k;
+	int numlvls;
+	int n;
+
+	assert(numleafsh > 0 && numleafsv > 0);
+
+	if (!(tree = jpc_tagtree_alloc())) {
+		return 0;
+	}
+	tree->numleafsh_ = numleafsh;
+	tree->numleafsv_ = numleafsv;
+
+	numlvls = 0;
+	nplh[0] = numleafsh;
+	nplv[0] = numleafsv;
+	do {
+		n = nplh[numlvls] * nplv[numlvls];
+		nplh[numlvls + 1] = (nplh[numlvls] + 1) / 2;
+		nplv[numlvls + 1] = (nplv[numlvls] + 1) / 2;
+		tree->numnodes_ += n;
+		++numlvls;
+	} while (n > 1);
+
+	if (!(tree->nodes_ = jas_malloc(tree->numnodes_ * sizeof(jpc_tagtreenode_t)))) {
+		return 0;
+	}
+
+	/* Initialize the parent links for all nodes in the tree. */
+
+	node = tree->nodes_;
+	parentnode = &tree->nodes_[tree->numleafsh_ * tree->numleafsv_];
+	parentnode0 = parentnode;
+
+	for (i = 0; i < numlvls - 1; ++i) {
+		for (j = 0; j < nplv[i]; ++j) {
+			k = nplh[i];
+			while (--k >= 0) {
+				node->parent_ = parentnode;
+				++node;
+				if (--k >= 0) {
+					node->parent_ = parentnode;
+					++node;
+				}
+				++parentnode;
+			}
+			if ((j & 1) || j == nplv[i] - 1) {
+				parentnode0 = parentnode;
+			} else {
+				parentnode = parentnode0;
+				parentnode0 += nplh[i];
+			}
+		}
+	}
+	node->parent_ = 0;
+
+	/* Initialize the data values to something sane. */
+
+	jpc_tagtree_reset(tree);
+
+	return tree;
+}
+
+/* Destroy a tag tree. */
+
+void jpc_tagtree_destroy(jpc_tagtree_t *tree)
+{
+	if (tree->nodes_) {
+		jas_free(tree->nodes_);
+	}
+	jas_free(tree);
+}
+
+/******************************************************************************\
+* Code.
+\******************************************************************************/
+
+/* Copy state information from one tag tree to another. */
+
+void jpc_tagtree_copy(jpc_tagtree_t *dsttree, jpc_tagtree_t *srctree)
+{
+	int n;
+	jpc_tagtreenode_t *srcnode;
+	jpc_tagtreenode_t *dstnode;
+
+	/* The two tag trees must have similar sizes. */
+	assert(srctree->numleafsh_ == dsttree->numleafsh_ &&
+	  srctree->numleafsv_ == dsttree->numleafsv_);
+
+	n = srctree->numnodes_;
+	srcnode = srctree->nodes_;
+	dstnode = dsttree->nodes_;
+	while (--n >= 0) {
+		dstnode->value_ = srcnode->value_;
+		dstnode->low_ = srcnode->low_;
+		dstnode->known_ = srcnode->known_;
+		++dstnode;
+		++srcnode;
+	}
+}
+
+/* Reset all of the state information associated with a tag tree. */
+
+void jpc_tagtree_reset(jpc_tagtree_t *tree)
+{
+	int n;
+	jpc_tagtreenode_t *node;
+
+	n = tree->numnodes_;
+	node = tree->nodes_;
+
+	while (--n >= 0) {
+		node->value_ = INT_MAX;
+		node->low_ = 0;
+		node->known_ = 0;
+		++node;
+	}
+}
+
+/* Set the value associated with the specified leaf node, updating
+the other nodes as necessary. */
+
+void jpc_tagtree_setvalue(jpc_tagtree_t *tree, jpc_tagtreenode_t *leaf, int value)
+{
+	jpc_tagtreenode_t *node;
+
+	assert(value >= 0);
+
+	node = leaf;
+	while (node && node->value_ > value) {
+		node->value_ = value;
+		node = node->parent_;
+	}
+}
+
+/* Get a particular leaf node. */
+
+jpc_tagtreenode_t *jpc_tagtree_getleaf(jpc_tagtree_t *tree, int n)
+{
+	return &tree->nodes_[n];
+}
+
+/* Invoke the tag tree encoding procedure. */
+
+int jpc_tagtree_encode(jpc_tagtree_t *tree, jpc_tagtreenode_t *leaf, int threshold,
+  jpc_bitstream_t *out)
+{
+	jpc_tagtreenode_t *stk[JPC_TAGTREE_MAXDEPTH - 1];
+	jpc_tagtreenode_t **stkptr;
+	jpc_tagtreenode_t *node;
+	int low;
+
+	assert(leaf);
+	assert(threshold >= 0);
+
+	/* Traverse to the root of the tree, recording the path taken. */
+	stkptr = stk;
+	node = leaf;
+	while (node->parent_) {
+		*stkptr++ = node;
+		node = node->parent_;
+	}
+
+	low = 0;
+	for (;;) {
+		if (low > node->low_) {
+			/* Deferred propagation of the lower bound downward in
+			  the tree. */
+			node->low_ = low;
+		} else {
+			low = node->low_;
+		}
+
+		while (low < threshold) {
+			if (low >= node->value_) {
+				if (!node->known_) {
+					if (jpc_bitstream_putbit(out, 1) == EOF) {
+						return -1;
+					}
+					node->known_ = 1;
+				}
+				break;
+			}
+			if (jpc_bitstream_putbit(out, 0) == EOF) {
+				return -1;
+			}
+			++low;
+		}
+		node->low_ = low;
+		if (stkptr == stk) {
+			break;
+		}
+		node = *--stkptr;
+
+	}
+	return (leaf->low_ < threshold) ? 1 : 0;
+
+}
+
+/* Invoke the tag tree decoding procedure. */
+
+int jpc_tagtree_decode(jpc_tagtree_t *tree, jpc_tagtreenode_t *leaf, int threshold,
+  jpc_bitstream_t *in)
+{
+	jpc_tagtreenode_t *stk[JPC_TAGTREE_MAXDEPTH - 1];
+	jpc_tagtreenode_t **stkptr;
+	jpc_tagtreenode_t *node;
+	int low;
+	int ret;
+
+	assert(threshold >= 0);
+
+	/* Traverse to the root of the tree, recording the path taken. */
+	stkptr = stk;
+	node = leaf;
+	while (node->parent_) {
+		*stkptr++ = node;
+		node = node->parent_;
+	}
+
+	low = 0;
+	for (;;) {
+		if (low > node->low_) {
+			node->low_ = low;
+		} else {
+			low = node->low_;
+		}
+		while (low < threshold && low < node->value_) {
+			if ((ret = jpc_bitstream_getbit(in)) < 0) {
+				return -1;
+			}
+			if (ret) {
+				node->value_ = low;
+			} else {
+				++low;
+			}
+		}
+		node->low_ = low;
+		if (stkptr == stk) {
+			break;
+		}
+		node = *--stkptr;
+	}
+
+	return (node->value_ < threshold) ? 1 : 0;
+}
+
+/******************************************************************************\
+* Code for debugging.
+\******************************************************************************/
+
+void jpc_tagtree_dump(jpc_tagtree_t *tree, FILE *out)
+{
+	jpc_tagtreenode_t *node;
+	int n;
+
+	node = tree->nodes_;
+	n = tree->numnodes_;
+	while (--n >= 0) {
+		fprintf(out, "node %p, parent %p, value %d, lower %d, known %d\n",
+		  (void *) node, (void *) node->parent_, node->value_, node->low_,
+		  node->known_);
+		++node;
+	}
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_tagtree.h b/converter/other/jpeg2000/libjasper/jpc/jpc_tagtree.h
new file mode 100644
index 00000000..1892b13f
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_tagtree.h
@@ -0,0 +1,216 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tag Tree Library
+ *
+ * $Id$
+ */
+
+#ifndef JPC_TAGTREE_H
+#define JPC_TAGTREE_H
+
+/******************************************************************************\
+* Includes
+\******************************************************************************/
+
+#include <limits.h>
+#include <stdio.h>
+
+#include "jpc_bs.h"
+
+/******************************************************************************\
+* Constants
+\******************************************************************************/
+
+/* The maximum allowable depth for a tag tree. */
+#define JPC_TAGTREE_MAXDEPTH	32
+
+/******************************************************************************\
+* Types
+\******************************************************************************/
+
+/*
+ * Tag tree node.
+ */
+
+typedef struct jpc_tagtreenode_ {
+
+	/* The parent of this node. */
+	struct jpc_tagtreenode_ *parent_;
+
+	/* The value associated with this node. */
+	int value_;
+
+	/* The lower bound on the value associated with this node. */
+	int low_;
+
+	/* A flag indicating if the value is known exactly. */
+	int known_;
+
+} jpc_tagtreenode_t;
+
+/*
+ * Tag tree.
+ */
+
+typedef struct {
+
+	/* The number of leaves in the horizontal direction. */
+	int numleafsh_;
+
+	/* The number of leaves in the vertical direction. */
+	int numleafsv_;
+
+	/* The total number of nodes in the tree. */
+	int numnodes_;
+
+	/* The nodes. */
+	jpc_tagtreenode_t *nodes_;
+
+} jpc_tagtree_t;
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Create a tag tree. */
+jpc_tagtree_t *jpc_tagtree_create(int numleafsh, int numleafsv);
+
+/* Destroy a tag tree. */
+void jpc_tagtree_destroy(jpc_tagtree_t *tree);
+
+/* Copy data from one tag tree to another. */
+void jpc_tagtree_copy(jpc_tagtree_t *dsttree, jpc_tagtree_t *srctree);
+
+/* Reset the tag tree state. */
+void jpc_tagtree_reset(jpc_tagtree_t *tree);
+
+/* Set the value associated with a particular leaf node of a tag tree. */
+void jpc_tagtree_setvalue(jpc_tagtree_t *tree, jpc_tagtreenode_t *leaf,
+  int value);
+
+/* Get a pointer to a particular leaf node. */
+jpc_tagtreenode_t *jpc_tagtree_getleaf(jpc_tagtree_t *tree, int n);
+
+/* Invoke the tag tree decoding procedure. */
+int jpc_tagtree_decode(jpc_tagtree_t *tree, jpc_tagtreenode_t *leaf,
+  int threshold, jpc_bitstream_t *in);
+
+/* Invoke the tag tree encoding procedure. */
+int jpc_tagtree_encode(jpc_tagtree_t *tree, jpc_tagtreenode_t *leaf,
+  int threshold, jpc_bitstream_t *out);
+
+/* Dump a tag tree (for debugging purposes). */
+void jpc_tagtree_dump(jpc_tagtree_t *tree, FILE *out);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_tsfb.c b/converter/other/jpeg2000/libjasper/jpc/jpc_tsfb.c
new file mode 100644
index 00000000..f7d66b57
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_tsfb.c
@@ -0,0 +1,662 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tree-Structured Filter Bank (TSFB) Library
+ *
+ * $Id$
+ */
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include <assert.h>
+
+#include "jasper/jas_malloc.h"
+#include "jasper/jas_seq.h"
+
+#include "jpc_tsfb.h"
+#include "jpc_cod.h"
+#include "jpc_cs.h"
+#include "jpc_util.h"
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+#define	bandnotovind(tsfbnode, x)	((x) / (tsfbnode)->numhchans)
+#define	bandnotohind(tsfbnode, x)	((x) % (tsfbnode)->numhchans)
+
+static jpc_tsfb_t *jpc_tsfb_create(void);
+static jpc_tsfbnode_t *jpc_tsfbnode_create(void);
+static void jpc_tsfbnode_destroy(jpc_tsfbnode_t *node);
+static void jpc_tsfbnode_synthesize(jpc_tsfbnode_t *node, int flags, jas_seq2d_t *x);
+static void jpc_tsfbnode_analyze(jpc_tsfbnode_t *node, int flags, jas_seq2d_t *x);
+static void qmfb2d_getbands(jpc_qmfb1d_t *hqmfb, jpc_qmfb1d_t *vqmfb,
+  uint_fast32_t xstart, uint_fast32_t ystart, uint_fast32_t xend,
+  uint_fast32_t yend, int maxbands, int *numbandsptr, jpc_tsfbnodeband_t *bands);
+static void jpc_tsfbnode_getbandstree(jpc_tsfbnode_t *node, uint_fast32_t posxstart,
+  uint_fast32_t posystart, uint_fast32_t xstart, uint_fast32_t ystart,
+  uint_fast32_t xend, uint_fast32_t yend, jpc_tsfb_band_t **bands);
+static int jpc_tsfbnode_findchild(jpc_tsfbnode_t *parnode, jpc_tsfbnode_t *cldnode);
+static int jpc_tsfbnode_getequivfilters(jpc_tsfbnode_t *tsfbnode, int cldind,
+  int width, int height, jas_seq_t **vfilter, jas_seq_t **hfilter);
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+jpc_tsfb_t *jpc_tsfb_wavelet(jpc_qmfb1d_t *hqmfb, jpc_qmfb1d_t *vqmfb, int numdlvls)
+{
+	jpc_tsfb_t *tsfb;
+	int dlvlno;
+	jpc_tsfbnode_t *curnode;
+	jpc_tsfbnode_t *prevnode;
+	int childno;
+	if (!(tsfb = jpc_tsfb_create())) {
+		return 0;
+	}
+	prevnode = 0;
+	for (dlvlno = 0; dlvlno < numdlvls; ++dlvlno) {
+		if (!(curnode = jpc_tsfbnode_create())) {
+			jpc_tsfb_destroy(tsfb);
+			return 0;
+		}
+		if (prevnode) {
+			prevnode->children[0] = curnode;
+			++prevnode->numchildren;
+			curnode->parent = prevnode;
+		} else {
+			tsfb->root = curnode;
+			curnode->parent = 0;
+		}
+		if (hqmfb) {
+			curnode->numhchans = jpc_qmfb1d_getnumchans(hqmfb);
+			if (!(curnode->hqmfb = jpc_qmfb1d_copy(hqmfb))) {
+				jpc_tsfb_destroy(tsfb);
+				return 0;
+			}
+		} else {
+			curnode->hqmfb = 0;
+			curnode->numhchans = 1;
+		}
+		if (vqmfb) {
+			curnode->numvchans = jpc_qmfb1d_getnumchans(vqmfb);
+			if (!(curnode->vqmfb = jpc_qmfb1d_copy(vqmfb))) {
+				jpc_tsfb_destroy(tsfb);
+				return 0;
+			}
+		} else {
+			curnode->vqmfb = 0;
+			curnode->numvchans = 1;
+		}
+		curnode->maxchildren = curnode->numhchans * curnode->numvchans;
+		for (childno = 0; childno < curnode->maxchildren;
+		  ++childno) {
+			curnode->children[childno] = 0;
+		}
+		prevnode = curnode;
+	}
+	return tsfb;
+}
+
+static jpc_tsfb_t *jpc_tsfb_create()
+{
+	jpc_tsfb_t *tsfb;
+	if (!(tsfb = jas_malloc(sizeof(jpc_tsfb_t)))) {
+		return 0;
+	}
+	tsfb->root = 0;
+	return tsfb;
+}
+
+void jpc_tsfb_destroy(jpc_tsfb_t *tsfb)
+{
+	if (tsfb->root) {
+		jpc_tsfbnode_destroy(tsfb->root);
+	}
+	jas_free(tsfb);
+}
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+void jpc_tsfb_analyze(jpc_tsfb_t *tsfb, int flags, jas_seq2d_t *x)
+{
+	if (tsfb->root) {
+		jpc_tsfbnode_analyze(tsfb->root, flags, x);
+	}
+}
+
+static void jpc_tsfbnode_analyze(jpc_tsfbnode_t *node, int flags, jas_seq2d_t *x)
+{
+	jpc_tsfbnodeband_t nodebands[JPC_TSFB_MAXBANDSPERNODE];
+	int numbands;
+	jas_seq2d_t *y;
+	int bandno;
+	jpc_tsfbnodeband_t *band;
+
+	if (node->vqmfb) {
+		jpc_qmfb1d_analyze(node->vqmfb, flags | JPC_QMFB1D_VERT, x);
+	}
+	if (node->hqmfb) {
+		jpc_qmfb1d_analyze(node->hqmfb, flags, x);
+	}
+	if (node->numchildren > 0) {
+		qmfb2d_getbands(node->hqmfb, node->vqmfb, jas_seq2d_xstart(x),
+		  jas_seq2d_ystart(x), jas_seq2d_xend(x), jas_seq2d_yend(x),
+		  JPC_TSFB_MAXBANDSPERNODE, &numbands, nodebands);
+		y = jas_seq2d_create(0, 0, 0, 0);
+		assert(y);
+		for (bandno = 0, band = nodebands; bandno < numbands; ++bandno, ++band) {
+			if (node->children[bandno]) {
+				if (band->xstart != band->xend && band->ystart != band->yend) {
+					jas_seq2d_bindsub(y, x, band->locxstart, band->locystart,
+					  band->locxend, band->locyend);
+					jas_seq2d_setshift(y, band->xstart, band->ystart);
+					jpc_tsfbnode_analyze(node->children[bandno], flags, y);
+				}
+			}
+		}
+		jas_matrix_destroy(y);
+	}
+}
+
+void jpc_tsfb_synthesize(jpc_tsfb_t *tsfb, int flags, jas_seq2d_t *x)
+{
+	if (tsfb->root) {
+		jpc_tsfbnode_synthesize(tsfb->root, flags, x);
+	}
+}
+
+static void jpc_tsfbnode_synthesize(jpc_tsfbnode_t *node, int flags, jas_seq2d_t *x)
+{
+	jpc_tsfbnodeband_t nodebands[JPC_TSFB_MAXBANDSPERNODE];
+	int numbands;
+	jas_seq2d_t *y;
+	int bandno;
+	jpc_tsfbnodeband_t *band;
+
+	if (node->numchildren > 0) {
+		qmfb2d_getbands(node->hqmfb, node->vqmfb, jas_seq2d_xstart(x),
+		  jas_seq2d_ystart(x), jas_seq2d_xend(x), jas_seq2d_yend(x),
+		  JPC_TSFB_MAXBANDSPERNODE, &numbands, nodebands);
+		y = jas_seq2d_create(0, 0, 0, 0);
+		for (bandno = 0, band = nodebands; bandno < numbands; ++bandno, ++band) {
+			if (node->children[bandno]) {
+				if (band->xstart != band->xend && band->ystart != band->yend) {
+					jas_seq2d_bindsub(y, x, band->locxstart, band->locystart,
+					  band->locxend, band->locyend);
+					jas_seq2d_setshift(y, band->xstart, band->ystart);
+					jpc_tsfbnode_synthesize(node->children[bandno], flags, y);
+				}
+			}
+		}
+		jas_seq2d_destroy(y);
+	}
+	if (node->hqmfb) {
+		jpc_qmfb1d_synthesize(node->hqmfb, flags, x);
+	}
+	if (node->vqmfb) {
+		jpc_qmfb1d_synthesize(node->vqmfb, flags | JPC_QMFB1D_VERT, x);
+	}
+}
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+
+int jpc_tsfb_getbands(jpc_tsfb_t *tsfb, uint_fast32_t xstart, uint_fast32_t ystart,
+  uint_fast32_t xend, uint_fast32_t yend, jpc_tsfb_band_t *bands)
+{
+	jpc_tsfb_band_t *savbands;
+	savbands = bands;
+	if (!tsfb->root) {
+		bands[0].xstart = xstart;
+		bands[0].ystart = ystart;
+		bands[0].xend = xend;
+		bands[0].yend = yend;
+		bands[0].locxstart = xstart;
+		bands[0].locystart = ystart;
+		bands[0].locxend = xend;
+		bands[0].locyend = yend;
+		bands[0].orient = JPC_TSFB_LL;
+		bands[0].synenergywt = JPC_FIX_ONE;
+		++bands;
+	} else {
+		jpc_tsfbnode_getbandstree(tsfb->root, xstart, ystart,
+		  xstart, ystart, xend, yend, &bands);
+	}
+	return bands - savbands;
+}
+
+static void jpc_tsfbnode_getbandstree(jpc_tsfbnode_t *node, uint_fast32_t posxstart,
+  uint_fast32_t posystart, uint_fast32_t xstart, uint_fast32_t ystart,
+  uint_fast32_t xend, uint_fast32_t yend, jpc_tsfb_band_t **bands)
+{
+	jpc_tsfbnodeband_t nodebands[JPC_TSFB_MAXBANDSPERNODE];
+	jpc_tsfbnodeband_t *nodeband;
+	int nodebandno;
+	int numnodebands;
+	jpc_tsfb_band_t *band;
+	jas_seq_t *hfilter;
+	jas_seq_t *vfilter;
+
+	qmfb2d_getbands(node->hqmfb, node->vqmfb, xstart, ystart, xend, yend,
+	  JPC_TSFB_MAXBANDSPERNODE, &numnodebands, nodebands);
+	if (node->numchildren > 0) {
+		for (nodebandno = 0, nodeband = nodebands;
+		  nodebandno < numnodebands; ++nodebandno, ++nodeband) {
+			if (node->children[nodebandno]) {
+				jpc_tsfbnode_getbandstree(node->children[
+				  nodebandno], posxstart +
+				  nodeband->locxstart - xstart, posystart +
+				  nodeband->locystart - ystart, nodeband->xstart,
+				  nodeband->ystart, nodeband->xend,
+				  nodeband->yend, bands);
+
+			}
+		}
+	}
+assert(numnodebands == 4 || numnodebands == 3);
+	for (nodebandno = 0, nodeband = nodebands; nodebandno < numnodebands;
+	  ++nodebandno, ++nodeband) {
+		if (!node->children[nodebandno]) {
+			band = *bands;
+			band->xstart = nodeband->xstart;
+			band->ystart = nodeband->ystart;
+			band->xend = nodeband->xend;
+			band->yend = nodeband->yend;
+			band->locxstart = posxstart + nodeband->locxstart -
+			  xstart;
+			band->locystart = posystart + nodeband->locystart -
+			  ystart;
+			band->locxend = band->locxstart + band->xend -
+			  band->xstart;
+			band->locyend = band->locystart + band->yend -
+			  band->ystart;
+			if (numnodebands == 4) {
+				switch (nodebandno) {
+				case 0:
+					band->orient = JPC_TSFB_LL;
+					break;
+				case 1:
+					band->orient = JPC_TSFB_HL;
+					break;
+				case 2:
+					band->orient = JPC_TSFB_LH;
+					break;
+				case 3:
+					band->orient = JPC_TSFB_HH;
+					break;
+				default:
+					abort();
+					break;
+				}
+			} else {
+				switch (nodebandno) {
+				case 0:
+					band->orient = JPC_TSFB_HL;
+					break;
+				case 1:
+					band->orient = JPC_TSFB_LH;
+					break;
+				case 2:
+					band->orient = JPC_TSFB_HH;
+					break;
+				default:
+					abort();
+					break;
+				}
+			}
+			jpc_tsfbnode_getequivfilters(node, nodebandno, band->xend - band->xstart, band->yend - band->ystart, &hfilter, &vfilter);
+			band->synenergywt = jpc_fix_mul(jpc_seq_norm(hfilter),
+			  jpc_seq_norm(vfilter));
+			jas_seq_destroy(hfilter);
+			jas_seq_destroy(vfilter);
+			++(*bands);
+		}
+	}
+}
+
+/******************************************************************************\
+*
+\******************************************************************************/
+
+static jpc_tsfbnode_t *jpc_tsfbnode_create()
+{
+	jpc_tsfbnode_t *node;
+	if (!(node = jas_malloc(sizeof(jpc_tsfbnode_t)))) {
+		return 0;
+	}
+	node->numhchans = 0;
+	node->numvchans = 0;
+	node->numchildren = 0;
+	node->maxchildren = 0;
+	node->hqmfb = 0;
+	node->vqmfb = 0;
+	node->parent = 0;
+	return node;
+}
+
+static void jpc_tsfbnode_destroy(jpc_tsfbnode_t *node)
+{
+	jpc_tsfbnode_t **child;
+	int childno;
+	for (childno = 0, child = node->children; childno < node->maxchildren;
+	  ++childno, ++child) {
+		if (*child) {
+			jpc_tsfbnode_destroy(*child);
+		}
+	}
+	if (node->hqmfb) {
+		jpc_qmfb1d_destroy(node->hqmfb);
+	}
+	if (node->vqmfb) {
+		jpc_qmfb1d_destroy(node->vqmfb);
+	}
+	jas_free(node);
+}
+
+
+
+
+
+
+
+
+static void qmfb2d_getbands(jpc_qmfb1d_t *hqmfb, jpc_qmfb1d_t *vqmfb,
+  uint_fast32_t xstart, uint_fast32_t ystart, uint_fast32_t xend,
+  uint_fast32_t yend, int maxbands, int *numbandsptr, jpc_tsfbnodeband_t *bands)
+{
+	jpc_qmfb1dband_t hbands[JPC_QMFB1D_MAXCHANS];
+	jpc_qmfb1dband_t vbands[JPC_QMFB1D_MAXCHANS];
+	int numhbands;
+	int numvbands;
+	int numbands;
+	int bandno;
+	int hbandno;
+	int vbandno;
+	jpc_tsfbnodeband_t *band;
+
+	if (hqmfb) {
+		jpc_qmfb1d_getbands(hqmfb, 0, xstart, ystart, xend, yend,
+		  JPC_QMFB1D_MAXCHANS, &numhbands, hbands);
+	} else {
+		numhbands = 1;
+		hbands[0].start = xstart;
+		hbands[0].end = xend;
+		hbands[0].locstart = xstart;
+		hbands[0].locend = xend;
+	}
+	if (vqmfb) {
+		jpc_qmfb1d_getbands(vqmfb, JPC_QMFB1D_VERT, xstart, ystart, xend,
+		  yend, JPC_QMFB1D_MAXCHANS, &numvbands, vbands);
+	} else {
+		numvbands = 1;
+		vbands[0].start = ystart;
+		vbands[0].end = yend;
+		vbands[0].locstart = ystart;
+		vbands[0].locend = yend;
+	}
+	numbands = numhbands * numvbands;
+	*numbandsptr = numbands;
+	for (bandno = 0, band = bands; bandno < numbands; ++bandno, ++band) {
+		hbandno = bandno % numhbands;
+		vbandno = bandno / numhbands;
+		band->xstart = hbands[hbandno].start;
+		band->ystart = vbands[vbandno].start;
+		band->xend = hbands[hbandno].end;
+		band->yend = vbands[vbandno].end;
+		band->locxstart = hbands[hbandno].locstart;
+		band->locystart = vbands[vbandno].locstart;
+		band->locxend = hbands[hbandno].locend;
+		band->locyend = vbands[vbandno].locend;
+		assert(band->xstart <= band->xend &&
+		  band->ystart <= band->yend);
+		if (band->xstart == band->xend) {
+			band->yend = band->ystart;
+			band->locyend = band->locystart;
+		} else if (band->ystart == band->yend) {
+			band->xend = band->xstart;
+			band->locxend = band->locxstart;
+		}
+	}
+}
+
+static int jpc_tsfbnode_getequivfilters(jpc_tsfbnode_t *tsfbnode, int cldind,
+  int width, int height, jas_seq_t **hfilter, jas_seq_t **vfilter)
+{
+	jas_seq_t *hseq;
+	jas_seq_t *vseq;
+	jpc_tsfbnode_t *node;
+	jas_seq2d_t *hfilters[JPC_QMFB1D_MAXCHANS];
+	jas_seq2d_t *vfilters[JPC_QMFB1D_MAXCHANS];
+	int numhchans;
+	int numvchans;
+	jas_seq_t *tmpseq;
+
+	hseq = 0;
+	vseq = 0;
+
+	if (!(hseq = jas_seq_create(0, 1))) {
+		goto error;
+	}
+	jas_seq_set(hseq, 0, jpc_inttofix(1));
+	if (!(vseq = jas_seq_create(0, 1))) {
+		goto error;
+	}
+	jas_seq_set(vseq, 0, jpc_inttofix(1));
+
+	node = tsfbnode;
+	while (node) {
+		if (node->hqmfb) {
+			numhchans = jpc_qmfb1d_getnumchans(node->hqmfb);
+			if (jpc_qmfb1d_getsynfilters(node->hqmfb, width, hfilters)) {
+				goto error;
+			}
+			if (!(tmpseq = jpc_seq_upsample(hseq, numhchans))) {
+				goto error;
+			}
+			jas_seq_destroy(hseq);
+			hseq = tmpseq;
+			if (!(tmpseq = jpc_seq_conv(hseq, hfilters[bandnotohind(node, cldind)]))) {
+				goto error;
+			}
+			jas_seq_destroy(hfilters[0]);
+			jas_seq_destroy(hfilters[1]);
+			jas_seq_destroy(hseq);
+			hseq = tmpseq;
+		}
+		if (node->vqmfb) {
+			numvchans = jpc_qmfb1d_getnumchans(node->vqmfb);
+			if (jpc_qmfb1d_getsynfilters(node->vqmfb, height, vfilters)) {
+				abort();
+			}
+			if (!(tmpseq = jpc_seq_upsample(vseq, numvchans))) {
+				goto error;
+			}
+			jas_seq_destroy(vseq);
+			vseq = tmpseq;
+			if (!(tmpseq = jpc_seq_conv(vseq, vfilters[bandnotovind(node, cldind)]))) {
+				goto error;
+			}
+			jas_seq_destroy(vfilters[0]);
+			jas_seq_destroy(vfilters[1]);
+			jas_seq_destroy(vseq);
+			vseq = tmpseq;
+		}
+		if (node->parent) {
+			cldind = jpc_tsfbnode_findchild(node->parent, node);
+		}
+		node = node->parent;
+	}
+
+	*hfilter = hseq;
+	*vfilter = vseq;
+
+	return 0;
+
+error:
+	if (hseq) {
+		jas_seq_destroy(hseq);
+	}
+	if (vseq) {
+		jas_seq_destroy(vseq);
+	}
+	return -1;
+
+}
+
+static int jpc_tsfbnode_findchild(jpc_tsfbnode_t *parnode, jpc_tsfbnode_t *cldnode)
+{
+	int i;
+
+	for (i = 0; i < parnode->maxchildren; i++) {
+		if (parnode->children[i] == cldnode)
+			return i;
+	}
+	assert(0);
+	return -1;
+}
+
+jpc_tsfb_t *jpc_cod_gettsfb(int qmfbid, int numlevels)
+{
+	jpc_tsfb_t *tsfb;
+
+	switch (qmfbid) {
+	case JPC_COX_RFT:
+		qmfbid = JPC_QMFB1D_FT;
+		break;
+	case JPC_COX_INS:
+		qmfbid = JPC_QMFB1D_NS;
+		break;
+	default:
+		assert(0);
+		qmfbid = 10;
+		break;
+	}
+
+{
+	jpc_qmfb1d_t *hqmfb;
+	hqmfb = jpc_qmfb1d_make(qmfbid);
+	assert(hqmfb);
+	tsfb = jpc_tsfb_wavelet(hqmfb, hqmfb, numlevels);
+	assert(tsfb);
+	jpc_qmfb1d_destroy(hqmfb);
+}
+
+	return tsfb;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_tsfb.h b/converter/other/jpeg2000/libjasper/jpc/jpc_tsfb.h
new file mode 100644
index 00000000..8670c22e
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_tsfb.h
@@ -0,0 +1,222 @@
+/*
+ * 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__
+ */
+
+/*
+ * Tree-Structured Filter Bank (TSFB) Library
+ *
+ * $Id$
+ */
+
+#ifndef JPC_TSFB_H
+#define JPC_TSFB_H
+
+/******************************************************************************\
+* Includes.
+\******************************************************************************/
+
+#include "jasper/jas_seq.h"
+
+#include "jpc_fix.h"
+#include "jpc_qmfb.h"
+
+/******************************************************************************\
+* Constants.
+\******************************************************************************/
+
+#define	JPC_TSFB_MAXBANDS	(JPC_TSFB_MAXDEPTH * 3 + 1)
+#define	JPC_TSFB_MAXDEPTH	32
+#define	JPC_TSFB_RITIMODE	JPC_QMFB1D_RITIMODE
+
+#define	JPC_TSFB_MAXBANDSPERNODE	(JPC_QMFB1D_MAXCHANS * JPC_QMFB1D_MAXCHANS)
+
+#define	JPC_TSFB_PRUNEVERT	0x01
+#define	JPC_TSFB_PRUNEHORZ	0x02
+
+#define JPC_TSFB_LL	0
+#define JPC_TSFB_LH	1
+#define JPC_TSFB_HL	2
+#define JPC_TSFB_HH	3
+
+/******************************************************************************\
+* Types.
+\******************************************************************************/
+
+typedef struct {
+
+	int xstart;
+	int ystart;
+	int xend;
+	int yend;
+	int locxstart;
+	int locystart;
+	int locxend;
+	int locyend;
+
+} jpc_tsfbnodeband_t;
+
+typedef struct jpc_tsfbnode_s {
+
+	int numhchans;
+	int numvchans;
+	jpc_qmfb1d_t *hqmfb;
+	jpc_qmfb1d_t *vqmfb;
+	int maxchildren;
+	int numchildren;
+	struct jpc_tsfbnode_s *children[JPC_TSFB_MAXBANDSPERNODE];
+	struct jpc_tsfbnode_s *parent;
+
+} jpc_tsfbnode_t;
+
+typedef struct {
+	jpc_tsfbnode_t *root;
+} jpc_tsfb_t;
+
+typedef struct {
+	int xstart;
+	int ystart;
+	int xend;
+	int yend;
+	int orient;
+	int locxstart;
+	int locystart;
+	int locxend;
+	int locyend;
+	jpc_fix_t synenergywt;
+} jpc_tsfb_band_t;
+
+/******************************************************************************\
+* Functions.
+\******************************************************************************/
+
+/* Create a TSFB. */
+jpc_tsfb_t *jpc_cod_gettsfb(int qmfbid, int numlevels);
+
+/* Create a wavelet-type TSFB with the specified horizontal and vertical
+  QMFBs. */
+jpc_tsfb_t *jpc_tsfb_wavelet(jpc_qmfb1d_t *hqmfb, jpc_qmfb1d_t *vqmfb,
+  int numdlvls);
+
+/* Destroy a TSFB. */
+void jpc_tsfb_destroy(jpc_tsfb_t *tsfb);
+
+/* Perform analysis. */
+void jpc_tsfb_analyze(jpc_tsfb_t *tsfb, int flags, jas_seq2d_t *x);
+
+/* Perform synthesis. */
+void jpc_tsfb_synthesize(jpc_tsfb_t *tsfb, int flags, jas_seq2d_t *x);
+
+/* Get band information for a TSFB. */
+int jpc_tsfb_getbands(jpc_tsfb_t *tsfb, uint_fast32_t xstart,
+  uint_fast32_t ystart, uint_fast32_t xend, uint_fast32_t yend,
+  jpc_tsfb_band_t *bands);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_util.c b/converter/other/jpeg2000/libjasper/jpc/jpc_util.c
new file mode 100644
index 00000000..82f4b285
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_util.c
@@ -0,0 +1,243 @@
+/*
+ * 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "jasper/jas_math.h"
+#include "jasper/jas_malloc.h"
+
+#include "jpc_fix.h"
+#include "jpc_cs.h"
+#include "jpc_flt.h"
+#include "jpc_util.h"
+
+/******************************************************************************\
+* Miscellaneous Functions
+\******************************************************************************/
+
+int jpc_atoaf(const char *s, int *numvalues, double **values)
+{
+	static char delim[] = ", \t\n";
+	char buf[4096];
+	int n;
+	double *vs;
+	char *cp;
+
+	strncpy(buf, s, sizeof(buf));
+	buf[sizeof(buf) - 1] = '\0';
+	n = 0;
+	if ((cp = strtok(buf, delim))) {
+		++n;
+		while ((cp = strtok(0, delim))) {
+			if (cp != '\0') {
+				++n;
+			}
+		}
+	}
+
+	if (n) {
+		if (!(vs = jas_malloc(n * sizeof(double)))) {
+			return -1;
+		}
+
+		strncpy(buf, s, sizeof(buf));
+		buf[sizeof(buf) - 1] = '\0';
+		n = 0;
+		if ((cp = strtok(buf, delim))) {
+			vs[n] = atof(cp);
+			++n;
+			while ((cp = strtok(0, delim))) {
+				if (cp != '\0') {
+					vs[n] = atof(cp);
+					++n;
+				}
+			}
+		}
+	} else {
+		vs = 0;
+	}
+
+	*numvalues = n;
+	*values = vs;
+
+	return 0;
+}
+
+jas_seq_t *jpc_seq_upsample(jas_seq_t *x, int m)
+{
+	jas_seq_t *z;
+	int i;
+
+	if (!(z = jas_seq_create(jas_seq_start(x) * m, (jas_seq_end(x) - 1) * m + 1)))
+		return 0;
+	for (i = jas_seq_start(z); i < jas_seq_end(z); i++) {
+		*jas_seq_getref(z, i) = (!JAS_MOD(i, m)) ? jas_seq_get(x, i / m) :
+		  jpc_inttofix(0);
+	}
+
+	return z;
+}
+
+jpc_fix_t jpc_seq_norm(jas_seq_t *x)
+{
+	jpc_fix_t s;
+	int i;
+
+	s = jpc_inttofix(0);
+	for (i = jas_seq_start(x); i < jas_seq_end(x); i++) {
+		s = jpc_fix_add(s, jpc_fix_mul(jas_seq_get(x, i), jas_seq_get(x, i)));
+	}
+
+	return jpc_dbltofix(sqrt(jpc_fixtodbl(s)));
+}
+
+jas_seq_t *jpc_seq_conv(jas_seq_t *x, jas_seq_t *y)
+{
+	int i;
+	int j;
+	int k;
+	jas_seq_t *z;
+	jpc_fix_t s;
+	jpc_fix_t v;
+
+	z = jas_seq_create(jas_seq_start(x) + jas_seq_start(y),
+	  jas_seq_end(x) + jas_seq_end(y) - 1);
+	assert(z);
+	for (i = jas_seq_start(z); i < jas_seq_end(z); i++) {
+		s = jpc_inttofix(0);
+		for (j = jas_seq_start(y); j < jas_seq_end(y); j++) {
+			k = i - j;
+			if (k < jas_seq_start(x) || k >= jas_seq_end(x)) {
+				v = JPC_FIX_ZERO;
+			} else {
+				v = jas_seq_get(x, k);
+			}
+			s = jpc_fix_add(s, jpc_fix_mul(jas_seq_get(y, j), v));
+		}
+		*jas_seq_getref(z, i) = s;
+	}
+
+	return z;
+}
diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_util.h b/converter/other/jpeg2000/libjasper/jpc/jpc_util.h
new file mode 100644
index 00000000..c23fc33b
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/jpc_util.h
@@ -0,0 +1,126 @@
+/*
+ * 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__
+ */
+
+#ifndef JPC_UTIL_H
+#define JPC_UTIL_H
+
+/* Parse a comma separated list of real numbers into an array of doubles. */
+int jpc_atoaf(const char *s, int *numvalues, double **values);
+
+/* Upsample a sequence. */
+jas_seq_t *jpc_seq_upsample(jas_seq_t *seq, int n);
+
+/* Convolve two sequences. */
+jas_seq_t *jpc_seq_conv(jas_seq_t *seq0, jas_seq_t *seq1);
+
+/* Compute the norm of a sequence. */
+jpc_fix_t jpc_seq_norm(jas_seq_t *x);
+
+#endif
diff --git a/converter/other/jpeg2000/libjasper/jpc/partlist b/converter/other/jpeg2000/libjasper/jpc/partlist
new file mode 100644
index 00000000..05c36ff9
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/jpc/partlist
@@ -0,0 +1 @@
+/mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_bs.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_cs.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_dec.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_enc.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_math.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_mct.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_mqdec.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_tagtree.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t1cod.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_tsfb.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t2dec.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t2enc.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_util.o
diff --git a/converter/other/jpeg2000/libjasper/partlist b/converter/other/jpeg2000/libjasper/partlist
new file mode 100644
index 00000000..4a088cee
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper/partlist
@@ -0,0 +1,4 @@
+/mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_debug.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_getopt.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_image.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_init.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_malloc.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_seq.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_stream.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_string.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_tvp.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/base/jas_version.o
+/mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jp2/jp2_cod.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jp2/jp2_dec.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jp2/jp2_enc.o
+/mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_bs.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_cs.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_dec.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_enc.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_math.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_mct.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_mqcod.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_mqdec.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_mqenc.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_qmfb.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_tagtree.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t1cod.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t1dec.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t1enc.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_tsfb.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t2cod.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t2dec.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_t2enc.o /mp/hdb4d/home/bryanh/netpbm/converter/other/jpeg2000/libjasper/jpc/jpc_util.o
+
diff --git a/converter/other/jpeg2000/libjasper_compat.h b/converter/other/jpeg2000/libjasper_compat.h
new file mode 100644
index 00000000..401144a3
--- /dev/null
+++ b/converter/other/jpeg2000/libjasper_compat.h
@@ -0,0 +1,24 @@
+/* Here's some stuff to create backward compatibility with older Jasper
+   libraries.  Unfortunately, new versions of the Jasper library are not
+   backward compatible with old applications.
+*/
+/* The color space thing got more complex between Version 1.600 and
+   1.701.  For example, it now allows for multiple kinds of RGB, whereas
+   in 1.600 RGB meant SRGB.  As part of that change, names changed
+   from "colorspace" to "clrspc".
+*/
+#if defined(jas_image_setcolorspace)
+/* Old style color space */
+#define jas_image_setclrspc jas_image_setcolorspace
+#define JAS_CLRSPC_GENRGB JAS_IMAGE_CS_RGB
+#define JAS_CLRSPC_GENGRAY JAS_IMAGE_CS_GRAY
+#define JAS_CLRSPC_UNKNOWN JAS_IMAGE_CS_UNKNOWN
+
+#define jas_clrspc_fam(clrspc) (clrspc)
+#define jas_image_clrspc jas_image_colorspace
+
+#define JAS_CLRSPC_FAM_RGB JAS_IMAGE_CS_RGB
+#define JAS_CLRSPC_FAM_GRAY JAS_IMAGE_CS_GRAY
+#define JAS_CLRSPC_FAM_UNKNOWN JAS_IMAGE_CS_UNKNOWN
+
+#endif
diff --git a/converter/other/jpeg2000/pamtojpeg2k.c b/converter/other/jpeg2000/pamtojpeg2k.c
new file mode 100644
index 00000000..76da46d2
--- /dev/null
+++ b/converter/other/jpeg2000/pamtojpeg2k.c
@@ -0,0 +1,522 @@
+/*****************************************************************************
+                              pamtojpeg2k
+******************************************************************************
+
+  Convert a PNM image to JPEG-2000 code stream image
+
+  By Bryan Henderson, San Jose CA  2002.10.26
+
+*****************************************************************************/
+
+#define _BSD_SOURCE 1    /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+#include <string.h>
+
+#include "pam.h"
+#include "shhopt.h"
+#include "nstring.h"
+#include "mallocvar.h"
+
+#include <jasper/jasper.h>
+#include "libjasper_compat.h"
+
+
+enum compmode {COMPMODE_INTEGER, COMPMODE_REAL};
+
+enum progression {PROG_LRCP, PROG_RLCP, PROG_RPCL, PROG_PCRL, PROG_CPRL};
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    char * inputFilename;
+    unsigned int imgareatlx;
+    unsigned int imgareatly;
+    unsigned int tilegrdtlx;
+    unsigned int tilegrdtly;
+    unsigned int tilewidth;
+    unsigned int tileheight;
+    unsigned int prcwidth;
+    unsigned int prcheight;
+    unsigned int cblkwidth;
+    unsigned int cblkheight;
+    enum compmode compmode;
+    float        compressionRatio;
+    char *       ilyrrates;
+    enum progression progression;
+    unsigned int numrlvls;
+    unsigned int numgbits;
+    unsigned int nomct;
+    unsigned int sop;
+    unsigned int eph;
+    unsigned int lazy;
+    unsigned int termall;
+    unsigned int segsym;
+    unsigned int vcausal;
+    unsigned int pterm;
+    unsigned int resetprob;
+    unsigned int debuglevel;  /* Jasper library debug level */
+    unsigned int verbose;
+};
+
+
+static void
+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
+   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 imgareatlxSpec, imgareatlySpec;
+    unsigned int tilegrdtlxSpec, tilegrdtlySpec;
+    unsigned int tilewidthSpec, tileheightSpec;
+    unsigned int prcwidthSpec, prcheightSpec;
+    unsigned int cblkwidthSpec, cblkheightSpec;
+    unsigned int modeSpec, compressionSpec, ilyrratesSpec;
+    unsigned int progressionSpec, numrlvlsSpec, numgbitsSpec;
+    unsigned int debuglevelSpec;
+
+    char * progressionOpt;
+    char * modeOpt;
+
+    unsigned int option_def_index;
+    
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "imgareatlx",   OPT_UINT,   &cmdlineP->imgareatlx,
+            &imgareatlxSpec,       0);
+    OPTENT3(0, "imgareatly",   OPT_UINT,   &cmdlineP->imgareatly,
+            &imgareatlySpec,       0);
+    OPTENT3(0, "tilegrdtlx",   OPT_UINT,   &cmdlineP->tilegrdtlx,
+            &tilegrdtlxSpec,       0);
+    OPTENT3(0, "tilegrdtly",   OPT_UINT,   &cmdlineP->tilegrdtly,
+            &tilegrdtlySpec,       0);
+    OPTENT3(0, "tilewidth",    OPT_UINT,   &cmdlineP->tilewidth,
+            &tilewidthSpec,        0);
+    OPTENT3(0, "tileheight",   OPT_UINT,   &cmdlineP->tileheight,
+            &tileheightSpec,       0);
+    OPTENT3(0, "prcwidth",     OPT_UINT,   &cmdlineP->prcwidth,
+            &prcwidthSpec,       0);
+    OPTENT3(0, "prcheight",    OPT_UINT,   &cmdlineP->prcheight,
+            &prcheightSpec,      0);
+    OPTENT3(0, "cblkwidth",    OPT_UINT,   &cmdlineP->cblkwidth,
+            &cblkwidthSpec,      0);
+    OPTENT3(0, "cblkheight",   OPT_UINT,   &cmdlineP->cblkheight,
+            &cblkheightSpec,     0);
+    OPTENT3(0, "mode",         OPT_STRING, &modeOpt,
+            &modeSpec,           0);
+    OPTENT3(0, "compression",  OPT_FLOAT,  &cmdlineP->compressionRatio,
+            &compressionSpec,    0);
+    OPTENT3(0, "ilyrrates",    OPT_STRING, &cmdlineP->ilyrrates,
+            &ilyrratesSpec,      0);
+    OPTENT3(0, "progression",  OPT_STRING, &progressionOpt,
+            &progressionSpec,    0);
+    OPTENT3(0, "numrlvls",     OPT_UINT,   &cmdlineP->numrlvls,
+            &numrlvlsSpec,       0);
+    OPTENT3(0, "numgbits",     OPT_UINT,   &cmdlineP->numgbits,
+            &numgbitsSpec,       0);
+    OPTENT3(0, "nomct",        OPT_FLAG,   NULL, 
+            &cmdlineP->nomct,    0);
+    OPTENT3(0, "sop",          OPT_FLAG,   NULL, 
+            &cmdlineP->sop,      0);
+    OPTENT3(0, "eph",          OPT_FLAG,   NULL, 
+            &cmdlineP->eph,      0);
+    OPTENT3(0, "lazy",         OPT_FLAG,   NULL, 
+            &cmdlineP->lazy,     0);
+    OPTENT3(0, "termall",      OPT_FLAG,   NULL, 
+            &cmdlineP->termall,  0);
+    OPTENT3(0, "segsym",       OPT_FLAG,   NULL, 
+            &cmdlineP->segsym,    0);
+    OPTENT3(0, "vcausal",      OPT_FLAG,   NULL, 
+            &cmdlineP->vcausal,   0);
+    OPTENT3(0, "pterm",        OPT_FLAG,   NULL, 
+            &cmdlineP->pterm,     0);
+    OPTENT3(0, "resetprob",    OPT_FLAG,   NULL, 
+            &cmdlineP->resetprob, 0);
+    OPTENT3(0, "verbose",      OPT_FLAG,   NULL, 
+            &cmdlineP->verbose,   0);
+    OPTENT3(0, "debuglevel",   OPT_UINT,   &cmdlineP->debuglevel,
+            &debuglevelSpec,      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);
+
+    if (!imgareatlxSpec)
+        cmdlineP->imgareatlx = 0;
+    if (!imgareatlySpec)
+        cmdlineP->imgareatly = 0;
+    if (!tilegrdtlxSpec)
+        cmdlineP->tilegrdtlx = 0;
+    if (!tilegrdtlySpec)
+        cmdlineP->tilegrdtly = 0;
+    if (!tilewidthSpec)
+        cmdlineP->tilewidth = 0;
+    if (!tileheightSpec)
+        cmdlineP->tileheight = 0;
+    if (!prcwidthSpec)
+        cmdlineP->prcwidth = 32768;
+    if (!prcheightSpec)
+        cmdlineP->prcheight = 32768;
+    if (!cblkwidthSpec)
+        cmdlineP->cblkwidth = 64;
+    if (!cblkheightSpec)
+        cmdlineP->cblkheight = 64;
+    if (modeSpec) {
+        if (strcmp(modeOpt, "integer") == 0 || strcmp(modeOpt, "int") == 0)
+            cmdlineP->compmode = COMPMODE_INTEGER;
+        else if (strcmp(modeOpt, "real") == 0)
+            cmdlineP->compmode = COMPMODE_REAL;
+        else
+            pm_error("Invalid value for 'mode' option: '%s'.  "
+                     "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) {
+        if (strcmp(progressionOpt, "lrcp") == 0)
+            cmdlineP->progression = PROG_LRCP;
+        if (strcmp(progressionOpt, "rlcp") == 0)
+            cmdlineP->progression = PROG_RLCP;
+        if (strcmp(progressionOpt, "rpcl") == 0)
+            cmdlineP->progression = PROG_RPCL;
+        if (strcmp(progressionOpt, "pcrl") == 0)
+            cmdlineP->progression = PROG_PCRL;
+        if (strcmp(progressionOpt, "cprl") == 0)
+            cmdlineP->progression = PROG_CPRL;
+        else
+            pm_error("Invalid value for -progression: '%s'.  "
+                     "Valid values are lrcp, rlcp, rpcl, pcrl, and cprl.",
+                     progressionOpt);
+    } else
+        cmdlineP->progression = PROG_LRCP;
+    if (!numrlvlsSpec)
+        cmdlineP->numrlvls = 6;
+    if (!numgbitsSpec)
+        cmdlineP->numgbits = 2;
+    if (!debuglevelSpec)
+        cmdlineP->debuglevel = 0;
+
+    if (argc - 1 == 0)
+        cmdlineP->inputFilename = strdup("-");  /* he wants stdin */
+    else if (argc - 1 == 1)
+        cmdlineP->inputFilename = strdup(argv[1]);
+    else 
+        pm_error("Too many arguments.  The only argument accepted\n"
+                 "is the input file specification");
+
+}
+
+
+
+static void
+createJasperRaster(struct pam *  const inpamP, 
+                   jas_image_t * const jasperP) {
+
+    jas_matrix_t ** matrix;  /* malloc'ed */
+        /* matrix[X] is the data for Plane X of the current row */
+    unsigned int plane;
+    unsigned int row;
+    tuple * tuplerow;
+    bool oddMaxval;
+    sample jasperMaxval;
+
+    MALLOCARRAY_NOFAIL(matrix, inpamP->depth);
+
+    for (plane = 0; plane < inpamP->depth; ++plane) {
+        matrix[plane] = jas_matrix_create(1, inpamP->width);
+
+        if (matrix[plane] == NULL)
+            pm_error("Unable to create matrix for plane %u.  "
+                     "jas_matrix_create() failed.", plane);
+    }   
+    tuplerow = pnm_allocpamrow(inpamP);
+
+    jasperMaxval = pm_bitstomaxval(pm_maxvaltobits(inpamP->maxval));
+    oddMaxval = jasperMaxval != inpamP->maxval;
+
+    for (row = 0; row < inpamP->height; ++row) {
+        unsigned int col;
+
+        pnm_readpamrow(inpamP, tuplerow);
+
+        for (col = 0; col < inpamP->width; ++col) {
+            unsigned int plane;
+            for (plane = 0; plane < inpamP->depth; ++plane) {
+                unsigned int jasperSample;
+
+                if (oddMaxval)
+                    jasperSample = tuplerow[col][plane] * 
+                        jasperMaxval / inpamP->maxval;
+                else
+                    jasperSample = tuplerow[col][plane];
+
+                jas_matrix_set(matrix[plane], 0, col, jasperSample);
+            }
+        }
+        { 
+            unsigned int plane;
+
+            for (plane = 0; plane < inpamP->depth; ++plane) {
+                int rc;
+                rc = jas_image_writecmpt(jasperP, plane, 0, row, 
+                                         inpamP->width, 1,
+                                         matrix[plane]);
+                if (rc != 0)
+                    pm_error("jas_image_writecmpt() of plane %u failed.", 
+                             plane);
+            }
+        }
+    }
+
+    pnm_freepamrow(tuplerow);
+    for (plane = 0; plane < inpamP->depth; ++plane)
+        jas_matrix_destroy(matrix[plane]);
+    
+    free(matrix);
+}
+
+
+
+static void
+createJasperImage(struct pam *   const inpamP, 
+                  jas_image_t ** const jasperPP) {
+
+	jas_image_cmptparm_t * cmptparms;
+    unsigned int plane;
+
+    MALLOCARRAY_NOFAIL(cmptparms, inpamP->depth);
+
+    for (plane = 0; plane < inpamP->depth; ++plane) {
+        cmptparms[plane].tlx = 0;
+        cmptparms[plane].tly = 0;
+        cmptparms[plane].hstep = 1;
+        cmptparms[plane].vstep = 1;
+        cmptparms[plane].width = inpamP->width;
+        cmptparms[plane].height = inpamP->height;
+        cmptparms[plane].prec = pm_maxvaltobits(inpamP->maxval);
+        cmptparms[plane].sgnd = 0;
+    }
+    *jasperPP = 
+        jas_image_create(inpamP->depth, cmptparms, JAS_CLRSPC_UNKNOWN);
+    if (*jasperPP == NULL)
+        pm_error("Unable to create jasper image structure.  "
+                 "jas_image_create() failed.");
+
+    free(cmptparms);
+}
+
+
+
+static void
+convertToJasperImage(struct pam *   const inpamP,
+                     jas_image_t ** const jasperPP) {
+
+    jas_image_t * jasperP;
+
+    createJasperImage(inpamP, &jasperP);
+
+    if (strncmp(inpamP->tuple_type, "RGB", 3) == 0) {
+        if (inpamP->depth < 3)
+            pm_error("Input tuple type is RGB*, but depth is only %d.  "
+                     "It should be at least 3.", inpamP->depth);
+        else {
+            jas_image_setclrspc(jasperP, JAS_CLRSPC_GENRGB);
+            jas_image_setcmpttype(jasperP, 0,
+                                  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
+            jas_image_setcmpttype(jasperP, 1,
+                                  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
+            jas_image_setcmpttype(jasperP, 2,
+                                  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
+        }
+    } else {
+        if (strncmp(inpamP->tuple_type, "GRAYSCALE", 9 == 0) ||
+            strncmp(inpamP->tuple_type, "BLACKANDWHITE", 13) == 0) {
+            jas_image_setclrspc(jasperP, JAS_CLRSPC_GENGRAY);
+            jas_image_setcmpttype(jasperP, 0,
+                                  JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y));
+        }
+    }
+
+    createJasperRaster(inpamP, jasperP);
+
+    *jasperPP = jasperP;
+}
+
+
+
+static void
+writeJpc(jas_image_t *      const jasperP, 
+         struct cmdlineInfo const cmdline,
+         FILE *             const ofP) {
+
+    jas_stream_t * outStreamP;
+    const char * options;
+    const char * ilyrratesOpt;
+    const char * prgValue;
+    char rateOpt[20+1];
+
+    /* Note: ilyrrates is a hack because we're too lazy to properly parse
+       command line options to get the information and then compose
+       a proper input to Jasper.  So the user can screw things up by 
+       specifying garbage for the -ilyrrates option 
+    */
+    if (strlen(cmdline.ilyrrates) > 0)
+        asprintfN(&ilyrratesOpt, "ilyrrates=%s", cmdline.ilyrrates);
+    else
+        ilyrratesOpt = strdup("");
+
+    switch(cmdline.progression) {
+    case PROG_LRCP: prgValue = "lrcp"; break;
+    case PROG_RLCP: prgValue = "rlcp"; break;
+    case PROG_RPCL: prgValue = "rcpc"; break;
+    case PROG_PCRL: prgValue = "pcrl"; break;
+    case PROG_CPRL: prgValue = "cprl"; break;
+    }
+
+    /* 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" : ""
+        );
+    strfree(ilyrratesOpt);
+
+
+    /* Open the output image file (Standard Output) */
+    outStreamP = jas_stream_fdopen(fileno(ofP), "w+b");
+    if (outStreamP == NULL)
+        pm_error("Unable to open output stream.  jas_stream_fdopen() "
+                 "failed");
+
+    {
+        int rc;
+
+        if (cmdline.verbose)
+            pm_message("Using Jasper to encode to 'jpc' format with options "
+                       "'%s'", options);
+
+        rc = jas_image_encode(jasperP, outStreamP, 
+                              jas_image_strtofmt((char*)"jpc"), 
+                              (char*)options);
+        if (rc != 0)
+            pm_error("jas_image_encode() failed to encode the JPEG 2000 "
+                     "image.  Rc=%d", rc);
+    }
+	jas_stream_flush(outStreamP);
+
+    {
+        int rc;
+
+        rc = jas_stream_close(outStreamP);
+            
+        if (rc != 0)
+            pm_error("Failed to close output stream, "
+                     "jas_stream_close() rc = %d", rc);
+    }                     
+
+	jas_image_clearfmts();
+
+    strfree(options);
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+    struct cmdlineInfo cmdline;
+    FILE *ifP;
+    struct pam inpam;
+    jas_image_t * jasperP;
+
+    pnm_init(&argc, argv);
+    
+    parseCommandLine(argc, argv, &cmdline);
+    
+    { 
+        int rc;
+        
+        rc = jas_init();
+        if ( rc != 0 )
+            pm_error("Failed to initialize Jasper library.  "
+                     "jas_init() returns rc %d", rc );
+    }
+    
+    jas_setdbglevel(cmdline.debuglevel);
+    
+    ifP = pm_openr(cmdline.inputFilename);
+    
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+    
+    convertToJasperImage(&inpam, &jasperP);
+    
+    writeJpc(jasperP, cmdline, stdout);
+    
+	jas_image_destroy(jasperP);
+
+    pm_close(ifP);
+
+    pm_close(stdout);
+    
+    return 0;
+}
diff --git a/converter/other/jpegdatasource.c b/converter/other/jpegdatasource.c
new file mode 100644
index 00000000..5c1070e4
--- /dev/null
+++ b/converter/other/jpegdatasource.c
@@ -0,0 +1,183 @@
+/*****************************************************************************
+                           jpegdatasource.c
+******************************************************************************
+   This is the data source manager that Jpegtopnm supplies to the JPEG
+   library.  The Jpeg library uses this object to get JPEG input.
+
+   This data source manager is the same as the Jpeg library's built in
+   "stdio" one, except that it looks ahead and one can query it to see
+   if there is any data in the stream that the Jpeg library hasn't seen
+   yet.  Thus, you can use it in a program that reads multiple JPEG 
+   images and know when to stop.  You can also nicely handle completely
+   empty input files more gracefully than just crying input error.
+
+   This data source manager does 4K fread() reads and passes 4K buffers 
+   to the Jpeg library.  It reads one 4K block ahead, so there is up to
+   8K of image buffered at any time.
+
+   By Bryan Henderson, San Jose CA 2002.10.13
+*****************************************************************************/
+
+#include <ctype.h>	   
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+/* Note: jpeglib.h prerequires stdlib.h and ctype.h.  It should include them
+   itself, but doesn't.
+*/
+#include <jpeglib.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "pnm.h"
+
+#include "jpegdatasource.h"
+
+#define BUFFER_SIZE 4096
+
+struct sourceManager {
+    /* The following structure _must_ be the first thing in this structure,
+       because the methods below assume the address of the struct
+       jpeg_source_mgr is the same as the address of the struct sourceManager.
+       The former address is the only information the Jpeg library gives
+       these methods to tell them on what source manager object they are
+       supposed to operate.
+    */
+    struct jpeg_source_mgr jpegSourceMgr;
+    FILE * ifP;
+    JOCTET * currentBuffer;
+    JOCTET * nextBuffer;
+    unsigned int bytesInNextBuffer;
+    JOCTET buffer1[BUFFER_SIZE];
+    JOCTET buffer2[BUFFER_SIZE];
+};
+
+
+static void
+dsInitSource(j_decompress_ptr const cinfoP) {
+/*----------------------------------------------------------------------------
+   This is the init_source method for the data source manager the Jpeg
+   library uses.
+-----------------------------------------------------------------------------*/
+    /* The object was created ready to go and remains ready from one image
+       to the next.  No per-image initialization is necessary.
+    */
+}
+
+
+
+static boolean
+dsFillInputBuffer(j_decompress_ptr const cinfoP) {
+/*----------------------------------------------------------------------------
+   This is the fill_input_buffer method for the data source manager the Jpeg
+   library uses.
+-----------------------------------------------------------------------------*/
+    struct sourceManager * const srcP = (struct sourceManager *) cinfoP->src;
+
+    if (srcP->bytesInNextBuffer == 0) 
+        pm_error("End-of-file encountered in the middle of JPEG image.");
+    else {
+        /* Rotate the buffers */
+        srcP->jpegSourceMgr.next_input_byte = srcP->nextBuffer;
+        srcP->jpegSourceMgr.bytes_in_buffer = srcP->bytesInNextBuffer;
+        {
+            JOCTET * tmp;
+            tmp = srcP->nextBuffer;
+            srcP->nextBuffer = srcP->currentBuffer;
+            srcP->currentBuffer = tmp;
+        }
+
+        /* Fill the new 'next' buffer */
+        srcP->bytesInNextBuffer = 
+            fread(srcP->nextBuffer, 1, BUFFER_SIZE, srcP->ifP);
+    }
+    return TRUE;
+}
+
+
+
+static void
+dsSkipInputData(j_decompress_ptr const cinfoP, long const num_bytes) {
+/*----------------------------------------------------------------------------
+   This is the skip_input_data method for the data source manager the Jpeg
+   library uses.
+-----------------------------------------------------------------------------*/
+    struct jpeg_source_mgr * const jpegSourceMgrP = cinfoP->src;
+
+    long i;
+
+    for (i = 0; i < num_bytes; ++i) {
+        if (jpegSourceMgrP->bytes_in_buffer == 0)
+            dsFillInputBuffer(cinfoP);
+        ++jpegSourceMgrP->next_input_byte;
+        --jpegSourceMgrP->bytes_in_buffer;
+    }
+}
+
+
+
+static void
+dsTermSource(j_decompress_ptr const cinfoP) {
+/*----------------------------------------------------------------------------
+   This is the term_source method for the data source manager the Jpeg
+   library uses.
+-----------------------------------------------------------------------------*/
+    /* We couldn't care less that the Jpeg library is done reading an
+       image.  The source manager object remains active and ready for the
+       Jpeg library to read the next image.
+    */
+}
+
+
+
+bool
+dsDataLeft(struct sourceManager * const srcP) {
+
+    return((srcP->jpegSourceMgr.bytes_in_buffer > 0 ||
+            srcP->bytesInNextBuffer > 0));
+}
+
+
+
+struct sourceManager * 
+dsCreateSource(const char * const fileName) {
+
+    struct sourceManager * srcP;
+
+    MALLOCVAR(srcP);
+    if (srcP == NULL)
+        pm_error("Unable to get memory for the Jpeg library source manager.");
+
+    srcP->ifP = pm_openr(fileName);
+
+    srcP->jpegSourceMgr.init_source = dsInitSource;
+    srcP->jpegSourceMgr.fill_input_buffer = dsFillInputBuffer;
+    srcP->jpegSourceMgr.skip_input_data = dsSkipInputData;
+    srcP->jpegSourceMgr.resync_to_restart = jpeg_resync_to_restart;
+    srcP->jpegSourceMgr.term_source = dsTermSource;
+    
+    srcP->currentBuffer = srcP->buffer1;
+    srcP->nextBuffer = srcP->buffer2;
+    srcP->jpegSourceMgr.bytes_in_buffer = 
+        fread(srcP->currentBuffer, 1, BUFFER_SIZE, srcP->ifP);
+    srcP->jpegSourceMgr.next_input_byte = srcP->currentBuffer;
+    srcP->bytesInNextBuffer = 
+        fread(srcP->nextBuffer, 1, BUFFER_SIZE, srcP->ifP);
+
+    return srcP;
+}
+
+void
+dsDestroySource(struct sourceManager * const srcP) {
+    
+    pm_close(srcP->ifP);
+    free(srcP);
+
+}
+
+
+
+struct jpeg_source_mgr *
+dsJpegSourceMgr(struct sourceManager * const srcP) {
+    return &srcP->jpegSourceMgr;
+}
diff --git a/converter/other/jpegdatasource.h b/converter/other/jpegdatasource.h
new file mode 100644
index 00000000..07f17389
--- /dev/null
+++ b/converter/other/jpegdatasource.h
@@ -0,0 +1,18 @@
+#ifndef JPEGDATASOURCE_H_INCLUDED
+#define JPEGDATASOURCE_H_INCLUDED
+
+#include "pm_c_util.h"
+
+struct sourceManager * 
+dsCreateSource(const char * const fileName);
+
+void
+dsDestroySource(struct sourceManager * const srcP);
+
+bool
+dsDataLeft(struct sourceManager * const srcP);
+
+struct jpeg_source_mgr *
+dsJpegSourceMgr(struct sourceManager * const srcP);
+
+#endif
diff --git a/converter/other/jpegtopnm.c b/converter/other/jpegtopnm.c
new file mode 100644
index 00000000..60ae7e42
--- /dev/null
+++ b/converter/other/jpegtopnm.c
@@ -0,0 +1,970 @@
+/*****************************************************************************
+                                jpegtopnm
+******************************************************************************
+  This program is part of the Netpbm package.
+
+  This program converts from the JFIF format, which is based on JPEG, to
+  the fundamental ppm or pgm format (depending on whether the JFIF 
+  image is gray scale or color).
+
+  This program is by Bryan Henderson on 2000.03.20, but is derived
+  with permission from the program djpeg, which is in the Independent
+  Jpeg Group's JPEG library package.  Under the terms of that permission,
+  redistribution of this software is restricted as described in the 
+  file README.JPEG.
+
+  Copyright (C) 1991-1998, Thomas G. Lane.
+
+  TODO:
+
+    For CMYK and YCCK JPEG input, optionally produce a 4-deep PAM
+    output containing CMYK values.  Define a tupletype for this.
+    Extend pamtoppm to convert this to ppm using the standard
+    transformation.
+
+    See if additional decompressor options effects signficant speedup.
+    grayscale output of color image, downscaling, color quantization, and
+    dithering are possibilities.  Djpeg's man page says they make it faster.
+
+  IMPLEMENTATION NOTE - PRECISION
+
+    There are two versions of the JPEG library.  One handles only JPEG
+    files with 8 bit samples; the other handles only 12 bit files.
+    This program may be compiled and linked against either, and run
+    dynamically linked to either at runtime independently.  It uses
+    the precision information from the file header.  Note that when
+    the input has 12 bit precision, this program generates PPM files
+    with two-byte samples, but when the input has 8 bit precision, it
+    generates PPM files with one-byte samples.  One should use
+    Pnmdepth to reduce precision to 8 bits if one-byte-sample output
+    is essential.
+
+  IMPLEMENTATION NOTE - EXIF
+
+    See http://exif.org.  See the programs Exifdump
+    (http://topo.math.u-psud.fr/~bousch/exifdump.py) and Jhead
+    (http://www.sentex.net/~mwandel/jhead).
+
+    
+*****************************************************************************/
+
+#define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include <ctype.h>		/* to declare isprint() */
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+/* Note: jpeglib.h prerequires stdlib.h and ctype.h.  It should include them
+   itself, but doesn't.
+*/
+#include <jpeglib.h>
+#include "pnm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "exif.h"
+#include "jpegdatasource.h"
+
+#define EXIT_WARNING 2  /* Goes with EXIT_FAILURE, EXIT_SUCCESS in stdlib.h */
+
+enum inklevel {NORMAL, ADOBE, GUESS};
+   /* This describes image samples that represent ink levels.  NORMAL
+      means 0 is no ink; ADOBE means 0 is maximum ink.  GUESS means we
+      don't know what 0 means, so we have to guess from information in 
+      the image.
+      */
+
+enum colorspace {
+    /* These are the color spaces in which we can get pixels from the
+       JPEG decompressor.  We include only those that are possible
+       given our particular inputs to the decompressor.  The
+       decompressor is theoretically capable of other, e.g. YCCK.
+       Unlike the JPEG library, this type distinguishes between the
+       Adobe and non-Adobe style of CMYK samples.  
+    */
+    GRAYSCALE_COLORSPACE,
+    RGB_COLORSPACE, 
+    CMYK_NORMAL_COLORSPACE, 
+    CMYK_ADOBE_COLORSPACE
+    };
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    char *input_filespec;
+    char *exif_filespec;
+        /* Filespec in which to save EXIF information.  NULL means don't
+           save.  "-" means standard output
+        */
+    unsigned int verbose;
+    unsigned int nosmooth;
+    J_DCT_METHOD dct_method;
+    long int max_memory_to_use;
+    unsigned int trace_level;
+    enum inklevel inklevel;
+    unsigned int comments;
+    unsigned int dumpexif;
+    unsigned int multiple;
+};
+
+
+static bool displayComments;
+    /* User wants comments from the JPEG to be displayed */
+
+static void 
+interpret_maxmemory (bool         const maxmemorySpec,
+                     const char * const maxmemory, 
+                     long int *   const max_memory_to_use_p) { 
+/*----------------------------------------------------------------------------
+   Interpret the "maxmemory" command line option.
+-----------------------------------------------------------------------------*/
+    long int lval;
+    char ch;
+    
+    if (!maxmemorySpec) {
+        *max_memory_to_use_p = -1;  /* unspecified */
+    } else if (sscanf(maxmemory, "%ld%c", &lval, &ch) < 1) {
+        pm_error("Invalid value for --maxmemory option: '%s'.", maxmemory);
+    } else {
+        if (ch == 'm' || ch == 'M') lval *= 1000L;
+        *max_memory_to_use_p = lval * 1000L;
+    }
+}
+
+
+static void
+interpret_adobe(const int adobe, const int notadobe, 
+                enum inklevel * const inklevel_p) {
+/*----------------------------------------------------------------------------
+   Interpret the adobe/notadobe command line options
+-----------------------------------------------------------------------------*/
+    if (adobe && notadobe)
+        pm_error("You cannot specify both -adobe and -notadobe options.");
+    else {
+        if (adobe)
+            *inklevel_p = ADOBE;
+        else if (notadobe)
+            *inklevel_p = NORMAL;
+        else 
+            *inklevel_p = GUESS;
+    }
+}
+
+
+
+static void
+parse_command_line(const int argc, char ** argv,
+                   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
+   sometimes, one of these strings is actually just a suffix of an entry
+   in argv!
+
+   On the other hand, unlike other option processing functions, we do
+   not change argv at all.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def;
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    int i;  /* local loop variable */
+
+    char *maxmemory;
+    char *dctval;
+    unsigned int adobe, notadobe;
+
+    unsigned int tracelevelSpec, exifSpec, dctvalSpec, maxmemorySpec;
+    unsigned int option_def_index;
+
+    int argc_parse;       /* argc, except we modify it as we parse */
+    char ** argv_parse;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+    MALLOCARRAY_NOFAIL(argv_parse, argc);
+    
+    /* argv, except we modify it as we parse */
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "verbose",     OPT_FLAG,   NULL, &cmdlineP->verbose,       0);
+    OPTENT3(0, "dct",         OPT_STRING, &dctval,
+            &dctvalSpec, 0);
+    OPTENT3(0, "maxmemory",   OPT_STRING, &maxmemory,
+            &maxmemorySpec, 0); 
+    OPTENT3(0, "nosmooth",    OPT_FLAG,   NULL, &cmdlineP->nosmooth,      0);
+    OPTENT3(0, "tracelevel",  OPT_UINT,   &cmdlineP->trace_level,   
+            &tracelevelSpec, 0);
+    OPTENT3(0, "adobe",       OPT_FLAG,   NULL, &adobe,                   0);
+    OPTENT3(0, "notadobe",    OPT_FLAG,   NULL, &notadobe,                0);
+    OPTENT3(0, "comments",    OPT_FLAG,   NULL, &cmdlineP->comments,      0);
+    OPTENT3(0, "exif",        OPT_STRING, &cmdlineP->exif_filespec, 
+            &exifSpec, 0);
+    OPTENT3(0, "dumpexif",    OPT_FLAG,   NULL, &cmdlineP->dumpexif,      0);
+    OPTENT3(0, "multiple",    OPT_FLAG,   NULL, &cmdlineP->multiple,      0);
+
+    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 */
+
+    /* Make private copy of arguments for 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);
+        /* Uses and sets argc_parse, argv_parse, 
+           and some of *cmdlineP and others. */
+
+    if (!tracelevelSpec)
+        cmdlineP->trace_level = 0;
+
+    if (!exifSpec)
+        cmdlineP->exif_filespec = NULL;
+
+    if (argc_parse - 1 == 0)
+        cmdlineP->input_filespec = strdup("-");  /* he wants stdin */
+    else if (argc_parse - 1 == 1)
+        cmdlineP->input_filespec = strdup(argv_parse[1]);
+    else 
+        pm_error("Too many arguments.  The only argument accepted "
+                 "is the input file specification");
+
+    if (!dctvalSpec)
+        cmdlineP->dct_method = JDCT_DEFAULT;
+    else {
+        if (STREQ(dctval, "int"))
+            cmdlineP->dct_method = JDCT_ISLOW;
+        else if (STREQ(dctval, "fast"))
+            cmdlineP->dct_method = JDCT_IFAST;
+        else if (STREQ(dctval, "float"))
+            cmdlineP->dct_method = JDCT_FLOAT;
+        else pm_error("Invalid value for the --dct option: '%s'.", dctval);
+    }
+
+    interpret_maxmemory(maxmemorySpec, maxmemory, 
+                        &cmdlineP->max_memory_to_use);
+
+    interpret_adobe(adobe, notadobe, &cmdlineP->inklevel);
+
+    free(argv_parse);
+}
+
+
+/*
+ * Marker processor for COM and interesting APPn markers.
+ * This replaces the library's built-in processor, which just skips the marker.
+ * We want to print out the marker as text, to the extent possible.
+ * Note this code relies on a non-suspending data source.
+ */
+
+#if 0
+static unsigned int
+jpeg_getc (j_decompress_ptr cinfo)
+/* Read next byte */
+{
+  struct jpeg_source_mgr * datasrc = cinfo->src;
+
+  if (datasrc->bytes_in_buffer == 0) {
+      if (! (*datasrc->fill_input_buffer) (cinfo)) 
+          pm_error("Can't suspend here.");
+  }
+  datasrc->bytes_in_buffer--;
+  return GETJOCTET(*datasrc->next_input_byte++);
+}
+
+
+static boolean
+print_text_marker (j_decompress_ptr cinfo) {
+/*----------------------------------------------------------------------------
+   This is a routine that you can register with the Jpeg decompressor
+   with e.g.
+
+     jpeg_set_marker_processor(cinfoP, JPEG_APP0 + app_type, 
+                               print_text_marker);
+
+  The decompressor then calls it when it encounters a miscellaneous marker
+  of the specified type (e.g. APP1).  At that time, the jpeg input stream
+  is positioned to the marker contents -- first 2 bytes of length information,
+  MSB first, where the length includes those two bytes, then the data.
+  
+  We just get and print the contents of the marker.
+
+  This routine is no longer used; it is kept as an example in case we want
+  to use it in the future.  Instead, we use jpeg_save_markers() and have
+  the Jpeg library store all the markers in memory for our later access.
+-----------------------------------------------------------------------------*/
+    const boolean traceit = (cinfo->err->trace_level >= 1);
+    const boolean display_value = 
+        traceit || (cinfo->unread_marker == JPEG_COM && displayComments);
+    
+    INT32 length;
+    unsigned int ch;
+    unsigned int lastch = 0;
+    
+    length = jpeg_getc(cinfo) << 8;
+    length += jpeg_getc(cinfo);
+    length -= 2;			/* discount the length word itself */
+
+    if (traceit) {
+        if (cinfo->unread_marker == JPEG_COM)
+            fprintf(stderr, "Comment, length %ld:\n", (long) length);
+        else			/* assume it is an APPn otherwise */
+            fprintf(stderr, "APP%d, length %ld:\n",
+                    cinfo->unread_marker - JPEG_APP0, (long) length);
+    }
+    
+    if (cinfo->unread_marker == JPEG_COM && displayComments)
+        fprintf(stderr, "COMMENT: ");
+    
+    while (--length >= 0) {
+        ch = jpeg_getc(cinfo);
+        if (display_value) {
+            /* Emit the character in a readable form.
+             * Nonprintables are converted to \nnn form,
+             * while \ is converted to \\.
+             * Newlines in CR, CR/LF, or LF form will be printed as one 
+             * newline.
+             */
+            if (ch == '\r') {
+              fprintf(stderr, "\n");
+            } else if (ch == '\n') {
+                if (lastch != '\r')
+                    fprintf(stderr, "\n");
+            } else if (ch == '\\') {
+                fprintf(stderr, "\\\\");
+            } else if (isprint(ch)) {
+                putc(ch, stderr);
+            } else {
+                fprintf(stderr, "\\%03o", ch);
+            }
+          lastch = ch;
+        }
+    }
+    
+    if (display_value)
+        fprintf(stderr, "\n");
+    
+    return TRUE;
+}
+#endif
+
+
+
+static void
+print_marker(struct jpeg_marker_struct const marker) {
+
+    if (marker.original_length != marker.data_length) {
+        /* This should be impossible, because we asked for up to 65535
+           bytes, and the jpeg spec doesn't allow anything bigger than that.
+        */
+        pm_message("INTERNAL ERROR: %d of %d bytes of marker were "
+                   "saved.", marker.data_length, marker.original_length);
+    }
+
+    {
+        int i;
+        JOCTET lastch;
+
+        lastch = 0;
+        for (i = 0; i < marker.data_length; i++) {
+            /* Emit the character in a readable form.
+             * Nonprintables are converted to \nnn form,
+             * while \ is converted to \\.
+             * Newlines in CR, CR/LF, or LF form will be printed as one 
+             * newline.
+             */
+            if (marker.data[i] == '\r') {
+                fprintf(stderr, "\n");
+            } else if (marker.data[i] == '\n') {
+                if (lastch != '\r')
+                    fprintf(stderr, "\n");
+            } else if (marker.data[i] == '\\') {
+                fprintf(stderr, "\\\\");
+            } else if (isprint(marker.data[i])) {
+                putc(marker.data[i], stderr);
+            } else {
+                fprintf(stderr, "\\%03o", marker.data[i]);
+            }
+            lastch = marker.data[i];
+        }
+        fprintf(stderr, "\n");
+    }
+}
+
+
+typedef struct rgb {unsigned int r; unsigned int g; unsigned int b;} rgb_type;
+
+
+static rgb_type *
+read_rgb(JSAMPLE *ptr, const enum colorspace color_space, 
+         const unsigned int maxval) {
+/*----------------------------------------------------------------------------
+  Return the RGB triple corresponding to the color of the JPEG pixel at
+  'ptr', which is in color space 'color_space'.  
+
+  Assume 'maxval' is the maximum sample value in the input pixel, and also
+  use it for the maximum sample value in the return value.
+-----------------------------------------------------------------------------*/
+    static rgb_type rgb;  /* Our return value */
+
+    switch (color_space) {
+    case RGB_COLORSPACE: {
+        rgb.r = GETJSAMPLE(*(ptr+0));
+        rgb.g = GETJSAMPLE(*(ptr+1)); 
+        rgb.b = GETJSAMPLE(*(ptr+2)); 
+    }
+        break;
+    case CMYK_NORMAL_COLORSPACE: {
+        const int c = GETJSAMPLE(*(ptr+0));
+        const int m = GETJSAMPLE(*(ptr+1));
+        const int y = GETJSAMPLE(*(ptr+2));
+        const int k = GETJSAMPLE(*(ptr+3));
+
+        /* I swapped m and y below, because they looked wrong.
+           -Bryan 2000.08.20
+           */
+        rgb.r = ((maxval-k)*(maxval-c))/maxval;
+        rgb.g = ((maxval-k)*(maxval-m))/maxval;
+        rgb.b = ((maxval-k)*(maxval-y))/maxval;
+    }
+        break;
+    case CMYK_ADOBE_COLORSPACE: {
+        const int c = GETJSAMPLE(*(ptr+0));
+        const int m = GETJSAMPLE(*(ptr+1));
+        const int y = GETJSAMPLE(*(ptr+2));
+        const int k = GETJSAMPLE(*(ptr+3));
+
+        rgb.r = (k*c)/maxval;
+        rgb.g = (k*m)/maxval;
+        rgb.b = (k*y)/maxval;
+    }
+        break;
+    default:
+        pm_error("Internal error: unknown color space %d passed to "
+                 "read_rgb().", (int) color_space);
+    }
+    return(&rgb);
+}
+
+
+
+/* pnmbuffer is declared global because it would be improper to pass a
+   pointer to it as input to copy_pixel_row(), since it isn't
+   logically a parameter of the operation, but rather is private to
+   copy_pixel_row().  But it would be impractical to allocate and free
+   the storage with every call to copy_pixel_row().
+*/
+static xel *pnmbuffer;      /* Output buffer.  Input to pnm_writepnmrow() */
+
+static void
+copy_pixel_row(const JSAMPROW jpegbuffer, const int width, 
+               const unsigned int samples_per_pixel, 
+               const enum colorspace color_space,
+               const unsigned int maxval,
+               FILE * const output_file, const int output_type) {
+  JSAMPLE *ptr;
+  unsigned int output_cursor;     /* Cursor into output buffer 'pnmbuffer' */
+
+  ptr = jpegbuffer;  /* Start at beginning of input row */
+
+  for (output_cursor = 0; output_cursor < width; output_cursor++) {
+      xel current_pixel;
+      if (samples_per_pixel >= 3) {
+          const rgb_type * const rgb_p = read_rgb(ptr, color_space, maxval);
+          PPM_ASSIGN(current_pixel, rgb_p->r, rgb_p->g, rgb_p->b);
+      } else {
+          PNM_ASSIGN1(current_pixel, GETJSAMPLE(*ptr));
+      }
+      ptr += samples_per_pixel;  /* move to next pixel of input */
+      pnmbuffer[output_cursor] = current_pixel;
+  }
+  pnm_writepnmrow(output_file, pnmbuffer, width,
+                  maxval, output_type, FALSE);
+}
+
+
+
+static void
+set_color_spaces(const J_COLOR_SPACE jpeg_color_space,
+                 int * const output_type_p,
+                 J_COLOR_SPACE * const out_color_space_p) {
+/*----------------------------------------------------------------------------
+   Decide what type of output (PPM or PGM) we shall generate and what 
+   color space we must request from the JPEG decompressor, based on the
+   color space of the input JPEG image, 'jpeg_color_space'.
+
+   Write to stderr a message telling which type we picked.
+
+   Exit the process with EXIT_FAILURE completion code and a message to
+   stderr if the input color space is beyond our capability.
+-----------------------------------------------------------------------------*/
+    /* Note that the JPEG decompressor is not capable of translating
+       CMYK or YCCK to RGB, but can translate YCCK to CMYK.
+    */
+
+    switch (jpeg_color_space) {
+    case JCS_UNKNOWN:
+        pm_error("Input JPEG image has 'unknown' color space "
+                 "(JCS_UNKNOWN).\n"
+                 "We cannot interpret this image.");
+        break;
+    case JCS_GRAYSCALE:
+        *output_type_p = PGM_TYPE;
+        *out_color_space_p = JCS_GRAYSCALE;
+        break;
+    case JCS_RGB:
+        *output_type_p = PPM_TYPE;
+        *out_color_space_p = JCS_RGB;
+        break;
+    case JCS_YCbCr:
+        *output_type_p = PPM_TYPE;
+        *out_color_space_p = JCS_RGB;
+        /* Design note:  We found this YCbCr->RGB conversion increases
+           user mode CPU time by 2.5%.  2002.10.12
+        */
+        break;
+    case JCS_CMYK:
+        *output_type_p = PPM_TYPE;
+        *out_color_space_p = JCS_CMYK;
+        break;
+    case JCS_YCCK:
+        *output_type_p = PPM_TYPE;
+        *out_color_space_p = JCS_CMYK;
+        break;
+    default:
+        pm_error("Internal error: unknown color space code %d passed "
+                 "to set_color_spaces().", jpeg_color_space);
+    }
+    pm_message("WRITING %s FILE", 
+               *output_type_p == PPM_TYPE ? "PPM" : "PGM");
+}
+
+
+
+static const char *
+colorspace_name(const J_COLOR_SPACE jpeg_color_space) {
+
+    const char *retval;
+
+    switch(jpeg_color_space) {
+    case JCS_UNKNOWN: retval = "JCS_UNKNOWN"; break;
+    case JCS_GRAYSCALE: retval= "JCS_GRAYSCALE"; break;
+    case JCS_RGB: retval = "JCS_RGB"; break;
+    case JCS_YCbCr: retval = "JCS_YCbCr"; break;
+    case JCS_CMYK: retval = "JCS_CMYK"; break;
+    case JCS_YCCK: retval = "JCS_YCCK"; break;
+    default: retval = "invalid"; break;
+    };
+    return(retval);
+}
+
+
+
+static void
+print_verbose_info_about_header(struct jpeg_decompress_struct const cinfo){
+
+    struct jpeg_marker_struct * markerP;
+
+    pm_message("input color space is %d (%s)\n", 
+               cinfo.jpeg_color_space, 
+               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
+       trace level >= 1.  Our job is to interpret it a little bit.
+    */
+    if (cinfo.marker_list)
+        pm_message("Miscellaneous markers (excluding APP0, APP12) "
+                   "in header:");
+    else
+        pm_message("No miscellaneous markers (excluding APP0, APP12) "
+                   "in header");
+    for (markerP = cinfo.marker_list; markerP; markerP = markerP->next) {
+        if (markerP->marker == JPEG_COM)
+            pm_message("Comment marker (COM):");
+        else if (markerP->marker >= JPEG_APP0 && 
+                 markerP->marker <= JPEG_APP0+15)
+            pm_message("Miscellaneous marker type APP%d:", 
+                       markerP->marker - JPEG_APP0);
+        else
+            pm_message("Miscellaneous marker of unknown type (0x%X):",
+                       markerP->marker);
+        
+        print_marker(*markerP);
+    }
+}
+
+
+
+static void
+beginJpegInput(struct jpeg_decompress_struct * const cinfoP,
+               const boolean verbose, 
+               const J_DCT_METHOD dct_method, 
+               const int max_memory_to_use, 
+               const boolean nosmooth) {
+/*----------------------------------------------------------------------------
+   Read the JPEG header, create decompressor object (and
+   allocate memory for it), set up decompressor.
+-----------------------------------------------------------------------------*/
+    /* Read file header, set default decompression parameters */
+    jpeg_read_header(cinfoP, TRUE);
+
+    cinfoP->dct_method = dct_method;
+    if (max_memory_to_use != -1)
+        cinfoP->mem->max_memory_to_use = max_memory_to_use;
+    if (nosmooth)
+        cinfoP->do_fancy_upsampling = FALSE;
+    
+}
+
+
+
+static void
+print_comments(struct jpeg_decompress_struct const cinfo) {
+    
+    struct jpeg_marker_struct * markerP;
+
+    for (markerP = cinfo.marker_list;
+         markerP; markerP = markerP->next) 
+        if (markerP->marker == JPEG_COM) {
+            pm_message("COMMENT:");
+            print_marker(*markerP);
+        }
+}
+
+
+
+static void
+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;
+    const char * error;
+
+    assert(marker.data_length >= 6);
+
+    process_EXIF(marker.data+6, marker.data_length-6, 
+                 &imageInfo, FALSE, &error);
+
+    if (error) {
+        pm_message("EXIF header is invalid.  %s", error);
+        strfree(error);
+    } else
+        ShowImageInfo(&imageInfo);
+}
+
+
+
+static boolean
+is_exif(struct jpeg_marker_struct const marker) {
+/*----------------------------------------------------------------------------
+   Return true iff the JPEG miscellaneous marker 'marker' is an Exif 
+   header.
+-----------------------------------------------------------------------------*/
+    boolean retval;
+    
+    if (marker.marker == JPEG_APP0+1) {
+        if (marker.data_length >=6 && memcmp(marker.data, "Exif", 4) == 0)
+            retval = TRUE;
+        else retval = FALSE;
+    }
+    else retval = FALSE;
+
+    return retval;
+}
+
+
+
+static void
+dump_exif(struct jpeg_decompress_struct const cinfo) {
+/*----------------------------------------------------------------------------
+   Dump as informational messages the contents of all EXIF headers in
+   the image, interpreted.  An EXIF header is an APP1 marker.
+-----------------------------------------------------------------------------*/
+    struct jpeg_marker_struct * markerP;
+    boolean found_one;
+
+    found_one = FALSE;  /* initial value */
+
+    for (markerP = cinfo.marker_list;
+         markerP; markerP = markerP->next) 
+        if (is_exif(*markerP)) {
+            pm_message("EXIF INFO:");
+            print_exif_info(*markerP);
+            found_one = TRUE;
+        }
+    if (!found_one)
+        pm_message("No EXIF info in image.");
+}
+
+
+
+static void
+save_exif(struct jpeg_decompress_struct const cinfo, 
+          const char *                  const exif_filespec) {
+/*----------------------------------------------------------------------------
+  Write the contents of the first Exif header in the image into the
+  file with filespec 'exif_filespec'.  Start with the two byte length
+  field.  If 'exif_filespec' is "-", write to standard output.
+
+  If there is no Exif header in the image, write just zero, as a two
+  byte pure binary integer.
+-----------------------------------------------------------------------------*/
+    FILE * exif_file;
+    struct jpeg_marker_struct * markerP;
+
+    exif_file = pm_openw(exif_filespec);
+
+    for (markerP = cinfo.marker_list; 
+         markerP && !is_exif(*markerP);
+         markerP = markerP->next);
+
+    if (markerP) {
+        pm_writebigshort(exif_file, markerP->data_length+2);
+        if (ferror(exif_file))
+            pm_error("Write of Exif header to %s failed on first byte.",
+                     exif_filespec);
+        else {
+            int rc;
+
+            rc = fwrite(markerP->data, 1, markerP->data_length, exif_file);
+            if (rc != markerP->data_length)
+                pm_error("Write of Exif header to '%s' failed.  Wrote "
+                         "length successfully, but then failed after "
+                         "%d characters of data.", exif_filespec, rc);
+        }
+    } else {
+        /* There is no Exif header in the image */
+        pm_writebigshort(exif_file, 0);
+        if (ferror(exif_file))
+            pm_error("Write of Exif header file '%s' failed.", exif_filespec);
+    }
+    pm_close(exif_file);
+}
+
+
+
+static void
+tellDetails(struct jpeg_decompress_struct const cinfo,
+            xelval                        const maxval,
+            int                           const output_type) {
+
+    print_verbose_info_about_header(cinfo);
+
+    pm_message("Input image data precision = %d bits", 
+               cinfo.data_precision);
+    pm_message("Output file will have format %c%c "
+               "with max sample value of %d.", 
+               (char) (output_type/256), (char) (output_type % 256),
+               maxval);
+}  
+
+
+
+static enum colorspace
+computeColorSpace(struct jpeg_decompress_struct * const cinfoP,
+                  enum inklevel                   const inklevel) {
+    
+    enum colorspace colorSpace;
+
+    if (cinfoP->out_color_space == JCS_GRAYSCALE)
+        colorSpace = GRAYSCALE_COLORSPACE;
+    else if (cinfoP->out_color_space == JCS_RGB)
+        colorSpace = RGB_COLORSPACE;
+    else if (cinfoP->out_color_space == JCS_CMYK) {
+        switch (inklevel) {
+        case ADOBE:
+            colorSpace = CMYK_ADOBE_COLORSPACE; break;
+        case NORMAL:
+            colorSpace = CMYK_NORMAL_COLORSPACE; break;
+        case GUESS:
+            colorSpace = CMYK_ADOBE_COLORSPACE; break;
+        }
+    } else
+        pm_error("Internal error: unacceptable output color space from "
+                 "JPEG decompressor.");
+
+    return colorSpace;
+}
+
+
+
+static void
+convertImage(FILE *                          const ofP, 
+             struct cmdlineInfo              const cmdline,
+             struct jpeg_decompress_struct * const cinfoP) {
+
+    int output_type;
+        /* The type of output file, PGM or PPM.  Value is either PPM_TYPE
+           or PGM_TYPE, which conveniently also pass as format values
+           PPM_FORMAT and PGM_FORMAT.
+        */
+    JSAMPROW jpegbuffer;  /* Input buffer.  Filled by jpeg_scanlines() */
+    unsigned int maxval;  
+        /* The maximum value of a sample (color component), both in the input
+           and the output.
+        */
+    enum colorspace color_space;
+        /* The color space of the pixels coming out of the JPEG decompressor */
+
+    beginJpegInput(cinfoP, cmdline.verbose, 
+                   cmdline.dct_method, 
+                   cmdline.max_memory_to_use, cmdline.nosmooth);
+                   
+    set_color_spaces(cinfoP->jpeg_color_space, &output_type, 
+                     &cinfoP->out_color_space);
+
+    maxval = (1 << cinfoP->data_precision) - 1;
+
+    if (cmdline.verbose) 
+        tellDetails(*cinfoP, maxval, output_type);
+
+    /* Calculate output image dimensions so we can allocate space */
+    jpeg_calc_output_dimensions(cinfoP);
+
+    jpegbuffer = ((*cinfoP->mem->alloc_sarray)
+                  ((j_common_ptr) cinfoP, JPOOL_IMAGE,
+                   cinfoP->output_width * cinfoP->output_components, 
+                   (JDIMENSION) 1)
+        )[0];
+
+    /* Start decompressor */
+    jpeg_start_decompress(cinfoP);
+
+    if (ofP)
+        /* Write pnm output header */
+        pnm_writepnminit(ofP, cinfoP->output_width, cinfoP->output_height,
+                         maxval, output_type, FALSE);
+
+    pnmbuffer = pnm_allocrow(cinfoP->output_width);
+    
+    color_space = computeColorSpace(cinfoP, cmdline.inklevel);
+
+    /* Process data */
+    while (cinfoP->output_scanline < cinfoP->output_height) {
+        jpeg_read_scanlines(cinfoP, &jpegbuffer, 1);
+        if (ofP)
+            copy_pixel_row(jpegbuffer, cinfoP->output_width, 
+                           cinfoP->out_color_components,
+                           color_space, maxval, ofP, output_type);
+    }
+
+    if (cmdline.comments)
+        print_comments(*cinfoP);
+    if (cmdline.dumpexif)
+        dump_exif(*cinfoP);
+    if (cmdline.exif_filespec)
+        save_exif(*cinfoP, cmdline.exif_filespec);
+
+    pnm_freerow(pnmbuffer);
+
+    /* Finish decompression and release decompressor memory. */
+    jpeg_finish_decompress(cinfoP);
+}
+
+
+
+
+static void
+saveMarkers(struct jpeg_decompress_struct * const cinfoP) {
+
+    unsigned int app_type;
+    /* Get all the miscellaneous markers (COM and APPn) saved for our
+       later access.
+    */
+    jpeg_save_markers(cinfoP, JPEG_COM, 65535);
+    for (app_type = 0; app_type <= 15; ++app_type) {
+        if (app_type == 0 || app_type == 14) {
+            /* The jpeg library uses APP0 and APP14 internally (see
+               libjpeg.doc), so we don't mess with those.
+            */
+        } else
+            jpeg_save_markers(cinfoP, JPEG_APP0 + app_type, 65535);
+    }
+}
+
+
+
+static void
+convertImages(FILE *                          const ofP,
+              struct cmdlineInfo              const cmdline,
+              struct jpeg_decompress_struct * const cinfoP,
+              struct sourceManager *          const sourceManagerP) {
+              
+    if (cmdline.multiple) {
+        unsigned int imageSequence;
+        for (imageSequence = 0; dsDataLeft(sourceManagerP); ++imageSequence) {
+            if (cmdline.verbose)
+                pm_message("Reading Image %u", imageSequence);
+            convertImage(ofP, cmdline, cinfoP);
+        }
+    } else {
+        if (dsDataLeft(sourceManagerP))
+            convertImage(ofP, cmdline, cinfoP);
+        else
+            pm_error("Input stream is empty");
+    }
+}
+
+
+
+int
+main(int argc, char **argv) {
+    FILE * ofP;
+    struct cmdlineInfo cmdline;
+    struct jpeg_decompress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    struct sourceManager * sourceManagerP;
+
+    pnm_init(&argc, argv);
+
+    parse_command_line(argc, argv, &cmdline);
+
+    if (cmdline.exif_filespec && STREQ(cmdline.exif_filespec, "-"))
+        /* He's got exif going to stdout, so there can be no image output */
+        ofP = NULL;
+    else
+        ofP = stdout;
+
+    displayComments = cmdline.comments;
+
+    /* Initialize the JPEG decompression object with default error handling. */
+    cinfo.err = jpeg_std_error(&jerr);
+    jpeg_create_decompress(&cinfo);
+
+    if (cmdline.trace_level == 0 && cmdline.verbose) 
+        cinfo.err->trace_level = 1;
+    else 
+        cinfo.err->trace_level = cmdline.trace_level;
+    
+    saveMarkers(&cinfo);
+
+    sourceManagerP = dsCreateSource(cmdline.input_filespec);
+
+    cinfo.src = dsJpegSourceMgr(sourceManagerP);
+
+    convertImages(ofP, cmdline, &cinfo, sourceManagerP);
+
+    jpeg_destroy_decompress(&cinfo);
+
+    if (ofP) {
+        int rc;
+        rc = fclose(ofP);
+        if (rc == EOF) 
+            pm_error("Error writing output file.  Errno = %s (%d).",
+                     strerror(errno), errno);
+    }
+
+    dsDestroySource(sourceManagerP);
+
+    free(cmdline.input_filespec);
+  
+    exit(jerr.num_warnings > 0 ? EXIT_WARNING : EXIT_SUCCESS);
+}
+
diff --git a/converter/other/pamrgbatopng.c b/converter/other/pamrgbatopng.c
new file mode 100644
index 00000000..7babf9f9
--- /dev/null
+++ b/converter/other/pamrgbatopng.c
@@ -0,0 +1,150 @@
+#include <png.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+#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/pamtodjvurle.c b/converter/other/pamtodjvurle.c
new file mode 100644
index 00000000..ae35e81d
--- /dev/null
+++ b/converter/other/pamtodjvurle.c
@@ -0,0 +1,293 @@
+/*****************************************************************************
+                               pamtodjvurle
+******************************************************************************
+  This program converts a PAM image to DjVu Color RLE format.
+  
+  By Bryan Henderson, San Jose, CA April 2004.
+
+  Contributed to the public domain by its author.
+
+  This work is inspired by Ppmtodjvurle, written by Scott Pakin
+  <scott+pbm@pakin.org> in March 2004.  Bryan took the requirements of
+  the DjVu Color RLE format and the technique for generating the format
+  (but not code) from that program.
+
+*****************************************************************************/
+#include <stdio.h>
+#include <assert.h>
+
+#include "pam.h"
+#include "pammap.h"
+#include "shhopt.h"
+
+
+struct cmdlineInfo {
+    const char * inputFilespec;
+    const char * transparent;
+    unsigned int showcolormap;
+};
+
+
+
+static void 
+parseCommandLine(int argc, 
+                 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 = malloc( 100*sizeof( optEntry ) );
+    /* Instructions to optParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+  
+    unsigned int option_def_index;
+    unsigned int transparentSpec;
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "transparent",   OPT_STRING, &cmdlineP->transparent, 
+            &transparentSpec,        0);
+    OPTENT3(0, "showcolormap",  OPT_FLAG, NULL,
+            &cmdlineP->showcolormap,        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 );
+    /* Uses and sets argc, argv, and some of *cmdline_p and others. */
+
+    if (!transparentSpec)
+        cmdlineP->transparent = "white";
+
+    /* Get the program parameters */
+
+    if (argc-1 >= 1)
+        cmdlineP->inputFilespec = argv[1];
+    else
+        cmdlineP->inputFilespec = "-";
+    
+    if (argc-1 > 1)
+        pm_error("Program takes at most one argument:  the file name.  "
+                 "You specified %d", argc-1);
+}
+
+
+
+static void
+computeColorMap(struct pam *   const pamP,
+                tuple **       const tupleArray,
+                unsigned int * const numColorsP,
+                tupletable *   const colormapP,
+                tuplehash *    const colorhashP,
+                bool           const show) {
+
+    unsigned int numColors;
+    tupletable colormap;
+
+    colormap = pnm_computetuplefreqtable(pamP, tupleArray, 0, &numColors);
+    if (numColors > 0xFF0)
+        pm_error("too many colors; "
+                 "use pnmquant to reduce to no more than %u colors", 0xFF0);
+    
+    if (show) {
+        unsigned int colorIndex;
+        fprintf(stderr, "Color map:\n");
+        fprintf(stderr, "    Index Color\n");
+        for (colorIndex = 0; colorIndex < numColors; ++colorIndex) {
+            unsigned int plane;
+            fprintf(stderr, "    %5u   ", colorIndex);
+            for (plane = 0; plane < pamP->depth; ++plane)
+                fprintf(stderr, "%3lu ", colormap[colorIndex]->tuple[plane]);
+            fprintf(stderr, "\n");
+        }
+    }
+
+    *colorhashP = pnm_computetupletablehash(pamP, colormap, numColors);
+
+    *numColorsP = numColors;
+    *colormapP  = colormap;
+}
+
+
+
+static void
+makeDjvurleHeader(FILE *       const ofP,
+                  struct pam * const pamP,
+                  unsigned int const numColors,
+                  tupletable   const colormap) {
+    
+    unsigned int colorIndex;
+
+    fprintf(ofP, "R6\n");
+    fprintf(ofP, "%d %d %d\n", pamP->width, pamP->height, numColors);
+
+    for (colorIndex = 0; colorIndex < numColors; ++colorIndex) {
+        sample red, grn, blu;
+
+        if (pamP->depth >= 3) {
+            red = colormap[colorIndex]->tuple[PAM_RED_PLANE];
+            grn = colormap[colorIndex]->tuple[PAM_GRN_PLANE];
+            blu = colormap[colorIndex]->tuple[PAM_BLU_PLANE];
+        } else
+            red = grn = blu = colormap[colorIndex]->tuple[0];
+        
+        fputc(pnm_scalesample(red, pamP->maxval, 255), ofP);
+        fputc(pnm_scalesample(grn, pamP->maxval, 255), ofP);
+        fputc(pnm_scalesample(blu, pamP->maxval, 255), ofP);
+    }
+}
+
+
+
+static bool
+colorEqual(tuple        comparand,
+           unsigned int comparandDepth,
+           tuple        comparator) {
+
+    /* comparator has depth 3 */
+
+    if (comparandDepth >= 3)
+        return (comparand[0] == comparator[0] &&
+                comparand[1] == comparator[1] &&
+                comparand[2] == comparator[2]);
+    else
+        return (comparand[0] == comparator[0] &&
+                comparand[0] == comparator[1] &&
+                comparand[0] == comparator[2]);
+}
+
+
+
+static void 
+writeRleRun(FILE *       const ofP, 
+            struct pam * const pamP,
+            tuple        const color, 
+            int          const count,
+            tuplehash    const colorhash,
+            tuple        const transcolor) {
+/*----------------------------------------------------------------------------
+  Write one DjVu Color RLE run to the file 'ofP'.  The run is 
+  'count' pixels of color 'color', using the color index given by
+  'colorhash' and assuming 'transcolor' is the transparent color.
+  
+  'transcolor' is a 3-deep tuple with the same maxval as the image.
+-----------------------------------------------------------------------------*/
+    uint32n rlevalue;         /* RLE-encoded color/valuex */
+    int index;
+
+    if (count > 0) {
+        if (colorEqual(color, pamP->depth, transcolor))
+            index = 0xFFF;
+        else {
+            int found;
+            pnm_lookuptuple(pamP, colorhash, color, &found, &index);
+            assert(found);
+        }
+        rlevalue = (index << 20) | count;
+      
+        pm_writebiglong(ofP, rlevalue);
+    }
+}
+
+
+
+static void
+writeDjvurleRow(FILE *       const ofP,
+                struct pam * const pamP,
+                tuple *      const tupleRow,
+                tuplehash    const colorhash,
+                tuple        const transcolor) {
+
+    unsigned int col;
+    unsigned int runlength;
+    tuple prevpixel;        /* Previous pixel seen */
+
+    prevpixel = tupleRow[0];
+    runlength = 0;
+    
+    for (col = 0; col < pamP->width; ++col) {
+        tuple const newpixel = tupleRow[col];      /* Current pixel color */
+        
+        if (pnm_tupleequal(pamP, newpixel, prevpixel))
+            /* This is a continuation of the current run */
+            ++runlength;
+          else {
+              /* The run is over.  Write it out and start a run of the next
+                 color.
+              */
+              writeRleRun(ofP, pamP, prevpixel, runlength, 
+                          colorhash, transcolor);
+              runlength = 1;
+              prevpixel = newpixel;
+          }
+        if (runlength >= (1<<20)-1) {
+            /* Can't make the run any longer.  Write it out and start a
+               new run.
+            */
+            writeRleRun(ofP, pamP, prevpixel, runlength, 
+                        colorhash, transcolor);
+            runlength = 1;
+        }
+    }
+    /* Write the last run we started */
+    writeRleRun(ofP, pamP, prevpixel, runlength, colorhash, transcolor);
+}
+
+
+
+int 
+main(int argc, char *argv[]) {
+
+    FILE * const rlefile = stdout;
+
+    struct cmdlineInfo cmdline;
+    FILE *ifP;                 /* Input (Netpbm) file */
+    struct pam pam;            /* Description of the image */
+    tuple ** tupleArray;       /* The image raster */
+    tupletable colormap;       /* List of all of the colors used */
+    unsigned int numColors;    /* Number of unique colors in the color map */
+    tuplehash colorhash; 
+        /* Mapping from color to index into colormap[] */
+    tuple transcolor;
+        /* Color that should be considered transparent */
+
+    pnm_init (&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    tupleArray = pnm_readpam(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+
+    transcolor = pnm_parsecolor(cmdline.transparent, pam.maxval);
+    
+    computeColorMap(&pam, tupleArray, &numColors, &colormap, &colorhash,
+                    cmdline.showcolormap);
+    
+    makeDjvurleHeader(rlefile, &pam, numColors, colormap);
+
+    /* Write the raster */
+
+    {
+        unsigned int row;
+        for (row = 0; row < pam.height; ++row)
+            writeDjvurleRow(rlefile, &pam, tupleArray[row], colorhash, 
+                            transcolor);
+    }
+    /* Clean up */
+    
+    pnm_freepamarray(tupleArray, &pam);
+    pnm_freetupletable(&pam, colormap);
+    pnm_destroytuplehash(colorhash);
+    pnm_freepamtuple(transcolor);
+    pm_close(ifP);
+
+    return 0;
+}
diff --git a/converter/other/pamtofits.c b/converter/other/pamtofits.c
new file mode 100644
index 00000000..d0552a5c
--- /dev/null
+++ b/converter/other/pamtofits.c
@@ -0,0 +1,304 @@
+/* pnmtofits.c - read a PNM image and produce a FITS file
+**
+** Copyright (C) 1989 by Wilson H. Bent (whb@hoh-2.att.com).
+**
+** 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.
+**
+** Modified by Alberto Accomazzi (alberto@cfa.harvard.edu), Dec 1, 1992.
+**
+** Added PPM input capability; the program is renamed pnmtofits.
+** This program produces files with NAXIS = 2 if input file is in PBM
+** or PGM format, and NAXIS = 3, NAXIS3 = 3 if input file is a PPM file.
+** Data is written out as either 8 bits/pixel or 16 bits/pixel integers,
+** depending on the value of maxval in the input file.
+** Flags -max, -min can be used to set DATAMAX, DATAMIN, BSCALE and BZERO
+** in the FITS header, but do not cause the data to be rescaled.
+*/
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "nstring.h"
+#include "pam.h"
+
+struct cmdlineInfo {
+    const char * inputFileName;
+    unsigned int maxSpec;
+    double max;
+    double min;
+};
+
+
+
+static void 
+parseCommandLine(int argc, 
+                 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 optParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+
+    unsigned int minSpec;
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "min",     OPT_FLOAT,
+            &cmdlineP->min,  &minSpec,                              0);
+    OPTENT3(0, "max",     OPT_FLOAT,
+            &cmdlineP->max,  &cmdlineP->maxSpec,                    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 */
+
+    /* Set some defaults the lazy way (using multiple setting of variables) */
+
+    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (!minSpec)
+        cmdlineP->min = 0.0;
+
+    if (cmdlineP->maxSpec) {
+        if (cmdlineP->max <= cmdlineP->min)
+            pm_error("-max must be greater than min (%f).  You specified %f",
+                     cmdlineP->min, cmdlineP->max);
+    }
+
+    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);
+    }
+}
+
+
+
+
+static void
+writeHeaderCard(const char * const s) {
+/*----------------------------------------------------------------------------
+   Write the string 's', padded with spaces to 80 characters.
+-----------------------------------------------------------------------------*/
+    const char * card;
+
+    asprintfN(&card, "%-80.80s", s);
+
+    fwrite(card, sizeof(card[0]), 80, stdout);
+
+    strfree(card);
+}
+
+
+
+static void
+padToMultipleOf36Cards(unsigned int const nCardsAlreadyWritten) {
+
+    /* pad with blanks cards to multiple of 36 cards */
+
+    unsigned int const npadCard = 36 - (nCardsAlreadyWritten % 36);
+    unsigned int i;
+    
+    for (i = 0; i < npadCard; ++i)
+        writeHeaderCard("");
+}
+
+
+
+static void
+writeFitsHeader(int    const bitpix,
+                int    const planes,
+                int    const cols,
+                int    const rows,
+                double const bscale,
+                double const fitsBzero,
+                double const datamax,
+                double const datamin) {
+
+    char buffer[80+1];
+    unsigned int cardsWritten;
+                
+    cardsWritten = 0;  /* initial value */
+
+    sprintf(buffer, "%-20.20s%10.10s", "SIMPLE  =", "T");
+    writeHeaderCard(buffer);
+    ++cardsWritten;
+
+    sprintf(buffer, "%-20.20s%10d", "BITPIX  =", bitpix);
+    writeHeaderCard(buffer);
+    ++cardsWritten;
+
+    sprintf(buffer, "%-20.20s%10d", "NAXIS   =", (planes == 3) ? 3 : 2);
+    writeHeaderCard(buffer);
+    ++cardsWritten;
+
+    sprintf(buffer, "%-20.20s%10d", "NAXIS1  =", cols);
+    writeHeaderCard(buffer);
+    ++cardsWritten;
+
+    sprintf(buffer, "%-20.20s%10d", "NAXIS2  =", rows);
+    writeHeaderCard(buffer);
+    ++cardsWritten;
+
+    if (planes == 3) {
+        sprintf(buffer, "%-20.20s%10d", "NAXIS3  =", 3);
+        writeHeaderCard(buffer);
+        ++cardsWritten;
+    }
+
+    sprintf(buffer, "%-18.18s%12.5E", "BSCALE  =", bscale);
+    writeHeaderCard(buffer);
+    ++cardsWritten;
+    
+    sprintf(buffer, "%-18.18s%12.5E", "BZERO   =", fitsBzero);
+    writeHeaderCard(buffer);
+    ++cardsWritten;
+
+    sprintf(buffer, "%-18.18s%12.5E", "DATAMAX =", datamax);
+    writeHeaderCard(buffer);
+    ++cardsWritten;
+
+    sprintf(buffer, "%-18.18s%12.5E", "DATAMIN =", datamin);
+    writeHeaderCard(buffer);
+    ++cardsWritten;
+
+    writeHeaderCard("HISTORY Created by pnmtofits.");
+    ++cardsWritten;
+
+    writeHeaderCard("END");
+    ++cardsWritten;
+
+    padToMultipleOf36Cards(cardsWritten);
+}
+
+
+
+static void
+writeRaster(struct pam * const pamP,
+            tuple **     const tuples,
+            unsigned int const bitpix,
+            int          const offset) {
+
+    unsigned int plane;
+
+    for (plane = 0; plane < pamP->depth; ++plane) {
+        unsigned int row;
+        for (row = 0; row < pamP->height; ++row) {
+            unsigned int col;
+            for (col = 0; col < pamP->width; ++col) {
+                if (bitpix == 16) {
+                    /* 16 bit FITS samples are signed integers */
+                    int const fitsSample =
+                        (int)tuples[row][col][plane] - offset;
+                    pm_writebigshort(stdout, (short)fitsSample);
+                } else
+                    /* 8 bit FITS samples are unsigned integers */
+                    putchar(tuples[row][col][plane] - offset);
+            }
+        }
+    }
+    {
+        /* pad raster to 36 cards with nulls */
+        unsigned int const bytesWritten =
+            pamP->height * pamP->width * pamP->depth * bitpix/8;
+        unsigned int const npad = (36*80) - (bytesWritten % (36*80));
+        unsigned int i;
+
+        for (i = 0; i < npad; ++i)
+            putchar('\0');
+    }
+}
+
+
+
+int
+main(int argc, char * argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    tuple ** tuples;
+    struct pam pam;
+    unsigned int bitpix;
+    double datamin, datamax, bscale, fitsBzero;
+    int pnmSampleOffsetFromFits;
+        /* This is what you add to a FITS sample (raster) value in order
+           to get the PNM sample value which it represents.  Note that in
+           the default case, that PNM sample value is also the FITS "physical"
+           value, but user options can change that.
+        */
+    
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    tuples = pnm_readpam(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+
+    datamin = cmdline.min;
+
+    if (cmdline.maxSpec)
+        datamax = cmdline.max;
+    else {
+        if (pam.maxval <= cmdline.min)
+            pm_error("You must specify -max greater than -min (%f).  "
+                     "max defaults to the maxval, which is %u",
+                     cmdline.min, (unsigned)pam.maxval);
+        datamax = pam.maxval;
+    }
+
+    assert(datamax > datamin);
+
+    bscale = (datamax - datamin) / pam.maxval;
+    
+    if (pam.maxval > 255) {
+        bitpix = 16;
+        /* Because 16 bit FITS samples are signed, we have to do a 2**15
+           offset to get any possible unsigned 16 bit PNM sample into a FITS
+           sample.
+        */
+        fitsBzero = 1 << 15;
+        pnmSampleOffsetFromFits = 1 << 15;
+    } else {
+        bitpix = 8;
+        fitsBzero = datamin;
+        /* Both 8 bit FITS samples and PNM samples are unsigned 8 bits, so
+           we make them identical.
+        */
+        pnmSampleOffsetFromFits = 0;
+    }
+
+    fitsBzero = datamin + pnmSampleOffsetFromFits;
+    pm_close(ifP);
+
+    writeFitsHeader(bitpix, pam.depth, pam.width, pam.height,
+                    bscale, fitsBzero, datamax, datamin);
+
+    writeRaster(&pam, tuples, bitpix, pnmSampleOffsetFromFits);
+
+    return 0;
+}
diff --git a/converter/other/pamtohdiff.c b/converter/other/pamtohdiff.c
new file mode 100644
index 00000000..0e1ff00f
--- /dev/null
+++ b/converter/other/pamtohdiff.c
@@ -0,0 +1,142 @@
+/******************************************************************************
+                                 pamtohdiff
+*******************************************************************************
+  This program creates a PAM output which a horizontal difference image of
+  the input PAM.  The samples in each row are a number to be added to to
+  the previous output row to create the next output row (and the first
+  output row is simply the same as the input row).
+
+  Because these samples must be positive and negative and PAM samples are
+  unsigned, we bias each PAM sample by the input maxval and make the output
+  maxval twice the input maxval.
+
+  By Bryan Henderson, San Jose, CA 2002.04.15.
+
+******************************************************************************/
+#include <string.h>
+#include <stdio.h>
+
+#include "pam.h"
+#include "shhopt.h"
+
+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 verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, 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 = malloc( 100*sizeof( optEntry ) );
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    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 */
+
+    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 < 1)
+        cmdlineP->inputFilespec = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFilespec = argv[1];
+    else
+        pm_error("Too many arguments.");
+}
+
+
+
+int 
+main(int argc, char *argv[]) {
+    FILE *ifP;
+    struct cmdlineInfo cmdline;
+    struct pam inpam, outpam;
+    unsigned int row;
+    tuple * inrow;
+    tuple * outrow;
+    tuple * prevrow;
+
+    pnm_init( &argc, argv );
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    outpam = inpam;
+    outpam.file = stdout;
+    outpam.format = PAM_FORMAT;
+    strcpy(outpam.tuple_type, "hdiff");
+
+    pnm_writepaminit(&outpam);
+
+    inrow = pnm_allocpamrow(&inpam);
+    outrow = pnm_allocpamrow(&outpam);
+    prevrow = pnm_allocpamrow(&inpam);
+
+    pnm_setpamrow(&inpam, prevrow, 0);
+
+    /* All arithmetic in this operation and in the reverse operation
+       (to recover the image) is done modulus the maxval+1 (the hdiff
+       PAM and the image have the same maxval) in order to produce
+       legal PAM samples (which must be in the range 0..maxval).  This
+       might seem to throw away information, but it doesn't.  Example:
+       maxval is 99.  Intensity goes from 90 in Row 0 to 10 in Row 1.
+       The difference is -80.  -80 mod 100 is 20, so 20 goes in the
+       hdiff output.  On reconstructing the image, the interpreter
+       knows the "20" can't be +20, because that would create the
+       sample 90 + 20 = 110, and violate maxval.  So it must be -80.
+       Modulus arithmetic by the interpreter effectively makes that
+       decision.  
+    */
+
+
+    /* The bias is just to make it easier to look at the output visually.
+       If you display the values as intensities, and your differences are
+       all +/- half of maxval, you can see positive transitions as bright
+       spots and negative transitions as dark spots.
+    */
+    
+    {
+        unsigned int const bias = outpam.maxval/2;
+        for (row = 0; row < inpam.height; ++row) {
+            unsigned int col;
+            pnm_readpamrow(&inpam, inrow);
+            for (col = 0; col < inpam.width; ++col) {
+            unsigned int plane;
+            for (plane = 0; plane < inpam.depth; ++plane) {
+                
+                sample const sampleValue = inrow[col][plane];
+                int const difference = sampleValue - prevrow[col][plane];
+                outrow[col][plane] = (difference + bias) % (outpam.maxval+1);
+                prevrow[col][plane] = sampleValue;
+            }
+        }
+            pnm_writepamrow(&outpam, outrow);
+        }
+    }
+    pnm_freepamrow(prevrow);
+    pnm_freepamrow(outrow);
+    pnm_freepamrow(inrow);
+
+    exit(0);
+}
+
diff --git a/converter/other/pamtohtmltbl.c b/converter/other/pamtohtmltbl.c
new file mode 100644
index 00000000..293badcb
--- /dev/null
+++ b/converter/other/pamtohtmltbl.c
@@ -0,0 +1,284 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pam.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+
+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 *transparent;  /* NULL if none */
+    unsigned int verbose;
+};
+
+
+
+
+static void
+parseCommandLine ( int argc, 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 = malloc(100*sizeof(optEntry));
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    unsigned int transparentSpec;
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "verbose",     OPT_FLAG,   NULL,                  
+            &cmdlineP->verbose,       0 );
+    OPTENT3(0, "transparent", OPT_STRING, &cmdlineP->transparent,
+            &transparentSpec,  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);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+
+    if (!transparentSpec)
+        cmdlineP->transparent = NULL;
+
+    if (argc-1 < 1)
+        cmdlineP->inputFilespec = "-";
+    else if (argc-1 == 1)
+        cmdlineP->inputFilespec = argv[1];
+    else
+        pm_error("Too many arguments.  Program takes at most one argument: "
+                 "input file name");
+}
+
+
+
+
+static void
+pripix(struct pam * const pamP,
+       tuple        const color, 
+       unsigned int const rectWidth, 
+       unsigned int const rectHeight, 
+       tuple        const transparentColor) {
+
+    if (rectWidth > 0 && rectHeight > 0) {
+        printf("<TD VALIGN=CENTER ALIGN=CENTER");
+
+        if (rectWidth != 1) 
+            printf(" COLSPAN=%d", rectWidth);
+        if (rectHeight != 1) 
+            printf(" ROWSPAN=%d", rectHeight);
+
+        if (transparentColor && 
+            !pnm_tupleequal(pamP, color,transparentColor)) {
+            /* No BGCOLOR attribute */
+        } else {
+            tuple const colorff = pnm_allocpamtuple(pamP);
+
+            unsigned int r, g, b;
+
+            pnm_scaletuple(pamP, colorff, color, 0xff);
+
+            if (pamP->depth < 3)
+                r = g = b = colorff[0];
+            else {
+                r = color[PAM_RED_PLANE];
+                g = color[PAM_GRN_PLANE];
+                b = color[PAM_BLU_PLANE];
+            }
+            printf(" BGCOLOR=#%02X%02X%02X", r, g, b);
+        }
+        printf(">");
+        printf("<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0>"
+               "<TR><TD></TD></TR></TABLE>");
+        printf("</TD>\n");
+    }
+}
+
+
+
+static void
+findSameColorRectangle(struct pam *   const pamP,
+                       tuple **       const tuples,
+                       unsigned int   const row,
+                       unsigned int   const col,
+                       unsigned int * const rectWidthP,
+                       unsigned int * const rectHeightP) {
+/*----------------------------------------------------------------------------
+   Find the largest rectangle, in the image described by 'pam' and 
+   'tuples', of uniform color, whose upper left corner is at (row, col).
+
+   Return the width and height of that rectangle as *rectWidthP
+   and *rectHeightP.
+-----------------------------------------------------------------------------*/
+    tuple const rectangleColor = tuples[row][col];
+
+    unsigned int i;
+    unsigned int mx, my;
+    unsigned int cnx, cny;
+
+    mx=0; my=0;
+    cnx = pamP->width - col; cny = pamP->height - row;
+
+    for (i=0; (!mx)||(!my); i++) {
+        int j;
+        /*fprintf(stderr,"\n[%d]",i);*/
+        for (j=0; j<=i; j++) {
+            if (!my) {
+                if (i>=cny) 
+                    my=cny;
+                else
+                    if (((!mx) || (j<mx)) && (j < cnx)) {
+                        /*fprintf(stderr,"%d/%d ",j,i);*/
+                        if (!pnm_tupleequal(pamP, tuples[row+i][col+j],
+                                            rectangleColor)) 
+                            my = i;
+                    }
+            }
+            if (!mx) {
+                if (i>=cnx) 
+                    mx=cnx;
+                else
+                    if (((!my) || (j<my)) && (j < cny)) {
+                        /*fprintf(stderr,"%d/%d ",i,j);*/
+                        if (!pnm_tupleequal(pamP, tuples[row+j][col+i],
+                                            rectangleColor)) 
+                            mx = i;
+                    }
+            }
+        }
+    }
+    *rectWidthP  = mx;
+    *rectHeightP = my;
+}
+
+
+
+static bool **
+allocOutputtedArray(unsigned int const width, unsigned int const height) {
+
+    bool ** outputted;
+    unsigned int row;
+
+    MALLOCARRAY(outputted, height);
+    if (outputted == NULL)
+        pm_error("Unable to allocate space for 'outputted' array");
+
+    for (row = 0; row < height; ++row) {
+        MALLOCARRAY(outputted[row], width);
+        if (outputted[row] == NULL)
+            pm_error("Unable to allocate space for 'outputted' array");
+    }
+    return outputted;
+}
+
+
+
+static void
+freeOutputtedArray(bool ** const outputted, unsigned int const height) {
+
+    unsigned int row;
+
+    for (row = 0; row < height; ++row)
+        free(outputted[row]);
+}
+
+
+
+static void
+markOutputted(bool ** const outputted,
+              unsigned int const upperLeftCol,
+              unsigned int const upperLeftRow,
+              unsigned int const width,
+              unsigned int const height) {
+
+    unsigned int const lowerRightCol = upperLeftCol + width;
+    unsigned int const lowerRightRow = upperLeftRow + height;
+    unsigned int row;
+    
+    for (row = upperLeftRow; row < lowerRightRow; ++row) {
+        unsigned int col;
+        for (col = upperLeftCol; col < lowerRightCol; ++col) 
+            outputted[row][col] = TRUE;
+    }
+}
+
+
+
+int
+main(int argc, char **argv) {
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    struct pam inpam;
+    tuple ** tuples;
+    int row;
+    unsigned int rectWidth, rectHeight;
+    bool ** outputted;
+    tuple transparentColor;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    tuples = pnm_readpam(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    if (cmdline.transparent) {
+        pixel transcolor;
+        transcolor = ppm_parsecolor(cmdline.transparent, inpam.maxval);
+        transparentColor = pnm_allocpamtuple(&inpam);
+        transparentColor[PAM_RED_PLANE] = PPM_GETR(transcolor);
+        transparentColor[PAM_GRN_PLANE] = PPM_GETG(transcolor);
+        transparentColor[PAM_BLU_PLANE] = PPM_GETB(transcolor);
+    } else
+        transparentColor = NULL;
+
+    outputted = allocOutputtedArray(inpam.width, inpam.height);
+
+    printf("<TABLE WIDTH=%d HEIGHT=%d BORDER=0 CELLSPACING=0 CELLPADDING=0>\n",
+           inpam.width, inpam.height);
+    for (row = 0; row < inpam.height; ++row) {
+        int col;
+        printf("<TR>\n");
+        pripix(&inpam, tuples[row][0], 1, 1, transparentColor); 
+        markOutputted(outputted, 0, row, 1, 1);
+
+        for (col = 1; col < inpam.width; ++col) {
+            if (!outputted[row][col]) {
+                findSameColorRectangle(&inpam, tuples, row, col, 
+                                       &rectWidth, &rectHeight);
+                if (cmdline.verbose)
+                    pm_message("[%d/%d] [%d/%d]",
+                               col, row, rectWidth, rectHeight);
+                pripix(&inpam, tuples[row][col], rectWidth, rectHeight, 
+                       transparentColor);
+                markOutputted(outputted, col, row, rectWidth, rectHeight);
+            }
+        }
+        printf("</TR>\n");
+    }
+    printf("</TABLE>\n");
+
+    if (transparentColor)
+        pnm_freepamtuple(transparentColor);
+    pnm_freepamarray(tuples, &inpam);
+    freeOutputtedArray(outputted, inpam.height);
+
+    exit(0);
+}
diff --git a/converter/other/pamtopfm.c b/converter/other/pamtopfm.c
new file mode 100644
index 00000000..f8fdc96b
--- /dev/null
+++ b/converter/other/pamtopfm.c
@@ -0,0 +1,304 @@
+/*****************************************************************************
+                                  pamtopfm
+******************************************************************************
+  This program converts a PAM image to PFM (Portable Float Map).
+  
+  By Bryan Henderson, San Jose, CA April 2004.
+
+  Contributed to the public domain by its author.
+
+*****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pam.h"
+#include "pm_gamma.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+
+enum endian {ENDIAN_BIG, ENDIAN_LITTLE};
+
+struct cmdlineInfo {
+    const char * inputFilespec;
+    unsigned int verbose;
+    enum endian endian;
+    float scale;
+};
+
+
+
+static enum endian machineEndianness;
+
+
+
+static void 
+parseCommandLine(int argc, 
+                 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 = malloc( 100*sizeof( optEntry ) );
+    /* Instructions to optParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+  
+    unsigned int option_def_index;
+    char * endianOpt;
+    unsigned int endianSpec, scaleSpec;
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "endian",   OPT_STRING, &endianOpt, &endianSpec,        0);
+    OPTENT3(0, "scale",    OPT_FLOAT,  &cmdlineP->scale, &scaleSpec,   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 );
+    /* Uses and sets argc, argv, and some of *cmdline_p and others. */
+
+    if (endianSpec) {
+        if (streq(endianOpt, "big"))
+            cmdlineP->endian = ENDIAN_BIG;
+        else if (streq(endianOpt, "little"))
+            cmdlineP->endian = ENDIAN_LITTLE;
+        else
+            pm_error("Invalid value '%s' for -endian.  "
+                     "Must be 'big' or 'little'.", endianOpt);
+    } else
+        cmdlineP->endian = machineEndianness;
+
+    if (!scaleSpec) {
+        cmdlineP->scale = 1.0;
+    }
+    if (cmdlineP->scale == 0.0)
+        pm_error("Scale factor cannot be zero");
+
+    /* Get the program parameters */
+
+    if (argc-1 >= 1)
+        cmdlineP->inputFilespec = argv[1];
+    else
+        cmdlineP->inputFilespec = "-";
+    
+    if (argc-1 > 1)
+        pm_error("Program takes at most one argument:  the file name.  "
+                 "You specified %d", argc-1);
+}
+
+
+
+static enum endian
+thisMachineEndianness(void) {
+/*----------------------------------------------------------------------------
+   Endianness is a component of the format in which a machine represents
+   a number in memory or a register.  It is the only component of the format
+   that varies among typical machines.
+
+   Big endianness is the natural format.  In this format, if an integer is
+   4 bytes, to be stored at memory address 100-103, the most significant 
+   byte goes at 100, the next most significant at 101, and the least
+   significant byte at 103.  This is natural because it matches the way
+   humans read and write numbers.  I.e. 258 is stored as 0x00000102.
+
+   Little endian is extremely common because it is used by IA32.  In the
+   example above, the least significant byte goes first, so 258 would be
+   stored as 0x02010000.
+
+   You can extend this concept to floating point numbers, even though the
+   bytes of a floating point number differ by more than significance.
+-----------------------------------------------------------------------------*/
+    short const testNumber = 0x0001;
+
+    unsigned char * const storedNumber = (unsigned char *)&testNumber;
+    enum endian endianness;
+    
+    if (storedNumber[0] == 0x01)
+        endianness = ENDIAN_LITTLE;
+    else
+        endianness = ENDIAN_BIG;
+
+    return endianness;
+}
+
+
+
+typedef struct {
+    unsigned char bytes[4];
+} pfmSample;
+
+
+
+static void
+floatToPfmSample(float       const input,
+                 pfmSample *       outputP,
+                 enum endian const pfmEndianness) {
+/*----------------------------------------------------------------------------
+   Type converter
+-----------------------------------------------------------------------------*/
+    if (machineEndianness == pfmEndianness) {
+        *(float *)outputP->bytes = input;
+    } else {
+        unsigned char reversed[sizeof(pfmSample)];
+        unsigned int i, j;
+
+        *(float *)reversed = input;
+        
+        for (i = 0, j = sizeof(pfmSample)-1; 
+             i < sizeof(pfmSample); 
+             ++i, --j)
+            
+            outputP->bytes[i] = reversed[j];
+    }
+}
+
+
+
+struct pfmHeader {
+    unsigned int width;
+    unsigned int height;
+    bool color;
+    float scaleFactor;
+    enum endian endian;
+};
+
+
+static void
+writePfmHeader(FILE *           const ofP,
+               struct pfmHeader const pfmHeader) {
+
+    const char * const magic = pfmHeader.color ? "PF" : "Pf";
+    float const scaleFactorEndian = 
+        pfmHeader.endian == ENDIAN_BIG ? 
+            pfmHeader.scaleFactor :
+            - pfmHeader.scaleFactor;
+
+    fprintf(ofP, "%s\n",    magic);
+    fprintf(ofP, "%u %u\n", pfmHeader.width, pfmHeader.height);
+    fprintf(ofP, "%f\n",    scaleFactorEndian);
+}
+
+
+
+static void
+writePfmRow(struct pam * const pamP,
+            FILE *       const ofP,
+            unsigned int const pfmRow,
+            unsigned int const pfmSamplesPerRow,
+            tuplen **    const tuplenArray,
+            enum endian  const endian,
+            float        const scaleFactor,
+            pfmSample *  const pfmRowBuffer) {
+
+    int const row = pamP->height - pfmRow - 1;
+    tuplen * const tuplenRow = tuplenArray[row];
+
+    int col;
+    int pfmCursor;
+    int rc;
+
+    pfmCursor = 0;  /* initial value */
+
+    for (col = 0; col < pamP->width; ++col) {
+        /* The order of planes (R, G, B) is the same in PFM as in PAM. */
+        unsigned int plane;
+        for (plane = 0; plane < pamP->depth; ++plane) {
+            pfmSample val;
+            floatToPfmSample(tuplenRow[col][plane] * scaleFactor, 
+                             &val, endian);
+            pfmRowBuffer[pfmCursor++] = val;
+        }
+    }
+    assert(pfmCursor == pfmSamplesPerRow);
+
+    rc = fwrite(pfmRowBuffer, sizeof(pfmSample), pfmSamplesPerRow, ofP);
+    if (rc != pfmSamplesPerRow)
+        pm_error("Unable to write to output file in the middle of row %d", 
+                 pfmRow);
+
+
+}
+
+
+
+static struct pfmHeader
+makePfmHeader(const struct pam * const pamP,
+              float              const scaleFactor,
+              enum endian        const endian) {
+    
+    struct pfmHeader pfmHeader;
+    
+    pfmHeader.width  = pamP->width;
+    pfmHeader.height = pamP->height;
+
+    if (strncmp(pamP->tuple_type, "RGB", 3) == 0)
+        pfmHeader.color = TRUE;
+    else if (strncmp(pamP->tuple_type, "GRAYSCALE", 9) == 0)
+        pfmHeader.color = FALSE;
+    else if (strncmp(pamP->tuple_type, "BLACKANDWHITE", 13) == 0)
+        pfmHeader.color = FALSE;
+    else
+        pm_error("Invalid PAM input.  Tuple type is '%s'.  "
+                 "We understand only RGB* and GRAYSCALE*", pamP->tuple_type);
+
+    pfmHeader.scaleFactor = scaleFactor;
+    pfmHeader.endian = endian;
+        
+    return pfmHeader;
+}
+
+
+int
+main(int argc, char **argv ) {
+
+    struct cmdlineInfo cmdline;
+    FILE* ifP;
+    struct pam pam;
+    pfmSample * pfmRowBuffer;
+    unsigned int pfmSamplesPerRow;
+    unsigned int pfmRow;
+    tuplen ** tuplenArray;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    machineEndianness = thisMachineEndianness();
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    tuplenArray = pnm_readpamn(ifP, &pam, sizeof(pam));
+
+    writePfmHeader(stdout, 
+                   makePfmHeader(&pam, cmdline.scale, cmdline.endian));
+
+    pfmSamplesPerRow = pam.width * pam.depth;
+    
+    MALLOCARRAY_NOFAIL(pfmRowBuffer, pfmSamplesPerRow);
+
+    /* PFMs are upside down like BMPs */
+    for (pfmRow = 0; pfmRow < pam.height; ++pfmRow)
+        writePfmRow(&pam, stdout, pfmRow, pfmSamplesPerRow,
+                    tuplenArray, cmdline.endian, cmdline.scale,
+                    pfmRowBuffer);
+
+    pnm_freepamarrayn(tuplenArray, &pam);
+    free(pfmRowBuffer);
+    
+    pm_close(stdout);
+    pm_close(pam.file);
+
+    return 0;
+}
diff --git a/converter/other/pamtopnm.c b/converter/other/pamtopnm.c
new file mode 100644
index 00000000..cc1164da
--- /dev/null
+++ b/converter/other/pamtopnm.c
@@ -0,0 +1,155 @@
+/*----------------------------------------------------------------------------
+                               pamtopnm
+------------------------------------------------------------------------------
+  Part of the Netpbm package.
+
+  Convert PAM images to PBM, PGM, or PPM (i.e. PNM)
+
+  By Bryan Henderson, San Jose CA 2000.08.05
+
+  Contributed to the public domain by its author 2000.08.05.
+-----------------------------------------------------------------------------*/
+
+#include <string.h>
+
+#include "pam.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+
+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 */
+};
+
+
+static void
+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.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def;
+        /* Instructions to 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 OPTENTRY */
+    OPTENT3(0,   "assume",     OPT_FLAG,   NULL, &cmdlineP->assume,         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);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 == 0) 
+        cmdlineP->inputFilespec = "-";
+    else if (argc-1 != 1)
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
+    else
+        cmdlineP->inputFilespec = argv[1];
+}
+
+
+
+static void
+validateTupleType(struct pam const inpam, 
+                  int        const assumeTupleType) {
+/*----------------------------------------------------------------------------
+   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
+   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
+   planes and add to the right end of the tuple type to explain them.
+
+   If Callers specified 'assumeTupleType', we're even more liberal.
+-----------------------------------------------------------------------------*/
+    if (assumeTupleType) {
+        /* User says tuple type is appropriate regardless of tuple_type. */
+    } else {
+        if (inpam.depth >= 1 && 
+            strncmp(inpam.tuple_type, "BLACKANDWHITE", 
+                    sizeof("BLACKANDWHITE")-1) == 0) {
+            /* It's a PBMable image */
+        } else if (inpam.depth >= 1 && 
+                   strncmp(inpam.tuple_type, "GRAYSCALE",
+                           sizeof("GRAYSCALE")-1) == 0) {
+            /* It's a PGMable image */
+        } else if (inpam.depth >= 3 &&
+                   strncmp(inpam.tuple_type, "RGB", sizeof("RGB")-1) == 0) {
+            /* It's a PPMable image */
+        } else 
+            pm_error("PAM image does not have a depth and tuple_type "
+                     "consistent with a PNM image."
+                     "According to its "
+                     "header, depth is %d and tuple_type is '%s'.  "
+                     "Use the -assume option to convert anyway.",
+                     inpam.depth, inpam.tuple_type);
+    }
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE* ifP;
+    struct pam inpam;   /* Input PAM image */
+    struct pam outpam;  /* Output PNM image */
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+
+    validateTupleType(inpam, cmdline.assume);
+
+    outpam = inpam;
+    outpam.file = stdout;
+    
+    if (inpam.depth < 3) {
+        outpam.depth = 1;
+        if (inpam.maxval == 1)
+            outpam.format = PBM_FORMAT;
+        else 
+            outpam.format = PGM_FORMAT;
+    } else {
+        outpam.depth = 3;
+        outpam.format = PPM_FORMAT;
+    }
+
+    pnm_writepaminit(&outpam);
+
+    {
+        tuple *tuplerow;
+        
+        tuplerow = pnm_allocpamrow(&inpam);      
+        { 
+            int row;
+            
+            for (row = 0; row < inpam.height; row++) {
+                pnm_readpamrow(&inpam, tuplerow);
+                pnm_writepamrow(&outpam, tuplerow);
+            }
+        }
+        pnm_freepamrow(tuplerow);        
+    }
+    return 0;
+}
diff --git a/converter/other/pamtosvg/Makefile b/converter/other/pamtosvg/Makefile
new file mode 100644
index 00000000..7f9c3e30
--- /dev/null
+++ b/converter/other/pamtosvg/Makefile
@@ -0,0 +1,55 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/pamtosvg
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+BINARIES = 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 \
+
+MERGE_OBJECTS = \
+	pamtosvg.o2 \
+	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 \
+
+OBJECTS = $(PAMTOSVG_OBJECTS)
+
+MERGEBINARIES = $(BINARIES)
+
+all: $(BINARIES)
+
+include $(SRCDIR)/Makefile.common
+
+pamtosvg: $(PAMTOSVG_OBJECTS) $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $(PAMTOSVG_OBJECTS) \
+	  $(shell $(LIBOPT) $(NETPBMLIB)) \
+	  $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
diff --git a/converter/other/pamtosvg/README b/converter/other/pamtosvg/README
new file mode 100644
index 00000000..a06b71a5
--- /dev/null
+++ b/converter/other/pamtosvg/README
@@ -0,0 +1,109 @@
+The core of this program is derived from Martin Weber's
+(martweb@gmx.net) Autotrace.  Bryan Henderson adapted it to Netpbm in 
+February 2006.
+
+Much of the Autotrace code has been rewritten to be easier to read and match
+Netpbm coding style.
+
+Pieces of Autotrace that duplicate other Netpbm programs or just don't fit
+the Netpbm philosophy have been removed.  In particular, Autotrace has the
+ability to take formats other than Netpbm formats for input, to despeckle
+the image before tracing, and to quantize colors before tracing.  Pamtosvg
+has none of that.
+
+Pamtosvg uses libnetpbm to read the input image, process the command line,
+manage memory, and do several other minor things.  Autotrace has its own
+code for those things.
+
+Autotrace uses a shmaltzy trick to deal with open outlines.  There is a
+piece of the program that divides an outline at its corners and then creates
+a curve for the pieces between every two corners.  For an open outline,
+there are segments of the outline at each end that are not between two
+corners.  One piece of code finds the corners, and another computes the
+curves between them.  
+
+In order to use the closed outline code for the open outline case,
+Autotrace includes a dummy corner at the start of the outline in the
+list of corners.  The curve-finding code then has a special case for
+the segment after the last corner.  Pamtosvg uses a cleaner approach.
+The corner list is an actual list of corners -- there is no dummy
+corner.  The curve-finding code has two special cases for open
+outlines -- one for the segment before the first corner, and one for
+the segment after the last corner.
+
+
+STRATEGY
+--------
+
+Autotrace is capable of many more vector graphics output formats
+besides SVG.  The basic curve tracing is the same for all; it just has
+output formatting modules.  Netpbm ought to be able to generate those
+formats as well.  SVG is just the beginning.
+
+Of course, having a program that generates multiple output formats based
+on command line options is not the Netpbm way to approach it.  A pure
+traditional Netpbm approach would be to have a converter between PAM
+and each of the vector graphics formats.
+
+That isn't practical because of the information that gets lost when you
+convert from vector to raster form, and also because 99% of the logic
+in converting between PAM and a vector graphics format is the same for
+all the vector graphics formats.
+
+Therefore, the strategy is to adopt a single vector graphics format
+and use it as the common intermediate format.  Right now, it looks
+like SVG would be a good choice for that.  However, it may turn out to
+be better to create a vector graphics format specially for Netpbm.
+The reason for that is that an intermediate Netpbm format has a rather
+different requirement from all these other formats -- it isn't meant
+to be transmitted or stored, but it is meant to be easy for a
+programmer to work with.
+
+We need a program to go the other way -- to convert from SVG to PAM.
+I.e. a curve drawing program.  The Ppmdraw program does this kind of
+curve drawing (in fact, a Ppmdraw script can be considered a vector
+graphics format).  Ppmdraw itself might not be adaptable, but the
+library routines it uses are probably all we need to convert SVG to
+PAM.
+
+The Pamtosvg code should be reworked to use a libnetpbm tuple array
+instead of its at_bitmap_type for the raster.
+
+Nobody has any plans to do any of this work.  I document the strategy
+only so that if someone decides to do some work, he can go in the
+right direction.
+
+
+COPYRIGHT CONSIDERATIONS
+------------------------
+
+Bryan took the code and has distributed it under a copyright license
+granted to him, as a member of the public, by the authors.  That
+license is the GNU Lesser Public License Version 2.1.  All the authors
+offer that same license for Pamtosvg to the public.  A copy of it is
+in the Netpbm doc/ directory.
+
+
+CREDITS
+-------
+
+Autotrace's source code listed the following as contributors to it:
+
+Martin Weber <martweb@gmx.net>
+Bernhard Herzog (Postscript, svg and sk export filter) 
+Ian MacPhedran (xfig export filter) 
+Martin Kroeker (bugfixes) 
+Tobias Polzin (bugfixes) 
+Kevin O'Gorman (Shockwave support) 
+MenTaLguY (png import filter)
+Peter Cucka (bugfixes)
+Enrico Persiani (emf export) 
+Johannes Schindelin (Magick import filter)
+Masatake YAMATO (library, help with cvs)
+Steffen Politzky (dxf export)
+David A. Bartold (part of despeckle)
+Han-Wen Nienhuys (rpm-spec file)
+R. P. C. Rodgers (man page)
+Allen Barnett (improved emf export)
+Andrew Elia (dr2d export filter)
+Ralf Stubner (bugfixes about pstoedit usage)
diff --git a/converter/other/pamtosvg/autotrace.c b/converter/other/pamtosvg/autotrace.c
new file mode 100644
index 00000000..e9902669
--- /dev/null
+++ b/converter/other/pamtosvg/autotrace.c
@@ -0,0 +1,220 @@
+/* autotrace.c --- Autotrace API
+
+  Copyright (C) 2000, 2001, 2002 Martin Weber
+
+  The author can be contacted at <martweb@gmx.net>
+
+  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. */
+
+#include "mallocvar.h"
+
+#include "autotrace.h"
+#include "exception.h"
+
+#include "fit.h"
+#include "bitmap.h"
+#include "spline.h"
+
+#include "image-header.h"
+#include "image-proc.h"
+#include "thin-image.h"
+
+
+#define AT_DEFAULT_DPI 72
+
+at_fitting_opts_type *
+at_fitting_opts_new(void)
+{
+  at_fitting_opts_type * opts;
+  MALLOCVAR_NOFAIL(opts);
+  return opts;
+}
+
+at_fitting_opts_type *
+at_fitting_opts_copy (at_fitting_opts_type * original)
+{
+  at_fitting_opts_type * new_opts;
+  if (original == NULL)
+    return NULL;
+
+  new_opts = at_fitting_opts_new ();
+  *new_opts = *original;
+  new_opts->backgroundSpec = original->backgroundSpec;
+  new_opts->background_color = original->background_color;
+  return new_opts;
+}
+
+void 
+at_fitting_opts_free(at_fitting_opts_type * opts)
+{
+  free(opts);
+}
+
+at_output_opts_type *
+at_output_opts_new(void)
+{
+  at_output_opts_type * opts;
+  MALLOCVAR_NOFAIL(opts);
+  opts->dpi          = AT_DEFAULT_DPI;
+  return opts;
+}
+
+at_output_opts_type *
+at_output_opts_copy(at_output_opts_type * original)
+{
+  at_output_opts_type * opts =  at_output_opts_new();
+  *opts = *original;
+  return opts;
+}
+
+void
+at_output_opts_free(at_output_opts_type * opts)
+{
+  free(opts);
+}
+
+/* at_splines_new_full modifies its 'bitmap' argument
+   when it does the thin_image thing.
+*/
+at_spline_list_array_type * 
+at_splines_new_full(at_bitmap_type *       const bitmap,
+                    at_fitting_opts_type * const opts,
+                    at_msg_func                  msg_func, 
+                    void *                 const msg_data,
+                    at_progress_func             notify_progress,
+                    void *                 const progress_data,
+                    at_testcancel_func           test_cancel,
+                    void *                 const testcancel_data) {
+
+    at_spline_list_array_type * retval;
+    image_header_type image_header;
+    pixel_outline_list_type pixelOutlineList;
+    at_exception_type exp;
+    distance_map_type distanceMap;
+    bool haveDistMap;
+
+    exp = at_exception_new(msg_func, msg_data);
+
+    image_header.width  = at_bitmap_get_width(bitmap);
+    image_header.height = at_bitmap_get_height(bitmap);
+
+    if (opts->centerline) {
+        if (opts->preserve_width) {
+            /* Preserve line width prior to thinning. */
+            bool const paddedTrue = true;
+            distanceMap = new_distance_map(*bitmap, 255, paddedTrue, &exp);
+            haveDistMap = true;
+        } else
+            haveDistMap = false;
+        thin_image(bitmap, opts->backgroundSpec, opts->background_color, &exp);
+    } else
+        haveDistMap = false;
+
+    if (at_exception_got_fatal(&exp))
+        retval = NULL;
+    else {
+        if (opts->centerline) {
+            pixel background_color;
+
+            if (opts->backgroundSpec) 
+                background_color = opts->background_color;
+            else
+                PPM_ASSIGN(background_color, 255, 255, 255);
+            
+            pixelOutlineList =
+                find_centerline_pixels(*bitmap, background_color, 
+                                       notify_progress, progress_data,
+                                       test_cancel, testcancel_data, &exp);
+        } else
+            pixelOutlineList =
+                find_outline_pixels(*bitmap,
+                                    opts->backgroundSpec,
+                                    opts->background_color, 
+                                    notify_progress, progress_data,
+                                    test_cancel, testcancel_data, &exp);
+
+        if (at_exception_got_fatal(&exp) ||
+            (test_cancel && test_cancel(testcancel_data)))
+            retval = NULL;
+        else {
+            at_spline_list_array_type * splinesP;
+        
+            MALLOCVAR_NOFAIL(splinesP); 
+            fit_outlines_to_splines(pixelOutlineList, opts,
+                                    haveDistMap ? &distanceMap : NULL,
+                                    image_header.width,
+                                    image_header.height,
+                                    &exp,
+                                    notify_progress, progress_data,
+                                    test_cancel, testcancel_data,
+                                    splinesP);
+
+            if (at_exception_got_fatal(&exp) ||
+                (test_cancel && test_cancel(testcancel_data)))
+                retval = NULL;
+            else {
+                if (notify_progress)
+                    notify_progress(1.0, progress_data);
+
+                retval = splinesP;
+            }
+            free_pixel_outline_list(&pixelOutlineList);
+        }
+        if (haveDistMap)
+            free_distance_map(&distanceMap);
+    }
+    return retval;
+}
+
+
+
+void 
+at_splines_write(at_output_write_func                  outputWriter,
+                 FILE *                          const writeto,
+                 at_output_opts_type *           const optsArg,
+                 at_spline_list_array_type *     const splinesP,
+                 at_msg_func                           msgFunc,
+                 void *                          const msgData) {
+
+    at_output_opts_type * optsP;
+    bool newOpts;
+    int llx, lly, urx, ury;
+    llx = 0;
+    lly = 0;
+    urx = splinesP->width;
+    ury = splinesP->height;
+    
+    if (optsArg == NULL) {
+        newOpts = true;
+        optsP   = at_output_opts_new();
+    } else {
+        newOpts = false;
+        optsP   = optsArg;
+    }
+    (*outputWriter)(writeto, "DUMMYFILENAME",
+                    llx, lly, urx, ury, optsP, *splinesP,
+                    msgFunc, msgData);
+    if (newOpts)
+        at_output_opts_free(optsP);
+}
+
+
+
+void 
+at_splines_free(at_spline_list_array_type * const splines) {
+
+    free_spline_list_array(splines);
+    free(splines);
+}
diff --git a/converter/other/pamtosvg/autotrace.h b/converter/other/pamtosvg/autotrace.h
new file mode 100644
index 00000000..2ac81a08
--- /dev/null
+++ b/converter/other/pamtosvg/autotrace.h
@@ -0,0 +1,258 @@
+/* autotrace.h --- Autotrace API
+
+  Copyright (C) 2000, 2001, 2002 Martin Weber
+
+  The author can be contacted at <martweb@gmx.net>
+
+  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. */
+
+#ifndef AUTOTRACE_H
+#define AUTOTRACE_H
+
+#include <stdio.h>
+
+#include "point.h"
+#include "pm_c_util.h"
+#include "ppm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* ===================================================================== *
+ * Typedefs
+ * ===================================================================== */
+
+typedef struct _at_fitting_opts_type at_fitting_opts_type;
+typedef struct _at_input_opts_type   at_input_opts_type;
+typedef struct _at_output_opts_type  at_output_opts_type;
+typedef struct _at_bitmap_type at_bitmap_type;
+typedef struct _at_spline_type at_spline_type;
+typedef struct _at_spline_list_type at_spline_list_type;
+typedef struct _at_spline_list_array_type at_spline_list_array_type;
+
+/* Third degree is the highest we deal with.  */
+typedef enum _at_polynomial_degree
+{
+  AT_LINEARTYPE = 1, 
+  AT_QUADRATICTYPE = 2, 
+  AT_CUBICTYPE = 3, 
+  AT_PARALLELELLIPSETYPE = 4,
+  AT_ELLIPSETYPE = 5, 
+  AT_CIRCLETYPE = 6 
+  /* not the real number of points to define a
+     circle but to distinguish between a cubic spline */
+} at_polynomial_degree;
+
+/* A Bezier spline can be represented as four points in the real plane:
+   a starting point, ending point, and two control points.  The
+   curve always lies in the convex hull defined by the four points.  It
+   is also convenient to save the divergence of the spline from the
+   straight line defined by the endpoints.  */
+struct _at_spline_type
+{
+  float_coord v[4];	/* The control points.  */
+  at_polynomial_degree degree;
+  float linearity;
+};
+
+/* Each outline in a character is typically represented by many
+   splines.  So, here is a list structure for that:  */
+struct _at_spline_list_type
+{
+  at_spline_type *data;
+  unsigned length;
+  bool clockwise;
+  pixel color;
+  bool open;
+};
+
+/* Each character is in general made up of many outlines. So here is one
+   more list structure.  */
+struct _at_spline_list_array_type
+{
+  at_spline_list_type *data;
+  unsigned length;
+
+  /* splines bbox */
+  unsigned short height, width;
+  
+  /* the values for following members are inherited from 
+     at_fitting_opts_type */
+  bool backgroundSpec;
+  pixel background_color;
+  bool centerline;
+  bool preserve_width;
+  float width_weight_factor;
+
+};
+
+
+/* Fitting option.
+   With using at_fitting_opts_doc macro, the description of 
+   each option could be get. e.g. at_fitting_opts_doc(background_color) */
+struct _at_fitting_opts_type {
+    bool backgroundSpec;
+    pixel background_color;
+    float corner_always_threshold;
+    unsigned corner_surround;
+    float corner_threshold;
+    float error_threshold;
+    unsigned filter_iterations;
+    float line_reversion_threshold;
+    float line_threshold;
+    bool remove_adjacent_corners;
+    unsigned tangent_surround;
+    bool centerline;
+    bool preserve_width;
+    float width_weight_factor;
+};
+
+struct _at_output_opts_type
+{
+  int dpi;			/* DPI is used only in MIF output.*/
+};
+
+struct _at_bitmap_type
+{
+  unsigned short height;
+  unsigned short width;
+  unsigned char *bitmap;
+  unsigned int np;
+};
+
+typedef enum _at_msg_type
+{
+  AT_MSG_FATAL = 1,
+  AT_MSG_WARNING
+} at_msg_type;
+
+typedef
+void (* at_msg_func) (const char * const msg,
+                      at_msg_type  const msg_type,
+                      void *       const client_data);
+
+typedef 
+int (*at_output_write_func) (FILE *                          const file,
+                             const char *                    const name,
+                             int                             const llx,
+                             int                             const lly, 
+                             int                             const urx,
+                             int                             const ury,
+                             at_output_opts_type *           const opts,
+                             at_spline_list_array_type       const shape,
+                             at_msg_func                           msg_func, 
+                             void *                          const msg_data);
+
+/*
+ * Progress handler typedefs
+ * 0.0 <= percentage <= 1.0
+ */
+typedef
+void (*at_progress_func) (float const percentage,
+                           void *  const client_data);
+
+/*
+ * Test cancel
+ * Return true if auto-tracing should be stopped.
+ */
+typedef
+bool (*at_testcancel_func) (void * const client_data);
+
+/* ===================================================================== *
+ * Functions
+ * ===================================================================== */
+
+/* --------------------------------------------------------------------- *
+ * Fitting option related
+ *
+ * TODO: internal data access, copy
+ * --------------------------------------------------------------------- */
+at_fitting_opts_type * at_fitting_opts_new(void);
+at_fitting_opts_type * at_fitting_opts_copy (at_fitting_opts_type * original); 
+void at_fitting_opts_free(at_fitting_opts_type * opts);
+
+/* TODO: Gettextize */
+#define at_fitting_opts_doc(opt) _(at_doc__##opt)
+
+/* --------------------------------------------------------------------- *
+ * Output option related
+ *
+ * TODO: internal data access
+ * --------------------------------------------------------------------- */
+at_output_opts_type * at_output_opts_new(void);
+at_output_opts_type * at_output_opts_copy(at_output_opts_type * original);
+void at_output_opts_free(at_output_opts_type * opts);
+
+/* --------------------------------------------------------------------- *
+ * Spline related
+ *
+ * TODO: internal data access
+ * --------------------------------------------------------------------- */
+/* at_splines_new_full
+
+   args:
+
+   NOTIFY_PROGRESS is called repeatedly inside at_splines_new_full
+   to notify the progress of the execution. This might be useful for 
+   interactive applications. NOTIFY_PROGRESS is called following 
+   format:
+
+   NOTIFY_PROGRESS (percentage, progress_data);
+
+   test_cancel is called repeatedly inside at_splines_new_full
+   to test whether the execution is canceled or not.
+   If test_cancel returns TRUE, execution of at_splines_new_full
+   is stopped as soon as possible and returns NULL. If test_cancel 
+   returns FALSE, nothing happens. test_cancel  is called following
+   format:
+
+   TEST_CANCEL (testcancel_data);
+   
+   NULL is valid value for notify_progress and/or test_cancel if 
+   you don't need to know the progress of the execution and/or 
+   cancel the execution */ 
+
+at_spline_list_array_type * 
+at_splines_new_full(at_bitmap_type *       const bitmap,
+                    at_fitting_opts_type * const opts,
+                    at_msg_func                  msg_func, 
+                    void *                 const msg_data,
+                    at_progress_func             notify_progress,
+                    void *                 const progress_data,
+                    at_testcancel_func           test_cancel,
+                    void *                 const testcancel_data);
+
+void 
+at_splines_write(at_output_write_func                  output_writer,
+                 FILE *                          const writeto,
+                 at_output_opts_type *           const opts,
+                 at_spline_list_array_type *     const splines,
+                 at_msg_func                           msg_func,
+                 void *                          const msg_data);
+
+void
+at_splines_free(at_spline_list_array_type * const splines);
+
+
+/* --------------------------------------------------------------------- *
+ * Misc
+ * --------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/converter/other/pamtosvg/bitmap.c b/converter/other/pamtosvg/bitmap.c
new file mode 100644
index 00000000..1a00e748
--- /dev/null
+++ b/converter/other/pamtosvg/bitmap.c
@@ -0,0 +1,116 @@
+/* bitmap.c: operations on bitmaps. */
+
+#include <string.h>
+
+#include "mallocvar.h"
+
+#include "bitmap.h"
+
+at_bitmap_type *
+at_bitmap_new(unsigned short width,
+              unsigned short height,
+              unsigned int planes) {
+
+    at_bitmap_type * bitmap;
+
+    MALLOCVAR_NOFAIL(bitmap); 
+
+    *bitmap = at_bitmap_init(NULL, width, height, planes);
+
+    return bitmap;
+}
+
+
+
+at_bitmap_type *
+at_bitmap_copy(at_bitmap_type * src)
+{
+    at_bitmap_type * dist;
+    unsigned short width, height, planes;
+
+    width  = at_bitmap_get_width(src);
+    height = at_bitmap_get_height(src);
+    planes = at_bitmap_get_planes(src);
+    
+    dist = at_bitmap_new(width, height, planes);
+    memcpy(dist->bitmap, 
+           src->bitmap, 
+           width * height * planes * sizeof(unsigned char));
+    return dist;
+}
+
+
+
+at_bitmap_type
+at_bitmap_init(unsigned char * area,
+               unsigned short width,
+               unsigned short height,
+               unsigned int planes) {
+
+    at_bitmap_type bitmap;
+    
+    if (area)
+        bitmap.bitmap = area;
+    else {
+        if (width * height == 0)
+            bitmap.bitmap = NULL;
+        else {
+            MALLOCARRAY(bitmap.bitmap, width * height * planes);
+            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));
+        }
+    }
+    
+    bitmap.width  = width;
+    bitmap.height = height;
+    bitmap.np     =  planes;
+
+    return bitmap;  
+}
+
+void 
+at_bitmap_free (at_bitmap_type * bitmap)
+{
+    free_bitmap (bitmap);
+    free(bitmap);
+}
+
+unsigned short
+at_bitmap_get_width (at_bitmap_type * bitmap)
+{
+    return bitmap->width;
+}
+
+unsigned short
+at_bitmap_get_height (at_bitmap_type * bitmap)
+{
+    return bitmap->height;
+}
+
+unsigned short
+at_bitmap_get_planes (at_bitmap_type * bitmap)
+{
+    return bitmap->np;
+}
+
+
+
+bitmap_type
+new_bitmap (unsigned short width, unsigned short height)
+{
+    return at_bitmap_init(NULL,width,height,1);
+}
+
+/* Free the storage that is allocated for a bitmap.  On the other hand,
+   the bitmap might not have any storage allocated for it if it is zero
+   in either dimension; in that case, don't free it.  */
+
+void
+free_bitmap (bitmap_type *b)
+{
+    if (b->bitmap != NULL)
+        free (b->bitmap);
+}
diff --git a/converter/other/pamtosvg/bitmap.h b/converter/other/pamtosvg/bitmap.h
new file mode 100644
index 00000000..7334f138
--- /dev/null
+++ b/converter/other/pamtosvg/bitmap.h
@@ -0,0 +1,53 @@
+/* bitmap.h: definition for a bitmap type.  No packing is done by
+   default; each pixel is represented by an entire byte.  Among other
+   things, this means the type can be used for both grayscale and binary
+   images. */
+
+#ifndef BITMAP_H
+#define BITMAP_H
+
+#include "autotrace.h"
+#include <stdio.h>
+
+/* at_ prefix removed version */
+typedef at_bitmap_type bitmap_type;
+#define BITMAP_PLANES(b)          AT_BITMAP_PLANES(b)
+#define BITMAP_BITS(b)            AT_BITMAP_BITS(b)  
+#define BITMAP_WIDTH(b)           AT_BITMAP_WIDTH(b)  
+#define BITMAP_HEIGHT(b)          AT_BITMAP_HEIGHT(b) 
+
+/* This is the pixel at [ROW,COL].  */
+#define BITMAP_PIXEL(b, row, col)					\
+  ((b).bitmap + ((row) * (b).width + (col)) * (b).np)
+
+#define BITMAP_VALID_PIXEL(b, row, col)					\
+   	((row) < (b).height && (col) < (b).width)
+
+/* Allocate storage for the bits, set them all to white, and return an
+   initialized structure.  */
+extern bitmap_type new_bitmap (unsigned short width, unsigned short height);
+
+/* Free that storage.  */
+extern void free_bitmap (bitmap_type *);
+
+
+at_bitmap_type * at_bitmap_new(unsigned short width,
+			       unsigned short height,
+			       unsigned int planes);
+at_bitmap_type * at_bitmap_copy(at_bitmap_type * src);
+
+/* We have to export functions that supports internal datum 
+   access. Such functions might be useful for 
+   at_bitmap_new user. */
+unsigned short at_bitmap_get_width (at_bitmap_type * bitmap);
+unsigned short at_bitmap_get_height (at_bitmap_type * bitmap);
+unsigned short at_bitmap_get_planes (at_bitmap_type * bitmap);
+void at_bitmap_free (at_bitmap_type * bitmap);
+
+at_bitmap_type
+at_bitmap_init(unsigned char * area,
+	       unsigned short width,
+	       unsigned short height,
+	       unsigned int planes);
+
+#endif /* not BITMAP_H */
diff --git a/converter/other/pamtosvg/curve.c b/converter/other/pamtosvg/curve.c
new file mode 100644
index 00000000..cc8aeb59
--- /dev/null
+++ b/converter/other/pamtosvg/curve.c
@@ -0,0 +1,314 @@
+/* curve.c: operations on the lists of pixels and lists of curves.
+
+   The code was partially derived from limn.
+
+   Copyright (C) 1992 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+#include "mallocvar.h"
+
+#include "logreport.h"
+#include "curve.h"
+
+
+static float_coord
+int_to_real_coord(pm_pixelcoord const int_coord) {
+/*----------------------------------------------------------------------------
+  Turn an integer point into a real one.
+-----------------------------------------------------------------------------*/
+    float_coord real_coord;
+
+    real_coord.x = int_coord.col;
+    real_coord.y = int_coord.row;
+    real_coord.z = 0.0;
+    
+    return real_coord;
+}
+
+
+
+/* Return an entirely empty curve.  */
+
+curve_type
+new_curve (void)
+{
+  curve_type curve;
+  MALLOCVAR_NOFAIL(curve);
+  curve->point_list = NULL;
+  CURVE_LENGTH (curve) = 0;
+  CURVE_CYCLIC (curve) = false;
+  CURVE_START_TANGENT (curve) = CURVE_END_TANGENT (curve) = NULL;
+  PREVIOUS_CURVE (curve) = NEXT_CURVE (curve) = NULL;
+
+  return curve;
+}
+
+
+/* Don't copy the points or tangents, but copy everything else.  */
+
+curve_type
+copy_most_of_curve (curve_type old_curve)
+{
+  curve_type curve = new_curve ();
+
+  CURVE_CYCLIC (curve) = CURVE_CYCLIC (old_curve);
+  PREVIOUS_CURVE (curve) = PREVIOUS_CURVE (old_curve);
+  NEXT_CURVE (curve) = NEXT_CURVE (old_curve);
+
+  return curve;
+}
+
+
+/* The length of CURVE will be zero if we ended up not being able to fit
+   it (which in turn implies a problem elsewhere in the program, but at
+   any rate, we shouldn't try here to free the nonexistent curve).  */
+
+void
+free_curve (curve_type curve)
+{
+  if (CURVE_LENGTH (curve) > 0)
+    free (curve->point_list);
+  if (CURVE_START_TANGENT (curve))
+    free (CURVE_START_TANGENT (curve));
+  if (CURVE_END_TANGENT (curve))
+    free (CURVE_END_TANGENT (curve));
+}
+
+
+void
+append_point(curve_type  const curve,
+             float_coord const coord) {
+
+    CURVE_LENGTH(curve)++;
+    REALLOCARRAY_NOFAIL(curve->point_list, CURVE_LENGTH(curve));
+    LAST_CURVE_POINT(curve) = coord;
+    /* The t value does not need to be set.  */
+}
+
+
+void
+append_pixel(curve_type    const curve,
+             pm_pixelcoord const coord) {
+
+    append_point(curve, int_to_real_coord(coord));
+}
+
+
+/* Print a curve in human-readable form.  It turns out we never care
+   about most of the points on the curve, and so it is pointless to
+   print them all out umpteen times.  What matters is that we have some
+   from the end and some from the beginning.  */
+
+#define NUM_TO_PRINT 3
+
+#define LOG_CURVE_POINT(c, p, print_t)					\
+  do									\
+    {									\
+      LOG2 ("(%.3f,%.3f)", CURVE_POINT (c, p).x, CURVE_POINT (c, p).y);	\
+      if (print_t)							\
+        LOG1 ("/%.2f", CURVE_T (c, p));					\
+    }									\
+  while (0)
+
+void
+log_curve (curve_type curve, bool print_t)
+{
+  unsigned this_point;
+
+  if (!log_file) return;
+
+  LOG1 ("curve id = %lx:\n", (unsigned long) curve);
+  LOG1 ("  length = %u.\n", CURVE_LENGTH (curve));
+  if (CURVE_CYCLIC (curve))
+    LOG ("  cyclic.\n");
+
+  /* It should suffice to check just one of the tangents for being null
+     -- either they both should be, or neither should be.  */
+  if (CURVE_START_TANGENT (curve) != NULL)
+    LOG4 ("  tangents = (%.3f,%.3f) & (%.3f,%.3f).\n",
+          CURVE_START_TANGENT (curve)->dx, CURVE_START_TANGENT (curve)->dy,
+          CURVE_END_TANGENT (curve)->dx, CURVE_END_TANGENT (curve)->dy);
+
+  LOG ("  ");
+
+  /* If the curve is short enough, don't use ellipses.  */
+  if (CURVE_LENGTH (curve) <= NUM_TO_PRINT * 2)
+    {
+      for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++)
+        {
+          LOG_CURVE_POINT (curve, this_point, print_t);
+          LOG (" ");
+
+          if (this_point != CURVE_LENGTH (curve) - 1
+              && (this_point + 1) % NUM_TO_PRINT == 0)
+            LOG ("\n  ");
+        }
+    }
+  else
+    {
+      for (this_point = 0;
+           this_point < NUM_TO_PRINT && this_point < CURVE_LENGTH (curve);
+           this_point++)
+        {
+          LOG_CURVE_POINT (curve, this_point, print_t);
+          LOG (" ");
+        }
+
+      LOG ("...\n   ...");
+
+      for (this_point = CURVE_LENGTH (curve) - NUM_TO_PRINT;
+           this_point < CURVE_LENGTH (curve);
+           this_point++)
+        {
+          LOG (" ");
+          LOG_CURVE_POINT (curve, this_point, print_t);
+        }
+    }
+
+  LOG (".\n");
+}
+
+
+/* Like `log_curve', but write the whole thing.  */
+
+void
+log_entire_curve (curve_type curve)
+{
+  unsigned this_point;
+
+  if (!log_file) return;
+
+  LOG1 ("curve id = %lx:\n", (unsigned long) curve);
+  LOG1 ("  length = %u.\n", CURVE_LENGTH (curve));
+  if (CURVE_CYCLIC (curve))
+    LOG ("  cyclic.\n");
+
+  /* It should suffice to check just one of the tangents for being null
+     -- either they both should be, or neither should be.  */
+  if (CURVE_START_TANGENT (curve) != NULL)
+    LOG4 ("  tangents = (%.3f,%.3f) & (%.3f,%.3f).\n",
+          CURVE_START_TANGENT (curve)->dx, CURVE_START_TANGENT (curve)->dy,
+          CURVE_END_TANGENT (curve)->dx, CURVE_END_TANGENT (curve)->dy);
+
+  LOG (" ");
+
+  for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++)
+    {
+      LOG (" ");
+      LOG_CURVE_POINT (curve, this_point, true);
+      /* Compiler warning `Condition is always true' can be ignored */
+    }
+
+  LOG (".\n");
+}
+
+
+/* Return an initialized but empty curve list.  */
+
+curve_list_type
+new_curve_list (void)
+{
+  curve_list_type curve_list;
+
+  curve_list.length = 0;
+  curve_list.data = NULL;
+
+  return curve_list;
+}
+
+
+/* Free a curve list and all the curves it contains.  */
+
+void
+free_curve_list(curve_list_type * const curve_list) {
+
+  unsigned this_curve;
+
+  for (this_curve = 0; this_curve < curve_list->length; this_curve++)
+    {
+      free_curve (curve_list->data[this_curve]);
+      free (curve_list->data[this_curve]);
+    }
+
+  /* If the character was empty, it won't have any curves.  */
+  if (curve_list->data != NULL)
+    free (curve_list->data);
+}
+
+
+/* Add an element to a curve list.  */
+
+void
+append_curve (curve_list_type *curve_list, curve_type curve)
+{
+  curve_list->length++;
+  REALLOCARRAY_NOFAIL(curve_list->data, curve_list->length);
+  curve_list->data[curve_list->length - 1] = curve; }
+
+
+/* Return an initialized but empty curve list array.  */
+
+curve_list_array_type
+new_curve_list_array (void)
+{
+  curve_list_array_type curve_list_array;
+
+  CURVE_LIST_ARRAY_LENGTH (curve_list_array) = 0;
+  curve_list_array.data = NULL;
+
+  return curve_list_array;
+}
+
+
+/* Free a curve list array and all the curve lists it contains.  */
+
+void
+free_curve_list_array(const curve_list_array_type * const curve_list_array,
+                      at_progress_func                    notify_progress, 
+                      void *                        const client_data) {
+
+  unsigned this_list;
+
+  for (this_list = 0; this_list < CURVE_LIST_ARRAY_LENGTH(*curve_list_array);
+       this_list++) {
+      if (notify_progress)
+          notify_progress(((float)this_list)/
+                          (CURVE_LIST_ARRAY_LENGTH(*curve_list_array) *
+                           (float)3.0)+(float)0.666 ,
+                          client_data);
+      free_curve_list(&CURVE_LIST_ARRAY_ELT (*curve_list_array, this_list));
+  }
+  
+  /* If the character was empty, it won't have any curves.  */
+  if (curve_list_array->data != NULL)
+      free(curve_list_array->data);
+}
+
+
+/* Add an element to a curve list array.  */
+
+void
+append_curve_list(curve_list_array_type * const curve_list_array,
+                  curve_list_type         const curve_list) {
+
+  CURVE_LIST_ARRAY_LENGTH (*curve_list_array)++;
+  REALLOCARRAY_NOFAIL(curve_list_array->data,
+                      CURVE_LIST_ARRAY_LENGTH(*curve_list_array));
+  LAST_CURVE_LIST_ARRAY_ELT (*curve_list_array) = curve_list;
+}
+
+
+
diff --git a/converter/other/pamtosvg/curve.h b/converter/other/pamtosvg/curve.h
new file mode 100644
index 00000000..db3cc682
--- /dev/null
+++ b/converter/other/pamtosvg/curve.h
@@ -0,0 +1,160 @@
+/* curve.h: data structures for the conversion from pixels to splines. */
+
+#ifndef CURVE_H
+#define CURVE_H
+
+#include "autotrace.h"
+#include "point.h"
+#include "vector.h"
+
+/* We are simultaneously manipulating two different representations of
+   the same outline: one based on (x,y) positions in the plane, and one
+   based on parametric splines.  (We are trying to match the latter to
+   the former.)  Although the original (x,y)'s are pixel positions,
+   i.e., integers, after filtering they are reals.  */
+
+typedef struct {
+    float_coord coord;
+    float       t;
+} point_type;
+
+
+
+struct curve {
+/*----------------------------------------------------------------------------
+  An ordered list of contiguous points in the raster, with no corners
+  in it.  I.e. something that could reasonably be fit to a spline.
+-----------------------------------------------------------------------------*/
+    point_type *   point_list;
+    unsigned       length;
+    bool           cyclic;
+    vector_type *  start_tangent;
+    vector_type *  end_tangent;
+    struct curve * previous;
+    struct curve * next;
+};
+
+typedef struct curve * curve_type;
+
+/* Get at the coordinates and the t values.  */
+#define CURVE_POINT(c, n) ((c)->point_list[n].coord)
+#define LAST_CURVE_POINT(c) ((c)->point_list[(c)->length-1].coord)
+#define CURVE_T(c, n) ((c)->point_list[n].t)
+#define LAST_CURVE_T(c) ((c)->point_list[(c)->length-1].t)
+
+/* This is the length of `point_list'.  */
+#define CURVE_LENGTH(c)  ((c)->length)
+
+/* A curve is ``cyclic'' if it didn't have any corners, after all, so
+   the last point is adjacent to the first.  */
+#define CURVE_CYCLIC(c)  ((c)->cyclic)
+
+/* If the curve is cyclic, the next and previous points should wrap
+   around; otherwise, if we get to the end, we return CURVE_LENGTH and
+   -1, respectively.  */
+#define CURVE_NEXT(c, n)						\
+  ((n) + 1 >= CURVE_LENGTH (c)						\
+  ? CURVE_CYCLIC (c) ? ((n) + 1) % CURVE_LENGTH (c) : CURVE_LENGTH (c)	\
+  : (n) + 1)
+#define CURVE_PREV(c, n)						\
+  ((signed int) (n) - 1 < 0							\
+  ? CURVE_CYCLIC (c) ? (signed int) CURVE_LENGTH (c) + (signed int) (n) - 1 : -1\
+  : (signed int) (n) - 1)
+
+/* The tangents at the endpoints are computed using the neighboring curves.  */
+#define CURVE_START_TANGENT(c) ((c)->start_tangent)
+#define CURVE_END_TANGENT(c) ((c)->end_tangent)
+#define PREVIOUS_CURVE(c) ((c)->previous)
+#define NEXT_CURVE(c) ((c)->next)
+
+
+/* Return an entirely empty curve.  */
+extern curve_type new_curve (void);
+
+/* Return a curve the same as C, except without any points.  */
+extern curve_type copy_most_of_curve (curve_type c);
+
+/* Free the memory C uses.  */
+extern void free_curve (curve_type c);
+
+/* Append the point P to the end of C's list.  */
+void
+append_pixel(curve_type    const c,
+             pm_pixelcoord const p);
+
+/* Like `append_pixel', for a point in real coordinates.  */
+extern void append_point (curve_type c, float_coord p);
+
+/* Write some or all, respectively, of the curve C in human-readable
+   form to the log file, if logging is enabled.  */
+extern void log_curve (curve_type c, bool print_t);
+extern void log_entire_curve (curve_type c);
+
+/* Display the curve C online, if displaying is enabled.  */
+extern void display_curve (curve_type);
+
+
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   An ordered list of contiguous curves of a particular color.
+-----------------------------------------------------------------------------*/
+    curve_type * data;
+    unsigned     length;
+    bool         clockwise;
+    pixel        color;
+    bool         open;
+        /* The curve list does not form a closed shape;  i.e. the last
+           curve doesn't end where the first one starts.
+        */
+} curve_list_type;
+
+/* Number of curves in the list.  */
+#define CURVE_LIST_LENGTH(c_l)  ((c_l).length)
+#define CURVE_LIST_EMPTY(c_l) ((c_l).length == 0)
+
+/* Access the individual curves.  */
+#define CURVE_LIST_ELT(c_l, n) ((c_l).data[n])
+#define LAST_CURVE_LIST_ELT(c_l) ((c_l).data[CURVE_LIST_LENGTH (c_l) - 1])
+
+/* Says whether the outline that this curve list represents moves
+   clockwise or counterclockwise.  */
+#define CURVE_LIST_CLOCKWISE(c_l) ((c_l).clockwise)
+
+
+extern curve_list_type new_curve_list (void);
+
+void
+free_curve_list(curve_list_type * const curve_list);
+
+extern void append_curve (curve_list_type *, curve_type);
+
+/* And a character is a list of outlines.  I named this
+   `curve_list_array_type' because `curve_list_list_type' seemed pretty
+   monstrous.  */
+typedef struct
+{
+  curve_list_type *data;
+  unsigned length;
+} curve_list_array_type;
+
+/* Turns out we can use the same definitions for lists of lists as for
+   just lists.  But we define the usual names, just in case.  */
+#define CURVE_LIST_ARRAY_LENGTH CURVE_LIST_LENGTH
+#define CURVE_LIST_ARRAY_ELT CURVE_LIST_ELT
+#define LAST_CURVE_LIST_ARRAY_ELT LAST_CURVE_LIST_ELT
+
+curve_list_array_type
+new_curve_list_array(void);
+
+void
+free_curve_list_array(const curve_list_array_type * const curve_list_array,
+                      at_progress_func                    notify_progress, 
+                      void *                        const client_data);
+
+void
+append_curve_list(curve_list_array_type * const curve_list_array,
+                  curve_list_type         const curve_list);
+
+#endif
+
diff --git a/converter/other/pamtosvg/epsilon-equal.c b/converter/other/pamtosvg/epsilon-equal.c
new file mode 100644
index 00000000..46d630c5
--- /dev/null
+++ b/converter/other/pamtosvg/epsilon-equal.c
@@ -0,0 +1,19 @@
+/* epsilon-equal.c: define a error resist compare. */
+
+#include <math.h>
+
+#include "epsilon-equal.h"
+
+/* Numerical errors sometimes make a floating point number just slightly
+   larger or smaller than its true value.  When it matters, we need to
+   compare with some tolerance, REAL_EPSILON, defined in kbase.h.  */
+
+bool
+epsilon_equal(float const v1,
+              float const v2) {
+
+    return
+        v1 == v2		       /* Usually they'll be exactly equal, anyway.  */
+        || fabs(v1 - v2) <= REAL_EPSILON;
+}
+
diff --git a/converter/other/pamtosvg/epsilon-equal.h b/converter/other/pamtosvg/epsilon-equal.h
new file mode 100644
index 00000000..fa0437cd
--- /dev/null
+++ b/converter/other/pamtosvg/epsilon-equal.h
@@ -0,0 +1,20 @@
+/* epsilon-equal.h: define an error resist compare. */
+
+#ifndef EPSILON_EQUAL_H
+#define EPSILON_EQUAL_H
+
+#include "pm_c_util.h"
+
+/* Says whether V1 and V2 are within REAL_EPSILON of each other.
+   Fixed-point arithmetic would be better, to guarantee machine
+   independence, but it's so much more painful to work with.  The value
+   here is smaller than can be represented in either a `fix_word' or a
+   `scaled_num', so more precision than this will be lost when we
+   output, anyway.  */
+bool epsilon_equal(float const v1,
+                   float const v2);
+
+#define REAL_EPSILON 0.00001
+
+#endif /* not EPSILON_EQUAL_H */
+
diff --git a/converter/other/pamtosvg/exception.c b/converter/other/pamtosvg/exception.c
new file mode 100644
index 00000000..43761936
--- /dev/null
+++ b/converter/other/pamtosvg/exception.c
@@ -0,0 +1,55 @@
+
+#include "exception.h"
+
+at_exception_type
+at_exception_new(at_msg_func       client_func,
+                 void *      const client_data) {
+
+    at_exception_type e;
+
+    e.msg_type = 0;
+    e.client_func = client_func;
+    e.client_data = client_data;
+    
+    return e;
+}
+
+
+
+bool
+at_exception_got_fatal(at_exception_type * const exception) {
+
+    return (exception->msg_type == AT_MSG_FATAL);
+}
+
+
+
+void
+at_exception_fatal(at_exception_type * const exception,
+                   const char *        const message) {
+
+    if (exception) {
+        exception->msg_type = AT_MSG_FATAL;
+        if (exception->client_func) {
+            exception->client_func(message, 
+                                   AT_MSG_FATAL,
+                                   exception->client_data);
+        }
+    }
+}
+
+
+
+void
+at_exception_warning(at_exception_type * const exception,
+                     const char *        const message) {
+
+    if (exception) {
+        exception->msg_type = AT_MSG_WARNING;
+        if (exception->client_func) {
+            exception->client_func(message, 
+                                   AT_MSG_WARNING,
+                                   exception->client_data);
+        }
+    }
+}
diff --git a/converter/other/pamtosvg/exception.h b/converter/other/pamtosvg/exception.h
new file mode 100644
index 00000000..113f65e6
--- /dev/null
+++ b/converter/other/pamtosvg/exception.h
@@ -0,0 +1,43 @@
+/* exception.h: facility to handle error in autotrace */
+
+#ifndef AT_EXCEPTION_H
+#define AT_EXCEPTION_H 
+
+#include "autotrace.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Protocol:
+   If a function raises a FATAL(including propagation), 
+   the function must release resources allocated by the 
+   function itself.
+*/
+typedef struct _at_exception_type at_exception_type;
+struct _at_exception_type {
+    at_msg_type msg_type;
+    at_msg_func client_func;
+    void **     client_data;
+};
+
+at_exception_type
+at_exception_new(at_msg_func       client_func,
+                 void *      const client_data);
+
+bool
+at_exception_got_fatal(at_exception_type * const exception);
+
+void
+at_exception_fatal(at_exception_type * const exception,
+                   const char *        const message);
+
+void
+at_exception_warning(at_exception_type * const exception,
+                     const char *        const message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/converter/other/pamtosvg/fit.c b/converter/other/pamtosvg/fit.c
new file mode 100644
index 00000000..bcda033f
--- /dev/null
+++ b/converter/other/pamtosvg/fit.c
@@ -0,0 +1,1923 @@
+/* fit.c: turn a bitmap representation of a curve into a list of splines.
+    Some of the ideas, but not the code, comes from the Phoenix thesis.
+   See README for the reference.
+
+   The code was partially derived from limn.
+
+   Copyright (C) 1992 Free Software Foundation, Inc.
+
+   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, 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.  */
+
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+
+#include "autotrace.h"
+#include "fit.h"
+#include "message.h"
+#include "logreport.h"
+#include "spline.h"
+#include "vector.h"
+#include "curve.h"
+#include "pxl-outline.h"
+#include "epsilon-equal.h"
+
+#define CUBE(x) ((x) * (x) * (x))
+
+/* We need to manipulate lists of array indices.  */
+
+typedef struct index_list
+{
+  unsigned *data;
+  unsigned length;
+} index_list_type;
+
+/* The usual accessor macros.  */
+#define GET_INDEX(i_l, n)  ((i_l).data[n])
+#define INDEX_LIST_LENGTH(i_l)  ((i_l).length)
+#define GET_LAST_INDEX(i_l)  ((i_l).data[INDEX_LIST_LENGTH (i_l) - 1])
+
+static void append_index (index_list_type *, unsigned);
+static void free_index_list (index_list_type *);
+static index_list_type new_index_list (void);
+static void remove_adjacent_corners (index_list_type *, unsigned, bool,
+                     at_exception_type * exception);
+static void filter (curve_type, fitting_opts_type *);
+static void find_vectors
+  (unsigned, pixel_outline_type, vector_type *, vector_type *, unsigned);
+static float find_error (curve_type, spline_type, unsigned *,
+               at_exception_type * exception);
+static vector_type find_half_tangent (curve_type, bool start, unsigned *, unsigned);
+static void find_tangent (curve_type, bool, bool, unsigned);
+static void remove_knee_points (curve_type, bool);
+static void set_initial_parameter_values (curve_type);
+static float distance (float_coord, float_coord);
+
+
+static pm_pixelcoord
+real_to_int_coord(float_coord const real_coord) {
+/*----------------------------------------------------------------------------
+  Turn an real point into a integer one.
+-----------------------------------------------------------------------------*/
+
+    pm_pixelcoord int_coord;
+
+    int_coord.col = ROUND(real_coord.x);
+    int_coord.row = ROUND(real_coord.y);
+    
+    return int_coord;
+}
+
+
+static void
+appendCorner(index_list_type *  const cornerListP,
+             unsigned int       const pixelSeq,
+             pixel_outline_type const outline,
+             float              const angle,
+             char               const logType) {
+
+    pm_pixelcoord const coord = O_COORDINATE(outline, pixelSeq);
+
+    append_index(cornerListP, pixelSeq);
+    LOG4(" (%d,%d)%c%.3f", coord.col, coord.row, logType, angle);
+}
+
+
+
+static void
+lookAheadForBetterCorner(pixel_outline_type  const outline,
+                         unsigned int        const basePixelSeq,
+                         float               const baseCornerAngle,
+                         unsigned int        const cornerSurround,
+                         unsigned int        const cornerAlwaysThreshold,
+                         unsigned int *      const highestExaminedP,
+                         float *             const bestCornerAngleP,
+                         unsigned int *      const bestCornerIndexP,
+                         index_list_type *   const equallyGoodListP,
+                         index_list_type *   const cornerListP,
+                         at_exception_type * const exceptionP) {
+/*----------------------------------------------------------------------------
+   'basePixelSeq' is the sequence position within 'outline' of a pixel
+   that has a sufficiently small angle (to wit 'baseCornerAngle') to
+   be a corner.  We look ahead in 'outline' for an even better one.
+   We'll look up to 'cornerSurround' pixels ahead.
+
+   We return the pixel sequence of the best corner we find (which could
+   be the base) as *bestCornerIndexP.  Its angle is *bestCornerAngleP.
+
+   We return as *highestExaminedP the pixel sequence of the last pixel
+   we examined in our search (Caller can use this information to avoid
+   examining them again).
+
+   And we have this really dirty side effect: If we encounter any
+   corner whose angle is less than 'cornerAlwaysThreshold', we add
+   that to the list *cornerListP along the way.
+-----------------------------------------------------------------------------*/
+    float bestCornerAngle;
+    unsigned bestCornerIndex;
+    index_list_type equallyGoodList;
+    unsigned int q;
+    unsigned int i;
+
+    bestCornerIndex = basePixelSeq;     /* initial assumption */
+    bestCornerAngle = baseCornerAngle;    /* initial assumption */
+    
+    equallyGoodList = new_index_list();
+    
+    q = basePixelSeq;
+    i = basePixelSeq + 1;  /* Start with the next pixel */
+    
+    while (i < bestCornerIndex + cornerSurround &&
+           i < O_LENGTH(outline) &&
+           !at_exception_got_fatal(exceptionP)) {
+
+        vector_type inVector, outVector;
+        float cornerAngle;
+        
+        /* Check the angle.  */
+
+        q = i % O_LENGTH(outline);
+        find_vectors(q, outline, &inVector, &outVector, cornerSurround);
+        cornerAngle = Vangle(inVector, outVector, exceptionP);
+        if (!at_exception_got_fatal(exceptionP)) {
+            /* Perhaps the angle is sufficiently small that we want to
+               consider this a corner, even if it's not the best
+               (unless we've already wrapped around in the search, in
+               which case we have already added the corner, and we
+               don't want to add it again).
+            */
+            if (cornerAngle <= cornerAlwaysThreshold && q >= basePixelSeq)
+                appendCorner(cornerListP, q, outline, cornerAngle, '\\');
+
+            if (epsilon_equal(cornerAngle, bestCornerAngle))
+                append_index(&equallyGoodList, q);
+            else if (cornerAngle < bestCornerAngle) {
+                bestCornerAngle = cornerAngle;
+                /* We want to check `cornerSurround' pixels beyond the
+                   new best corner.
+                */
+                i = bestCornerIndex = q;
+                free_index_list(&equallyGoodList);
+                equallyGoodList = new_index_list();
+            }
+            ++i;
+        }
+    }
+    *bestCornerAngleP = bestCornerAngle;
+    *bestCornerIndexP = bestCornerIndex;
+    *equallyGoodListP = equallyGoodList;
+    *highestExaminedP = q;
+}
+
+
+
+static void
+establishCornerSearchLimits(pixel_outline_type  const outline,
+                            fitting_opts_type * const fittingOptsP,
+                            unsigned int *      const firstP,
+                            unsigned int *      const lastP) {
+/*----------------------------------------------------------------------------
+   Determine where in the outline 'outline' we should look for corners.
+-----------------------------------------------------------------------------*/
+    assert(O_LENGTH(outline) >= 1);
+    assert(O_LENGTH(outline) - 1 >= fittingOptsP->corner_surround);
+
+    *firstP = 0;
+    *lastP  = O_LENGTH(outline) - 1;
+    if (outline.open) {
+        *firstP += fittingOptsP->corner_surround;
+        *lastP  -= fittingOptsP->corner_surround;
+    }
+}
+
+
+
+static void
+removeAdjacent(index_list_type *   const cornerListP,
+               pixel_outline_type  const outline,
+               fitting_opts_type * const fittingOptsP,
+               at_exception_type * const exception) {
+               
+    /* We never want two corners next to each other, since the
+       only way to fit such a ``curve'' would be with a straight
+       line, which usually interrupts the continuity dreadfully.
+    */
+
+    if (INDEX_LIST_LENGTH(*cornerListP) > 0)
+        remove_adjacent_corners(
+            cornerListP,
+            O_LENGTH(outline) - (outline.open ? 2 : 1),
+            fittingOptsP->remove_adjacent_corners,
+            exception);
+}
+
+
+
+static index_list_type
+find_corners(pixel_outline_type  const outline,
+             fitting_opts_type * const fittingOptsP,
+             at_exception_type * const exceptionP) {
+
+    /* We consider a point to be a corner if (1) the angle defined by
+       the `corner_surround' points coming into it and going out from
+       it is less than `corner_threshold' degrees, and no point within
+       `corner_surround' points has a smaller angle; or (2) the angle
+       is less than `corner_always_threshold' degrees.
+    */
+    unsigned int p;
+    unsigned int firstPixelSeq, lastPixelSeq;
+    index_list_type cornerList;
+
+    cornerList = new_index_list();
+
+    if (O_LENGTH(outline) <= fittingOptsP->corner_surround * 2 + 1)
+        return cornerList;
+
+    establishCornerSearchLimits(outline, fittingOptsP,
+                                &firstPixelSeq, &lastPixelSeq);
+    
+    /* Consider each pixel on the outline in turn.  */
+    for (p = firstPixelSeq; p <= lastPixelSeq;) {
+        vector_type inVector, outVector;
+        float cornerAngle;
+
+        /* Check if the angle is small enough.  */
+        find_vectors(p, outline, &inVector, &outVector,
+                     fittingOptsP->corner_surround);
+        cornerAngle = Vangle(inVector, outVector, exceptionP);
+        if (at_exception_got_fatal(exceptionP))
+            goto cleanup;
+
+        if (fabs(cornerAngle) <= fittingOptsP->corner_threshold) {
+            /* We want to keep looking, instead of just appending the
+               first pixel we find with a small enough angle, since there
+               might be another corner within `corner_surround' pixels, with
+               a smaller angle.  If that is the case, we want that one.
+
+               If we come across a corner that is just as good as the
+               best one, we should make it a corner, too.  This
+               happens, for example, at the points on the `W' in some
+               typefaces, where the "points" are flat.
+            */
+            float bestCornerAngle;
+            unsigned bestCornerIndex;
+            index_list_type equallyGoodList;
+            unsigned int q;
+
+            if (cornerAngle <= fittingOptsP->corner_always_threshold)
+                /* The angle is sufficiently small that we want to
+                   consider this a corner, even if it's not the best.
+                */
+                appendCorner(&cornerList, p, outline, cornerAngle, '\\');
+
+            lookAheadForBetterCorner(outline, p, cornerAngle,
+                                     fittingOptsP->corner_surround,
+                                     fittingOptsP->corner_always_threshold,
+                                     &q,
+                                     &bestCornerAngle, &bestCornerIndex,
+                                     &equallyGoodList,
+                                     &cornerList,
+                                     exceptionP);
+
+            if (at_exception_got_fatal(exceptionP))
+                goto cleanup;
+
+            /* `q' is the index of the last point lookAhead checked.
+               He added the corner if `bestCornerAngle' is less than
+               `corner_always_threshold'.  If we've wrapped around, we
+               added the corner on the first pass.  Otherwise, we add
+               the corner now.
+            */
+            if (bestCornerAngle > fittingOptsP->corner_always_threshold
+                && bestCornerIndex >= p) {
+
+                unsigned int j;
+                
+                appendCorner(&cornerList, bestCornerIndex,
+                             outline, bestCornerAngle, '/');
+                
+                for (j = 0; j < INDEX_LIST_LENGTH (equallyGoodList); ++j)
+                    appendCorner(&cornerList, GET_INDEX(equallyGoodList, j),
+                                 outline, bestCornerAngle, '@');
+            }
+            free_index_list(&equallyGoodList);
+
+            /* If we wrapped around in our search, we're done;
+               otherwise, we move on to the pixel after the highest
+               one we just checked.
+            */
+            p = (q < p) ? O_LENGTH(outline) : q + 1;
+        } else
+            ++p;
+    }
+    removeAdjacent(&cornerList, outline, fittingOptsP, exceptionP);
+
+cleanup:  
+    return cornerList;
+}
+
+
+
+static void
+makeOutlineOneCurve(pixel_outline_type const outline,
+                    curve_list_type *  const curveListP) {
+/*----------------------------------------------------------------------------
+   Add to *curveListP a single curve that represents the outline 'outline'.
+-----------------------------------------------------------------------------*/
+    curve_type curve;
+    unsigned int pixelSeq;
+
+    curve = new_curve();
+    
+    for (pixelSeq = 0; pixelSeq < O_LENGTH(outline); ++pixelSeq)
+        append_pixel(curve, O_COORDINATE(outline, pixelSeq));
+    
+    if (curveListP->open)
+        CURVE_CYCLIC(curve) = false;
+    else
+        CURVE_CYCLIC(curve) = true;
+    
+    /* Make it a one-curve cycle */
+    NEXT_CURVE(curve)     = curve;
+    PREVIOUS_CURVE(curve) = curve;
+
+    append_curve(curveListP, curve);
+}
+
+
+
+static void
+addCurveStartingAtCorner(pixel_outline_type const outline,
+                         index_list_type    const cornerList,
+                         unsigned int       const cornerSeq,
+                         curve_list_type *  const curveListP) {
+
+    unsigned int const cornerPixelSeq = GET_INDEX(cornerList, cornerSeq);
+    
+    unsigned int lastPixelSeq;
+    curve_type curve;
+    unsigned int pixelSeq;
+    
+    if (cornerSeq + 1 >= cornerList.length)
+        /* No more corners, so we go through the end of the outline. */
+        lastPixelSeq = O_LENGTH(outline) - 1;
+    else
+        /* Go through the next corner */
+        lastPixelSeq = GET_INDEX(cornerList, cornerSeq + 1);
+    
+    curve = new_curve();
+
+    for (pixelSeq = cornerPixelSeq; pixelSeq <= lastPixelSeq; ++pixelSeq)
+        append_pixel(curve, O_COORDINATE(outline, pixelSeq));
+    
+    {
+        /* Add curve to end of chain */
+        if (!CURVE_LIST_EMPTY(*curveListP)) {
+            curve_type const previousCurve = LAST_CURVE_LIST_ELT(*curveListP);
+            NEXT_CURVE(previousCurve) = curve;
+            PREVIOUS_CURVE(curve)     = previousCurve;
+        }
+    }
+    append_curve(curveListP, curve);
+}
+
+
+
+static void
+divideOutlineWithCorners(pixel_outline_type const outline,
+                         index_list_type    const cornerList,
+                         curve_list_type *  const curveListP) {
+/*----------------------------------------------------------------------------
+   Divide the outline 'outline' into curves at the corner points
+   'cornerList' and add each curve to *curveListP.
+
+   Each curve contains the corners at each end.
+
+   The last curve is special.  It consists of the pixels (inclusive)
+   between the last corner and the end of the outline, and the
+   beginning of the outline and the first corner.
+
+   We link the curves in a chain.  If the outline (and therefore the
+   curve list) is closed, the chain is a cycle of all the curves.  If
+   it is open, the chain is a linear chain of all the curves except
+   the last one (the one that goes from the last corner to the first
+   corner).
+
+   Assume there is at least one corner.
+-----------------------------------------------------------------------------*/
+    unsigned int const firstCurveSeq = CURVE_LIST_LENGTH(*curveListP);
+        /* Index in curve list of the first curve we add */
+    unsigned int cornerSeq;
+
+    assert(cornerList.length > 0);
+
+    if (outline.open) {
+        /* Start with a curve that contains the point up to the first
+           corner
+        */
+        curve_type curve;
+        unsigned int pixelSeq;
+        
+        curve = new_curve();
+
+        for (pixelSeq = 0; pixelSeq <= GET_INDEX(cornerList, 0); ++pixelSeq)
+            append_pixel(curve, O_COORDINATE(outline, pixelSeq));
+
+        append_curve(curveListP, curve);
+    } else
+        /* We'll pick up the pixels before the first corner at the end */
+
+    /* Add to the list a curve that starts at each corner and goes
+       through the following corner, or the end of the outline if
+       there is no following corner.  Do it in order of the corners.
+    */
+    for (cornerSeq = 0; cornerSeq < cornerList.length; ++cornerSeq)
+        addCurveStartingAtCorner(outline, cornerList, cornerSeq, curveListP);
+
+    if (!outline.open) {
+        /* Come around to the start of the curve list -- add the pixels
+           before the first corner to the last curve, and chain the last
+           curve to the first one.
+        */
+        curve_type const firstCurve =
+            CURVE_LIST_ELT(*curveListP, firstCurveSeq);
+        curve_type const lastCurve  =
+            LAST_CURVE_LIST_ELT(*curveListP);
+
+        unsigned int pixelSeq;
+
+        for (pixelSeq = 0; pixelSeq <= GET_INDEX(cornerList, 0); ++pixelSeq)
+            append_pixel(lastCurve, O_COORDINATE(outline, pixelSeq));
+
+        NEXT_CURVE(lastCurve)      = firstCurve;
+        PREVIOUS_CURVE(firstCurve) = lastCurve;
+    }
+}
+
+
+
+static curve_list_array_type
+split_at_corners(pixel_outline_list_type const pixel_list,
+                 fitting_opts_type *     const fitting_opts,
+                 at_exception_type *     const exception) {
+/*----------------------------------------------------------------------------
+   Find the corners in PIXEL_LIST, the list of points.  (Presumably we
+   can't fit a single spline around a corner.)  The general strategy
+   is to look through all the points, remembering which we want to
+   consider corners.  Then go through that list, producing the
+   curve_list.  This is dictated by the fact that PIXEL_LIST does not
+   necessarily start on a corner---it just starts at the character's
+   first outline pixel, going left-to-right, top-to-bottom.  But we
+   want all our splines to start and end on real corners.
+
+   For example, consider the top of a capital `C' (this is in cmss20):
+                     x
+                     ***********
+                  ******************
+
+   PIXEL_LIST will start at the pixel below the `x'.  If we considered
+   this pixel a corner, we would wind up matching a very small segment
+   from there to the end of the line, probably as a straight line, which
+   is certainly not what we want.
+
+   PIXEL_LIST has one element for each closed outline on the character.
+   To preserve this information, we return an array of curve_lists, one
+   element (which in turn consists of several curves, one between each
+   pair of corners) for each element in PIXEL_LIST.
+-----------------------------------------------------------------------------*/
+    unsigned outlineSeq;
+    curve_list_array_type curve_array;
+
+    curve_array = new_curve_list_array();
+
+    LOG("\nFinding corners:\n");
+
+    for (outlineSeq = 0;
+         outlineSeq < O_LIST_LENGTH(pixel_list);
+         ++outlineSeq) {
+
+        pixel_outline_type const outline =
+            O_LIST_OUTLINE(pixel_list, outlineSeq);
+
+        index_list_type corner_list;
+        curve_list_type curve_list;
+
+        curve_list = new_curve_list();
+
+        CURVE_LIST_CLOCKWISE(curve_list) = O_CLOCKWISE(outline);
+        curve_list.color = outline.color;
+        curve_list.open  = outline.open;
+
+        LOG1("#%u:", outlineSeq);
+        
+        /* If the outline does not have enough points, we can't do
+           anything.  The endpoints of the outlines are automatically
+           corners.  We need at least `corner_surround' more pixels on
+           either side of a point before it is conceivable that we might
+           want another corner.
+        */
+        if (O_LENGTH(outline) > fitting_opts->corner_surround * 2 + 2)
+            corner_list = find_corners(outline, fitting_opts, exception);
+
+        else {
+            int const surround = (O_LENGTH(outline) - 3) / 2;
+            if (surround >= 2) {
+                unsigned int const save_corner_surround =
+                    fitting_opts->corner_surround;
+                fitting_opts->corner_surround = surround;
+                corner_list = find_corners(outline, fitting_opts, exception);
+                fitting_opts->corner_surround = save_corner_surround;
+            } else {
+                corner_list.length = 0;
+                corner_list.data = NULL;
+            }
+        }
+
+        if (corner_list.length == 0)
+            /* No corners.  Use all of the pixel outline as the one curve. */
+            makeOutlineOneCurve(outline, &curve_list);
+        else
+            divideOutlineWithCorners(outline, corner_list, &curve_list);
+        
+        LOG1(" [%u].\n", corner_list.length);
+        free_index_list(&corner_list);
+
+        /* And now add the just-completed curve list to the array.  */
+        append_curve_list(&curve_array, curve_list);
+    }
+
+    return curve_array;
+}
+
+
+
+static void
+removeKnees(curve_list_type const curveList) {
+/*----------------------------------------------------------------------------
+  Remove the extraneous ``knee'' points before filtering.  Since the
+  corners have already been found, we don't need to worry about
+  removing a point that should be a corner.
+-----------------------------------------------------------------------------*/
+    unsigned int curveSeq;
+    
+    LOG("\nRemoving knees:\n");
+    for (curveSeq = 0; curveSeq < curveList.length; ++curveSeq) {
+        LOG1("#%u:", curveSeq);
+        remove_knee_points(CURVE_LIST_ELT(curveList, curveSeq),
+                           CURVE_LIST_CLOCKWISE(curveList));
+    }
+}
+    
+
+
+static void
+computePointWeights(curve_list_type     const curveList,
+                    fitting_opts_type * const fittingOptsP,
+                    distance_map_type * const distP) {
+
+    unsigned int const height = distP->height;
+
+    unsigned int curveSeq;
+    
+    for (curveSeq = 0; curveSeq < curveList.length; ++curveSeq) {
+        unsigned pointSeq;
+        curve_type const curve = CURVE_LIST_ELT(curveList, curveSeq);
+        for (pointSeq = 0; pointSeq < CURVE_LENGTH(curve); ++pointSeq) {
+            float_coord * const coordP = &CURVE_POINT(curve, pointSeq);
+            unsigned int x = coordP->x;
+            unsigned int y = height - (unsigned int)coordP->y - 1;
+            
+            float width, w;
+
+            /* Each (x, y) is a point on the skeleton of the curve, which
+               might be offset from the true centerline, where the width
+               is maximal.  Therefore, use as the local line width the
+               maximum distance over the neighborhood of (x, y). 
+            */
+            width = distP->d[y][x];  /* initial value */
+            if (y - 1 >= 0) {
+                if ((w = distP->d[y-1][x]) > width)
+                    width = w;
+                if (x - 1 >= 0) {
+                    if ((w = distP->d[y][x-1]) > width)
+                        width = w;
+                    if ((w = distP->d[y-1][x-1]) > width)
+                        width = w;
+                }
+                if (x + 1 < distP->width) {
+                    if ((w = distP->d[y][x+1]) > width)
+                        width = w;
+                    if ((w = distP->d[y-1][x+1]) > width)
+                        width = w;
+                }
+            }
+            if (y + 1 < height) {
+                if ((w = distP->d[y+1][x]) > width)
+                    width = w;
+                if (x - 1 >= 0 && (w = distP->d[y+1][x-1]) > width)
+                    width = w;
+                if (x + 1 < distP->width && (w = distP->d[y+1][x+1]) > width)
+                    width = w;
+            }
+            coordP->z = width * (fittingOptsP->width_weight_factor);
+        }
+    }
+}
+
+
+
+static void
+filterCurves(curve_list_type     const curveList,
+             fitting_opts_type * const fittingOptsP) {
+             
+    unsigned int curveSeq;
+
+    LOG("\nFiltering curves:\n");
+
+    for (curveSeq = 0; curveSeq < curveList.length; ++curveSeq) {
+        LOG1("#%u: ", curveSeq);
+        filter(CURVE_LIST_ELT(curveList, curveSeq), fittingOptsP);
+    }
+}
+
+
+
+static void
+logSplinesForCurve(unsigned int     const curveSeq,
+                   spline_list_type const curveSplines) {
+
+    unsigned int splineSeq;
+
+    LOG1("Fitted splines for curve #%u:\n", curveSeq);
+    for (splineSeq = 0;
+         splineSeq < SPLINE_LIST_LENGTH(curveSplines);
+         ++splineSeq) {
+        LOG1("  %u: ", splineSeq);
+        if (log_file)
+            print_spline(log_file, SPLINE_LIST_ELT(curveSplines, splineSeq));
+    }
+}     
+       
+
+
+static void
+change_bad_lines(spline_list_type *        const spline_list,
+                 const fitting_opts_type * const fitting_opts) {
+
+/* Unfortunately, we cannot tell in isolation whether a given spline
+   should be changed to a line or not.  That can only be known after the
+   entire curve has been fit to a list of splines.  (The curve is the
+   pixel outline between two corners.)  After subdividing the curve, a
+   line may very well fit a portion of the curve just as well as the
+   spline---but unless a spline is truly close to being a line, it
+   should not be combined with other lines.  */
+
+  unsigned this_spline;
+  bool found_cubic = false;
+  unsigned length = SPLINE_LIST_LENGTH (*spline_list);
+
+  LOG1 ("\nChecking for bad lines (length %u):\n", length);
+
+  /* First see if there are any splines in the fitted shape.  */
+  for (this_spline = 0; this_spline < length; this_spline++)
+    {
+      if (SPLINE_DEGREE (SPLINE_LIST_ELT (*spline_list, this_spline)) ==
+       CUBICTYPE)
+        {
+          found_cubic = true;
+          break;
+        }
+    }
+
+  /* If so, change lines back to splines (we haven't done anything to
+     their control points, so we only have to change the degree) unless
+     the spline is close enough to being a line.  */
+  if (found_cubic)
+    for (this_spline = 0; this_spline < length; this_spline++)
+      {
+        spline_type s = SPLINE_LIST_ELT (*spline_list, this_spline);
+
+        if (SPLINE_DEGREE (s) == LINEARTYPE)
+          {
+            LOG1 ("  #%u: ", this_spline);
+            if (SPLINE_LINEARITY (s) > fitting_opts->line_reversion_threshold)
+              {
+                LOG ("reverted, ");
+                SPLINE_DEGREE (SPLINE_LIST_ELT (*spline_list, this_spline))
+                  = CUBICTYPE;
+              }
+            LOG1 ("linearity %.3f.\n", SPLINE_LINEARITY (s));
+          }
+      }
+    else
+      LOG ("  No lines.\n");
+}
+
+
+
+static bool
+spline_linear_enough(spline_type *             const spline,
+                     curve_type                const curve,
+                     const fitting_opts_type * const fitting_opts) {
+
+/* Supposing that we have accepted the error, another question arises:
+   would we be better off just using a straight line?  */
+
+  float A, B, C;
+  unsigned this_point;
+  float dist = 0.0, start_end_dist, threshold;
+
+  LOG ("Checking linearity:\n");
+
+  A = END_POINT(*spline).x - START_POINT(*spline).x;
+  B = END_POINT(*spline).y - START_POINT(*spline).y;
+  C = END_POINT(*spline).z - START_POINT(*spline).z;
+
+  start_end_dist = (float) (SQR(A) + SQR(B) + SQR(C));
+  LOG1 ("start_end_distance is %.3f.\n", sqrt(start_end_dist));
+
+  LOG3 ("  Line endpoints are (%.3f, %.3f, %.3f) and ", START_POINT(*spline).x, START_POINT(*spline).y, START_POINT(*spline).z);
+  LOG3 ("(%.3f, %.3f, %.3f)\n", END_POINT(*spline).x, END_POINT(*spline).y, END_POINT(*spline).z);
+
+  /* LOG3 ("  Line is %.3fx + %.3fy + %.3f = 0.\n", A, B, C); */
+
+  for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++)
+    {
+      float a, b, c, w;
+      float t = CURVE_T (curve, this_point);
+      float_coord spline_point = evaluate_spline (*spline, t);
+
+      a = spline_point.x - START_POINT(*spline).x;
+      b = spline_point.y - START_POINT(*spline).y;
+      c = spline_point.z - START_POINT(*spline).z;
+      w = (A*a + B*b + C*c) / start_end_dist;
+
+      dist += (float)sqrt(SQR(a-A*w) + SQR(b-B*w) + SQR(c-C*w));
+    }
+  LOG1 ("  Total distance is %.3f, ", dist);
+
+  dist /= (CURVE_LENGTH (curve) - 1);
+  LOG1 ("which is %.3f normalized.\n", dist);
+
+  /* We want reversion of short curves to splines to be more likely than
+     reversion of long curves, hence the second division by the curve
+     length, for use in `change_bad_lines'.  */
+  SPLINE_LINEARITY (*spline) = dist;
+  LOG1 ("  Final linearity: %.3f.\n", SPLINE_LINEARITY (*spline));
+  if (start_end_dist * (float) 0.5 > fitting_opts->line_threshold)
+    threshold = fitting_opts->line_threshold;
+  else
+    threshold = start_end_dist * (float) 0.5;
+  LOG1 ("threshold is %.3f .\n", threshold);
+  if (dist < threshold)
+    return true;
+  else
+    return false;
+}
+
+
+
+/* Forward declaration for recursion */
+
+static spline_list_type *
+fitCurve(curve_type                const curve,
+         const fitting_opts_type * const fitting_opts,
+         at_exception_type *       const exception);
+
+
+
+static spline_list_type *
+fit_with_line(curve_type const curve) {
+/*----------------------------------------------------------------------------
+  This routine returns the curve fitted to a straight line in a very
+  simple way: make the first and last points on the curve be the
+  endpoints of the line.  This simplicity is justified because we are
+  called only on very short curves.
+-----------------------------------------------------------------------------*/
+    spline_type line;
+
+    LOG("Fitting with straight line:\n");
+
+    SPLINE_DEGREE(line) = LINEARTYPE;
+    START_POINT(line) = CONTROL1(line) = CURVE_POINT(curve, 0);
+    END_POINT(line) = CONTROL2(line) = LAST_CURVE_POINT(curve);
+
+    /* Make sure that this line is never changed to a cubic.  */
+    SPLINE_LINEARITY(line) = 0;
+
+    if (log_file) {
+        LOG("  ");
+        print_spline(log_file, line);
+    }
+
+    return new_spline_list_with_spline(line);
+}
+
+
+
+#define B0(t) CUBE ((float) 1.0 - (t))
+#define B1(t) ((float) 3.0 * (t) * SQR ((float) 1.0 - (t)))
+#define B2(t) ((float) 3.0 * SQR (t) * ((float) 1.0 - (t)))
+#define B3(t) CUBE (t)
+
+static spline_type
+fit_one_spline(curve_type          const curve, 
+               at_exception_type * const exception) {
+/*----------------------------------------------------------------------------
+   Our job here is to find alpha1 (and alpha2), where t1_hat (t2_hat) is
+   the tangent to CURVE at the starting (ending) point, such that:
+
+   control1 = alpha1 * t1_hat + starting point
+   control2 = alpha2 * t2_hat + ending_point
+
+   and the resulting spline (starting_point .. control1 and control2 ..
+   ending_point) minimizes the least-square error from CURVE.
+
+   See pp.57--59 of the Phoenix thesis.
+
+   The B?(t) here corresponds to B_i^3(U_i) there.
+   The Bernshte\u in polynomials of degree n are defined by
+   B_i^n(t) = { n \choose i } t^i (1-t)^{n-i}, i = 0..n
+-----------------------------------------------------------------------------*/
+    /* Since our arrays are zero-based, the `C0' and `C1' here correspond
+       to `C1' and `C2' in the paper. 
+    */
+    float X_C1_det, C0_X_det, C0_C1_det;
+    float alpha1, alpha2;
+    spline_type spline;
+    vector_type start_vector, end_vector;
+    unsigned i;
+    vector_type * A;
+    vector_type t1_hat;
+    vector_type t2_hat;
+    float C[2][2] = { { 0.0, 0.0 }, { 0.0, 0.0 } };
+    float X[2] = { 0.0, 0.0 };
+
+    t1_hat = *CURVE_START_TANGENT(curve);  /* initial value */
+    t2_hat = *CURVE_END_TANGENT(curve);    /* initial value */
+
+    MALLOCARRAY_NOFAIL(A, CURVE_LENGTH(curve) * 2);
+
+    START_POINT(spline) = CURVE_POINT(curve, 0);
+    END_POINT(spline)   = LAST_CURVE_POINT(curve);
+    start_vector = make_vector(START_POINT(spline));
+    end_vector   = make_vector(END_POINT(spline));
+
+    for (i = 0; i < CURVE_LENGTH(curve); ++i) {
+        A[(i << 1) + 0] = Vmult_scalar(t1_hat, B1(CURVE_T(curve, i)));
+        A[(i << 1) + 1] = Vmult_scalar(t2_hat, B2(CURVE_T(curve, i)));
+    }
+
+    for (i = 0; i < CURVE_LENGTH(curve); ++i) {
+        vector_type temp, temp0, temp1, temp2, temp3;
+        vector_type * Ai = A + (i << 1);
+
+        C[0][0] += Vdot(Ai[0], Ai[0]);
+        C[0][1] += Vdot(Ai[0], Ai[1]);
+        /* C[1][0] = C[0][1] (this is assigned outside the loop)  */
+        C[1][1] += Vdot(Ai[1], Ai[1]);
+
+        /* Now the right-hand side of the equation in the paper.  */
+        temp0 = Vmult_scalar(start_vector, B0(CURVE_T(curve, i)));
+        temp1 = Vmult_scalar(start_vector, B1(CURVE_T(curve, i)));
+        temp2 = Vmult_scalar(end_vector, B2(CURVE_T(curve, i)));
+        temp3 = Vmult_scalar(end_vector, B3(CURVE_T(curve, i)));
+
+        temp = make_vector(
+            Vsubtract_point(CURVE_POINT(curve, i),
+                            Vadd(temp0, Vadd(temp1, Vadd(temp2, temp3)))));
+
+        X[0] += Vdot(temp, Ai[0]);
+        X[1] += Vdot(temp, Ai[1]);
+    }
+    free(A);
+
+    C[1][0] = C[0][1];
+    
+    X_C1_det = X[0] * C[1][1] - X[1] * C[0][1];
+    C0_X_det = C[0][0] * X[1] - C[0][1] * X[0];
+    C0_C1_det = C[0][0] * C[1][1] - C[1][0] * C[0][1];
+    if (C0_C1_det == 0.0) {
+        LOG ("zero determinant of C0*C1");
+        at_exception_fatal(exception, "zero determinant of C0*C1");
+        goto cleanup;
+    }
+
+    alpha1 = X_C1_det / C0_C1_det;
+    alpha2 = C0_X_det / C0_C1_det;
+
+    CONTROL1(spline) = Vadd_point(START_POINT(spline),
+                                  Vmult_scalar(t1_hat, alpha1));
+    CONTROL2(spline) = Vadd_point(END_POINT(spline),
+                                  Vmult_scalar(t2_hat, alpha2));
+    SPLINE_DEGREE(spline) = CUBICTYPE;
+
+cleanup:
+    return spline;
+}
+
+
+
+static void
+logSplineFit(spline_type const spline) {
+
+    if (SPLINE_DEGREE(spline) == LINEARTYPE)
+        LOG("  fitted to line:\n");
+    else
+        LOG("  fitted to spline:\n");
+    
+    if (log_file) {
+        LOG ("    ");
+        print_spline (log_file, spline);
+    }
+}
+
+
+
+static spline_list_type *
+fit_with_least_squares(curve_type                const curve,
+                       const fitting_opts_type * const fitting_opts,
+                       at_exception_type *       const exception) {
+/*----------------------------------------------------------------------------
+  The least squares method is well described in Schneider's thesis.
+  Briefly, we try to fit the entire curve with one spline.  If that
+  fails, we subdivide the curve. 
+-----------------------------------------------------------------------------*/
+    float error;
+    float best_error;
+    spline_type spline;
+    spline_type best_spline;
+    spline_list_type * spline_list;
+    unsigned int worst_point;
+    float previous_error;
+    
+    best_error = FLT_MAX;  /* initial value */
+    previous_error = FLT_MAX;  /* initial value */
+    spline_list = NULL;  /* initial value */
+    worst_point = 0;  /* initial value */
+
+    LOG ("\nFitting with least squares:\n");
+    
+    /* Phoenix reduces the number of points with a ``linear spline
+       technique''.  But for fitting letterforms, that is
+       inappropriate.  We want all the points we can get.
+    */
+    
+    /* It makes no difference whether we first set the `t' values or
+       find the tangents.  This order makes the documentation a little
+       more coherent.
+    */
+
+    LOG("Finding tangents:\n");
+    find_tangent(curve, /* to_start */ true,  /* cross_curve */ false,
+                 fitting_opts->tangent_surround);
+    find_tangent(curve, /* to_start */ false, /* cross_curve */ false,
+                 fitting_opts->tangent_surround);
+
+    set_initial_parameter_values(curve);
+
+    /* Now we loop, subdividing, until CURVE has been fit.  */
+    while (true) {
+        float error;
+
+        spline = fit_one_spline(curve, exception);
+        best_spline = spline;
+        if (at_exception_got_fatal(exception))
+            goto cleanup;
+
+        logSplineFit(spline);
+        
+        if (SPLINE_DEGREE(spline) == LINEARTYPE)
+            break;
+
+        error = find_error(curve, spline, &worst_point, exception);
+        if (error <= previous_error) {
+            best_error  = error;
+            best_spline = spline;
+        }
+        break;
+    }
+
+    if (SPLINE_DEGREE(spline) == LINEARTYPE) {
+        spline_list = new_spline_list_with_spline(spline);
+        LOG1("Accepted error of %.3f.\n", error);
+        return spline_list;
+    }
+
+    /* Go back to the best fit.  */
+    spline = best_spline;
+    error = best_error;
+
+    if (error < fitting_opts->error_threshold && !CURVE_CYCLIC(curve)) {
+        /* The points were fitted with a spline.  We end up here
+           whenever a fit is accepted.  We have one more job: see if
+           the ``curve'' that was fit should really be a straight
+           line.
+        */
+        if (spline_linear_enough(&spline, curve, fitting_opts)) {
+            SPLINE_DEGREE(spline) = LINEARTYPE;
+            LOG("Changed to line.\n");
+        }
+        spline_list = new_spline_list_with_spline(spline);
+        LOG1("Accepted error of %.3f.\n", error);
+    } else {
+        /* We couldn't fit the curve acceptably, so subdivide.  */
+        unsigned subdivision_index;
+        spline_list_type * left_spline_list;
+        spline_list_type * right_spline_list;
+        curve_type left_curve, right_curve;
+
+        left_curve  = new_curve();
+        right_curve = new_curve();
+
+        /* Insert 'left_curve', then 'right_curve' after 'curve' in the list */
+        NEXT_CURVE(right_curve) = NEXT_CURVE(curve);
+        PREVIOUS_CURVE(right_curve) = left_curve;
+        NEXT_CURVE(left_curve) = right_curve;
+        PREVIOUS_CURVE(left_curve) = curve;
+        NEXT_CURVE(curve) = left_curve;
+
+        LOG1("\nSubdividing (error %.3f):\n", error);
+        LOG3("  Original point: (%.3f,%.3f), #%u.\n",
+             CURVE_POINT (curve, worst_point).x,
+             CURVE_POINT (curve, worst_point).y, worst_point);
+        subdivision_index = worst_point;
+        LOG3 ("  Final point: (%.3f,%.3f), #%u.\n",
+              CURVE_POINT (curve, subdivision_index).x,
+              CURVE_POINT (curve, subdivision_index).y, subdivision_index);
+
+        /* The last point of the left-hand curve will also be the first
+           point of the right-hand curve.  */
+        CURVE_LENGTH(left_curve)  = subdivision_index + 1;
+        CURVE_LENGTH(right_curve) = CURVE_LENGTH(curve) - subdivision_index;
+        left_curve->point_list = curve->point_list;
+        right_curve->point_list = curve->point_list + subdivision_index;
+
+        /* We want to use the tangents of the curve which we are
+           subdividing for the start tangent for left_curve and the
+           end tangent for right_curve.
+        */
+        CURVE_START_TANGENT(left_curve) = CURVE_START_TANGENT(curve);
+        CURVE_END_TANGENT(right_curve)  = CURVE_END_TANGENT(curve);
+
+        /* We have to set up the two curves before finding the tangent at
+           the subdivision point.  The tangent at that point must be the
+           same for both curves, or noticeable bumps will occur in the
+           character.  But we want to use information on both sides of the
+           point to compute the tangent, hence cross_curve = true.
+        */
+        find_tangent(left_curve, /* to_start_point: */ false,
+                     /* cross_curve: */ true, fitting_opts->tangent_surround);
+        CURVE_START_TANGENT(right_curve) = CURVE_END_TANGENT(left_curve);
+
+        /* Now that we've set up the curves, we can fit them.  */
+        left_spline_list = fitCurve(left_curve, fitting_opts, exception);
+        if (at_exception_got_fatal(exception))
+            /* TODO: Memory allocated for left_curve and right_curve
+               will leak.*/
+            goto cleanup;
+
+        right_spline_list = fitCurve(right_curve, fitting_opts, exception);
+        /* TODO: Memory allocated for left_curve and right_curve
+           will leak.*/
+        if (at_exception_got_fatal(exception))
+            goto cleanup;
+        
+        /* Neither of the subdivided curves could be fit, so fail.  */
+        if (left_spline_list == NULL && right_spline_list == NULL)
+            return NULL;
+
+        /* Put the two together (or whichever of them exist).  */
+        spline_list = new_spline_list();
+
+        if (left_spline_list == NULL) {
+            LOG1("Could not fit spline to left curve (%lx).\n",
+                 (unsigned long) left_curve);
+            at_exception_warning(exception, "Could not fit left spline list");
+        } else {
+            concat_spline_lists(spline_list, *left_spline_list);
+            free_spline_list(*left_spline_list);
+            free(left_spline_list);
+        }
+        
+        if (right_spline_list == NULL) {
+            LOG1("Could not fit spline to right curve (%lx).\n",
+                 (unsigned long) right_curve);
+            at_exception_warning(exception, "Could not fit right spline list");
+        } else {
+            concat_spline_lists(spline_list, *right_spline_list);
+            free_spline_list(*right_spline_list);
+            free(right_spline_list);
+        }
+        if (CURVE_END_TANGENT(left_curve))
+            free(CURVE_END_TANGENT(left_curve));
+        free(left_curve);
+        free(right_curve);
+    }
+cleanup:
+
+    return spline_list;
+}
+
+
+
+static spline_list_type *
+fitCurve(curve_type                const curve,
+         const fitting_opts_type * const fittingOptsP,
+         at_exception_type *       const exception) {
+/*----------------------------------------------------------------------------
+  Transform a set of locations to a list of splines (the fewer the
+  better).  We are guaranteed that CURVE does not contain any corners.
+  We return NULL if we cannot fit the points at all.
+-----------------------------------------------------------------------------*/
+    spline_list_type * fittedSplinesP;
+
+    if (CURVE_LENGTH(curve) < 2) {
+        LOG("Tried to fit curve with less than two points");
+        at_exception_warning(exception, 
+                             "Tried to fit curve with less than two points");
+        fittedSplinesP = NULL;
+    } else if (CURVE_LENGTH(curve) < 4)
+        fittedSplinesP = fit_with_line(curve);
+    else
+        fittedSplinesP =
+            fit_with_least_squares(curve, fittingOptsP, exception);
+
+    return fittedSplinesP;
+}
+
+
+
+static void
+fitCurves(curve_list_type           const curveList,
+          pixel                     const color,
+          const fitting_opts_type * const fittingOptsP,
+          spline_list_type *        const splinesP,
+          at_exception_type *       const exceptionP) {
+          
+    spline_list_type curveListSplines;
+    unsigned int curveSeq;
+
+    curveListSplines = empty_spline_list();
+    
+    curveListSplines.open      = curveList.open;
+    curveListSplines.clockwise = curveList.clockwise;
+    curveListSplines.color     = color;
+
+    for (curveSeq = 0;
+         curveSeq < curveList.length && !at_exception_got_fatal(exceptionP);
+         ++curveSeq) {
+
+        curve_type const currentCurve = CURVE_LIST_ELT(curveList, curveSeq);
+
+        spline_list_type * curveSplinesP;
+
+        LOG1("\nFitting curve #%u:\n", curveSeq);
+
+        curveSplinesP = fitCurve(currentCurve, fittingOptsP, exceptionP);
+        if (!at_exception_got_fatal(exceptionP)) {
+            if (curveSplinesP == NULL) {
+                LOG1("Could not fit curve #%u", curveSeq);
+                at_exception_warning(exceptionP, "Could not fit curve");
+            } else {
+                logSplinesForCurve(curveSeq, *curveSplinesP);
+                
+                /* After fitting, we may need to change some would-be lines
+                   back to curves, because they are in a list with other
+                   curves.
+                */
+                change_bad_lines(curveSplinesP, fittingOptsP);
+                
+                concat_spline_lists(&curveListSplines, *curveSplinesP);
+                free_spline_list(*curveSplinesP);
+                free(curveSplinesP);
+            }
+        }
+    }
+    if (at_exception_got_fatal(exceptionP))
+        free_spline_list(curveListSplines);
+    else
+        *splinesP = curveListSplines;
+}
+    
+
+
+static void
+logFittedSplines(spline_list_type const curve_list_splines) {
+
+    unsigned int splineSeq;
+
+    LOG("\nFitted splines are:\n");
+    for (splineSeq = 0;
+         splineSeq < SPLINE_LIST_LENGTH(curve_list_splines);
+         ++splineSeq) {
+        LOG1("  %u: ", splineSeq);
+        print_spline(log_file,
+                     SPLINE_LIST_ELT(curve_list_splines, splineSeq));
+    }
+}
+
+
+
+static void
+fitCurveList(curve_list_type     const curveList,
+             fitting_opts_type * const fittingOptsP,
+             distance_map_type * const dist,
+             pixel               const color,
+             spline_list_type *  const splineListP,
+             at_exception_type * const exception) {
+/*----------------------------------------------------------------------------
+  Fit the list of curves CURVE_LIST to a list of splines, and return
+  it.  CURVE_LIST represents a single closed paths, e.g., either the
+  inside or outside outline of an `o'.
+-----------------------------------------------------------------------------*/
+    curve_type curve;
+    spline_list_type curveListSplines;
+
+    removeKnees(curveList);
+
+    if (dist != NULL)
+        computePointWeights(curveList, fittingOptsP, dist);
+    
+    /* We filter all the curves in 'curveList' at once; otherwise, we
+       would look at an unfiltered curve when computing tangents.
+    */
+    filterCurves(curveList, fittingOptsP);
+
+    /* Make the first point in the first curve also be the last point in
+       the last curve, so the fit to the whole curve list will begin and
+       end at the same point.  This may cause slight errors in computing
+       the tangents and t values, but it's worth it for the continuity.
+       Of course we don't want to do this if the two points are already
+       the same, as they are if the curve is cyclic.  (We don't append it
+       earlier, in `split_at_corners', because that confuses the
+       filtering.)  Finally, we can't append the point if the curve is
+       exactly three points long, because we aren't adding any more data,
+       and three points isn't enough to determine a spline.  Therefore,
+       the fitting will fail.
+    */
+    curve = CURVE_LIST_ELT(curveList, 0);
+    if (CURVE_CYCLIC(curve))
+        append_point(curve, CURVE_POINT(curve, 0));
+
+    /* Finally, fit each curve in the list to a list of splines.  */
+
+    fitCurves(curveList, color, fittingOptsP, &curveListSplines, exception);
+    if (!at_exception_got_fatal(exception)) {
+        if (log_file)
+            logFittedSplines(curveListSplines);
+        *splineListP = curveListSplines;
+    }
+}
+
+
+
+static void
+fitCurvesToSplines(curve_list_array_type    const curveArray,
+                   fitting_opts_type *      const fittingOptsP,
+                   distance_map_type *      const dist,
+                   unsigned short           const width,
+                   unsigned short           const height,
+                   at_exception_type *      const exception,
+                   at_progress_func               notifyProgress, 
+                   void *                   const progressData,
+                   at_testcancel_func             testCancel,
+                   void *                   const testcancelData,
+                   spline_list_array_type * const splineListArrayP) {
+    
+    unsigned splineListSeq;
+    bool cancelled;
+    spline_list_array_type splineListArray;
+
+    splineListArray = new_spline_list_array();
+    splineListArray.centerline          = fittingOptsP->centerline;
+    splineListArray.preserve_width      = fittingOptsP->preserve_width;
+    splineListArray.width_weight_factor = fittingOptsP->width_weight_factor;
+    splineListArray.backgroundSpec      = fittingOptsP->backgroundSpec;
+    splineListArray.background_color    = fittingOptsP->background_color;
+    /* Set dummy values. Real value is set in upper context. */
+    splineListArray.width  = width;
+    splineListArray.height = height;
+    
+    for (splineListSeq = 0, cancelled = false;
+         splineListSeq < CURVE_LIST_ARRAY_LENGTH(curveArray) &&
+             !at_exception_got_fatal(exception) && !cancelled;
+         ++splineListSeq) {
+
+        curve_list_type const curveList =
+            CURVE_LIST_ARRAY_ELT(curveArray, splineListSeq);
+      
+        spline_list_type curveSplineList;
+
+        if (notifyProgress)
+            notifyProgress((((float)splineListSeq)/
+                            ((float)CURVE_LIST_ARRAY_LENGTH(curveArray) *
+                             (float)3.0) + (float)0.333),
+                           progressData);
+        if (testCancel && testCancel(testcancelData))
+            cancelled = true;
+
+        LOG1("\nFitting curve list #%u:\n", splineListSeq);
+
+        fitCurveList(curveList, fittingOptsP, dist, curveList.color,
+                     &curveSplineList, exception);
+        if (!at_exception_got_fatal(exception))
+            append_spline_list(&splineListArray, curveSplineList);
+    }
+    *splineListArrayP = splineListArray;
+}
+
+
+
+void
+fit_outlines_to_splines(pixel_outline_list_type  const pixelOutlineList,
+                        fitting_opts_type *      const fittingOptsP,
+                        distance_map_type *      const dist,
+                        unsigned short           const width,
+                        unsigned short           const height,
+                        at_exception_type *      const exception,
+                        at_progress_func               notifyProgress, 
+                        void *                   const progressData,
+                        at_testcancel_func             testCancel,
+                        void *                   const testcancelData,
+                        spline_list_array_type * const splineListArrayP) {
+/*----------------------------------------------------------------------------
+   Transform a list of pixels in the outlines of the original character to
+   a list of spline lists fitted to those pixels.
+-----------------------------------------------------------------------------*/
+    curve_list_array_type const curveListArray =
+        split_at_corners(pixelOutlineList, fittingOptsP, exception);
+
+    fitCurvesToSplines(curveListArray, fittingOptsP, dist, width, height,
+                       exception, notifyProgress, progressData,
+                       testCancel, testcancelData, splineListArrayP);
+
+
+    free_curve_list_array(&curveListArray, notifyProgress, progressData);
+    
+    flush_log_output();
+}
+
+
+
+
+static void
+find_vectors(unsigned int       const test_index,
+             pixel_outline_type const outline,
+             vector_type *      const in,
+             vector_type *      const out,
+             unsigned int       const corner_surround) {
+/*----------------------------------------------------------------------------
+  Return the difference vectors coming in and going out of the outline
+  OUTLINE at the point whose index is TEST_INDEX.  In Phoenix,
+  Schneider looks at a single point on either side of the point we're
+  considering.  That works for him because his points are not touching.
+  But our points *are* touching, and so we have to look at
+  `corner_surround' points on either side, to get a better picture of
+  the outline's shape.
+-----------------------------------------------------------------------------*/
+    int i;
+    unsigned n_done;
+    pm_pixelcoord const candidate = O_COORDINATE(outline, test_index);
+
+    in->dx  = in->dy  = in->dz  = 0.0;
+    out->dx = out->dy = out->dz = 0.0;
+    
+    /* Add up the differences from p of the `corner_surround' points
+       before p.
+    */
+    for (i = O_PREV(outline, test_index), n_done = 0;
+         n_done < corner_surround;
+         i = O_PREV(outline, i), ++n_done)
+        *in = Vadd(*in, IPsubtract(O_COORDINATE(outline, i), candidate));
+    
+    /* And the points after p. */
+    for (i = O_NEXT (outline, test_index), n_done = 0;
+         n_done < corner_surround;
+         i = O_NEXT(outline, i), ++n_done)
+        *out = Vadd(*out, IPsubtract(O_COORDINATE(outline, i), candidate));
+}
+
+
+
+/* Remove adjacent points from the index list LIST.  We do this by first
+   sorting the list and then running through it.  Since these lists are
+   quite short, a straight selection sort (e.g., p.139 of the Art of
+   Computer Programming, vol.3) is good enough.  LAST_INDEX is the index
+   of the last pixel on the outline, i.e., the next one is the first
+   pixel. We need this for checking the adjacency of the last corner.
+
+   We need to do this because the adjacent corners turn into
+   two-pixel-long curves, which can only be fit by straight lines.  */
+
+static void
+remove_adjacent_corners (index_list_type *list, unsigned last_index,
+             bool remove_adj_corners,
+             at_exception_type * exception)
+             
+{
+  unsigned j;
+  unsigned last;
+  index_list_type new_list = new_index_list ();
+
+  for (j = INDEX_LIST_LENGTH (*list) - 1; j > 0; j--)
+    {
+      unsigned search;
+      unsigned temp;
+      /* Find maximal element below `j'.  */
+      unsigned max_index = j;
+
+      for (search = 0; search < j; search++)
+        if (GET_INDEX (*list, search) > GET_INDEX (*list, max_index))
+          max_index = search;
+
+      if (max_index != j)
+        {
+          temp = GET_INDEX (*list, j);
+          GET_INDEX (*list, j) = GET_INDEX (*list, max_index);
+          GET_INDEX (*list, max_index) = temp;
+      
+      /* xx -- really have to sort?  */
+      LOG ("needed exchange");
+      at_exception_warning(exception, "needed exchange");
+        }
+    }
+
+  /* The list is sorted.  Now look for adjacent entries.  Each time
+     through the loop we insert the current entry and, if appropriate,
+     the next entry.  */
+  for (j = 0; j < INDEX_LIST_LENGTH (*list) - 1; j++)
+    {
+      unsigned current = GET_INDEX (*list, j);
+      unsigned next = GET_INDEX (*list, j + 1);
+
+      /* We should never have inserted the same element twice.  */
+      /* assert (current != next); */
+
+      if ((remove_adj_corners) && ((next == current + 1) || (next == current)))
+        j++;
+
+      append_index (&new_list, current);
+    }
+
+  /* Don't append the last element if it is 1) adjacent to the previous
+     one; or 2) adjacent to the very first one.  */
+  last = GET_LAST_INDEX (*list);
+  if (INDEX_LIST_LENGTH (new_list) == 0
+      || !(last == GET_LAST_INDEX (new_list) + 1
+           || (last == last_index && GET_INDEX (*list, 0) == 0)))
+    append_index (&new_list, last);
+
+  free_index_list (list);
+  *list = new_list;
+}
+
+/* A ``knee'' is a point which forms a ``right angle'' with its
+   predecessor and successor.  See the documentation (the `Removing
+   knees' section) for an example and more details.
+
+   The argument CLOCKWISE tells us which direction we're moving.  (We
+   can't figure that information out from just the single segment with
+   which we are given to work.)
+
+   We should never find two consecutive knees.
+
+   Since the first and last points are corners (unless the curve is
+   cyclic), it doesn't make sense to remove those.  */
+
+/* This evaluates to true if the vector V is zero in one direction and
+   nonzero in the other.  */
+#define ONLY_ONE_ZERO(v)                                                \
+  (((v).dx == 0.0 && (v).dy != 0.0) || ((v).dy == 0.0 && (v).dx != 0.0))
+
+/* There are four possible cases for knees, one for each of the four
+   corners of a rectangle; and then the cases differ depending on which
+   direction we are going around the curve.  The tests are listed here
+   in the order of upper left, upper right, lower right, lower left.
+   Perhaps there is some simple pattern to the
+   clockwise/counterclockwise differences, but I don't see one.  */
+#define CLOCKWISE_KNEE(prev_delta, next_delta)                                                  \
+  ((prev_delta.dx == -1.0 && next_delta.dy == 1.0)                                              \
+   || (prev_delta.dy == 1.0 && next_delta.dx == 1.0)                                    \
+   || (prev_delta.dx == 1.0 && next_delta.dy == -1.0)                                   \
+   || (prev_delta.dy == -1.0 && next_delta.dx == -1.0))
+
+#define COUNTERCLOCKWISE_KNEE(prev_delta, next_delta)                                   \
+  ((prev_delta.dy == 1.0 && next_delta.dx == -1.0)                                              \
+   || (prev_delta.dx == 1.0 && next_delta.dy == 1.0)                                    \
+   || (prev_delta.dy == -1.0 && next_delta.dx == 1.0)                                   \
+   || (prev_delta.dx == -1.0 && next_delta.dy == -1.0))
+
+
+
+static void
+remove_knee_points(curve_type const curve,
+                   bool       const clockwise) {
+
+      unsigned const offset = (CURVE_CYCLIC(curve) == true) ? 0 : 1;
+      curve_type const trimmed_curve = copy_most_of_curve(curve);
+
+      pm_pixelcoord previous;
+      unsigned i;
+
+      if (!CURVE_CYCLIC(curve))
+          append_pixel(trimmed_curve,
+                       real_to_int_coord(CURVE_POINT(curve, 0)));
+
+      previous = real_to_int_coord(CURVE_POINT(curve,
+                                               CURVE_PREV(curve, offset)));
+
+      for (i = offset; i < CURVE_LENGTH (curve) - offset; ++i) {
+          pm_pixelcoord const current =
+              real_to_int_coord(CURVE_POINT(curve, i));
+          pm_pixelcoord const next =
+              real_to_int_coord(CURVE_POINT(curve, CURVE_NEXT(curve, i)));
+          vector_type const prev_delta = IPsubtract(previous, current);
+          vector_type const next_delta = IPsubtract(next, current);
+
+          if (ONLY_ONE_ZERO(prev_delta) && ONLY_ONE_ZERO(next_delta)
+              && ((clockwise && CLOCKWISE_KNEE(prev_delta, next_delta))
+                  || (!clockwise
+                      && COUNTERCLOCKWISE_KNEE(prev_delta, next_delta))))
+              LOG2(" (%d,%d)", current.col, current.row);
+          else {
+              previous = current;
+              append_pixel(trimmed_curve, current);
+          }
+      }
+
+      if (!CURVE_CYCLIC(curve))
+          append_pixel(trimmed_curve,
+                       real_to_int_coord(LAST_CURVE_POINT(curve)));
+
+      if (CURVE_LENGTH(trimmed_curve) == CURVE_LENGTH(curve))
+          LOG(" (none)");
+
+      LOG(".\n");
+
+      free_curve(curve);
+      *curve = *trimmed_curve;
+      free(trimmed_curve);      /* free_curve? --- Masatake */
+}
+
+
+
+/* Smooth the curve by adding in neighboring points.  Do this
+   `filter_iterations' times.  But don't change the corners.  */
+
+static void
+filter (curve_type curve, fitting_opts_type *fitting_opts)
+{
+  unsigned iteration, this_point;
+  unsigned offset = (CURVE_CYCLIC (curve) == true) ? 0 : 1;
+  float_coord prev_new_point;
+
+  /* We must have at least three points---the previous one, the current
+     one, and the next one.  But if we don't have at least five, we will
+     probably collapse the curve down onto a single point, which means
+     we won't be able to fit it with a spline.  */
+  if (CURVE_LENGTH (curve) < 5)
+    {
+      LOG1 ("Length is %u, not enough to filter.\n", CURVE_LENGTH (curve));
+      return;
+    }
+
+  prev_new_point.x = FLT_MAX;
+  prev_new_point.y = FLT_MAX;
+  prev_new_point.z = FLT_MAX;
+
+  for (iteration = 0; iteration < fitting_opts->filter_iterations;
+   iteration++)
+    {
+      curve_type newcurve = copy_most_of_curve (curve);
+      bool collapsed = false;
+
+      /* Keep the first point on the curve.  */
+      if (offset)
+        append_point (newcurve, CURVE_POINT (curve, 0));
+
+      for (this_point = offset; this_point < CURVE_LENGTH (curve) - offset;
+           this_point++)
+        {
+          vector_type in, out, sum;
+          float_coord new_point;
+
+          /* Calculate the vectors in and out, computed by looking at n points
+             on either side of this_point. Experimental it was found that 2 is
+             optimal. */
+
+          signed int prev, prevprev; /* have to be signed */
+          unsigned int next, nextnext;
+          float_coord candidate = CURVE_POINT (curve, this_point);
+
+          prev = CURVE_PREV (curve, this_point);
+          prevprev = CURVE_PREV (curve, prev);
+          next = CURVE_NEXT (curve, this_point);
+          nextnext = CURVE_NEXT (curve, next);
+
+          /* Add up the differences from p of the `surround' points
+             before p.  */
+          in.dx = in.dy = in.dz = 0.0;
+
+          in = Vadd (in, Psubtract (CURVE_POINT (curve, prev), candidate));
+          if (prevprev >= 0)
+              in = Vadd (in, Psubtract (CURVE_POINT (curve, prevprev), candidate));
+
+          /* And the points after p.  Don't use more points after p than we
+             ended up with before it.  */
+          out.dx = out.dy = out.dz = 0.0;
+
+          out = Vadd (out, Psubtract (CURVE_POINT (curve, next), candidate));
+          if (nextnext < CURVE_LENGTH (curve))
+              out = Vadd (out, Psubtract (CURVE_POINT (curve, nextnext), candidate));
+
+          /* Start with the old point.  */
+          new_point = candidate;
+          sum = Vadd (in, out);
+          /* We added 2*n+2 points, so we have to divide the sum by 2*n+2 */
+          new_point.x += sum.dx / 6;
+          new_point.y += sum.dy / 6;
+          new_point.z += sum.dz / 6;
+          if (fabs (prev_new_point.x - new_point.x) < 0.3
+              && fabs (prev_new_point.y - new_point.y) < 0.3
+              && fabs (prev_new_point.z - new_point.z) < 0.3)
+            {
+              collapsed = true;
+              break;
+            }
+
+
+          /* Put the newly computed point into a separate curve, so it
+             doesn't affect future computation (on this iteration).  */
+          append_point (newcurve, prev_new_point = new_point);
+        }
+
+      if (collapsed)
+    free_curve (newcurve);
+      else
+    {
+          /* Just as with the first point, we have to keep the last point.  */
+          if (offset)
+        append_point (newcurve, LAST_CURVE_POINT (curve));
+      
+          /* Set the original curve to the newly filtered one, and go again.  */
+          free_curve (curve);
+          *curve = *newcurve;
+    }
+      free (newcurve);
+    }
+
+  log_curve (curve, false);
+}
+
+
+
+/* Find reasonable values for t for each point on CURVE.  The method is
+   called chord-length parameterization, which is described in Plass &
+   Stone.  The basic idea is just to use the distance from one point to
+   the next as the t value, normalized to produce values that increase
+   from zero for the first point to one for the last point.  */
+
+static void
+set_initial_parameter_values (curve_type curve)
+{
+  unsigned p;
+
+  LOG ("\nAssigning initial t values:\n  ");
+
+  CURVE_T (curve, 0) = 0.0;
+
+  for (p = 1; p < CURVE_LENGTH (curve); p++)
+    {
+      float_coord point = CURVE_POINT (curve, p),
+                           previous_p = CURVE_POINT (curve, p - 1);
+      float d = distance (point, previous_p);
+      CURVE_T (curve, p) = CURVE_T (curve, p - 1) + d;
+    }
+
+  assert (LAST_CURVE_T (curve) != 0.0);
+
+  for (p = 1; p < CURVE_LENGTH (curve); p++)
+    CURVE_T (curve, p) = CURVE_T (curve, p) / LAST_CURVE_T (curve);
+
+  log_entire_curve (curve);
+}
+
+/* Find an approximation to the tangent to an endpoint of CURVE (to the
+   first point if TO_START_POINT is true, else the last).  If
+   CROSS_CURVE is true, consider points on the adjacent curve to CURVE.
+
+   It is important to compute an accurate approximation, because the
+   control points that we eventually decide upon to fit the curve will
+   be placed on the half-lines defined by the tangents and
+   endpoints...and we never recompute the tangent after this.  */
+
+static void
+find_tangent (curve_type curve, bool to_start_point, bool cross_curve,
+  unsigned tangent_surround)
+{
+  vector_type tangent;
+  vector_type **curve_tangent = (to_start_point == true) ? &(CURVE_START_TANGENT (curve))
+                                               : &(CURVE_END_TANGENT (curve));
+  unsigned n_points = 0;
+
+  LOG1 ("  tangent to %s: ", (to_start_point == true) ? "start" : "end");
+
+  if (*curve_tangent == NULL)
+    {
+        MALLOCVAR_NOFAIL(*curve_tangent);
+      do
+        {
+          tangent = find_half_tangent (curve, to_start_point, &n_points,
+            tangent_surround);
+
+          if ((cross_curve == true) || (CURVE_CYCLIC (curve) == true))
+            {
+              curve_type adjacent_curve
+                = (to_start_point == true) ? PREVIOUS_CURVE (curve) : NEXT_CURVE (curve);
+              vector_type tangent2
+                = (to_start_point == false) ? find_half_tangent (adjacent_curve, true, &n_points,
+                tangent_surround) : find_half_tangent (adjacent_curve, true, &n_points,
+                tangent_surround);
+
+              LOG3 ("(adjacent curve half tangent (%.3f,%.3f,%.3f)) ",
+                tangent2.dx, tangent2.dy, tangent2.dz);
+              tangent = Vadd (tangent, tangent2);
+            }
+          tangent_surround--;
+
+        }
+      while (tangent.dx == 0.0 && tangent.dy == 0.0);
+
+      assert (n_points > 0);
+      **curve_tangent = Vmult_scalar (tangent, (float)(1.0 / n_points));
+      if ((CURVE_CYCLIC (curve) == true) && CURVE_START_TANGENT (curve))
+          *CURVE_START_TANGENT (curve) = **curve_tangent;
+      if  ((CURVE_CYCLIC (curve) == true) && CURVE_END_TANGENT (curve))
+          *CURVE_END_TANGENT (curve) = **curve_tangent;
+    }
+  else
+    LOG ("(already computed) ");
+
+  LOG3 ("(%.3f,%.3f,%.3f).\n", (*curve_tangent)->dx, (*curve_tangent)->dy, (*curve_tangent)->dz);
+}
+
+/* Find the change in y and change in x for `tangent_surround' (a global)
+   points along CURVE.  Increment N_POINTS by the number of points we
+   actually look at.  */
+
+static vector_type
+find_half_tangent (curve_type c, bool to_start_point, unsigned *n_points,
+  unsigned tangent_surround)
+{
+  unsigned p;
+  int factor = to_start_point ? 1 : -1;
+  unsigned tangent_index = to_start_point ? 0 : c->length - 1;
+  float_coord tangent_point = CURVE_POINT (c, tangent_index);
+  vector_type tangent = { 0.0, 0.0 };
+  unsigned int surround;
+
+  if ((surround = CURVE_LENGTH (c) / 2) > tangent_surround)
+    surround = tangent_surround;
+
+  for (p = 1; p <= surround; p++)
+    {
+      int this_index = p * factor + tangent_index;
+      float_coord this_point;
+
+      if (this_index < 0 || this_index >= (int) c->length)
+        break;
+
+      this_point = CURVE_POINT (c, p * factor + tangent_index);
+
+      /* Perhaps we should weight the tangent from `this_point' by some
+         factor dependent on the distance from the tangent point.  */
+      tangent = Vadd (tangent,
+                      Vmult_scalar (Psubtract (this_point, tangent_point),
+                                    (float) factor));
+      (*n_points)++;
+    }
+
+  return tangent;
+}
+
+/* When this routine is called, we have computed a spline representation
+   for the digitized curve.  The question is, how good is it?  If the
+   fit is very good indeed, we might have an error of zero on each
+   point, and then WORST_POINT becomes irrelevant.  But normally, we
+   return the error at the worst point, and the index of that point in
+   WORST_POINT.  The error computation itself is the Euclidean distance
+   from the original curve CURVE to the fitted spline SPLINE.  */
+
+static float
+find_error (curve_type curve, spline_type spline, unsigned *worst_point,
+        at_exception_type * exception)
+{
+  unsigned this_point;
+  float total_error = 0.0;
+  float worst_error = FLT_MIN;
+
+  *worst_point = CURVE_LENGTH (curve) + 1;   /* A sentinel value.  */
+
+  for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++)
+    {
+      float_coord curve_point = CURVE_POINT (curve, this_point);
+      float t = CURVE_T (curve, this_point);
+      float_coord spline_point = evaluate_spline (spline, t);
+      float this_error = distance (curve_point, spline_point);
+      if (this_error >= worst_error)
+        {
+         *worst_point = this_point;
+          worst_error = this_error;
+        }
+      total_error += this_error;
+    }
+
+  if (*worst_point == CURVE_LENGTH (curve) + 1)
+    { /* Didn't have any ``worst point''; the error should be zero.  */
+      if (epsilon_equal (total_error, 0.0))
+        LOG ("  Every point fit perfectly.\n");
+      else
+    {
+      LOG("No worst point found; something is wrong");
+      at_exception_warning(exception, "No worst point found; something is wrong");
+    }
+    }
+  else
+    {
+      if (epsilon_equal (total_error, 0.0))
+        LOG ("  Every point fit perfectly.\n");
+      else
+        {
+          LOG5 ("  Worst error (at (%.3f,%.3f,%.3f), point #%u) was %.3f.\n",
+              CURVE_POINT (curve, *worst_point).x,
+              CURVE_POINT (curve, *worst_point).y,
+              CURVE_POINT (curve, *worst_point).z, *worst_point, worst_error);
+          LOG1 ("  Total error was %.3f.\n", total_error);
+          LOG2 ("  Average error (over %u points) was %.3f.\n",
+              CURVE_LENGTH (curve), total_error / CURVE_LENGTH (curve));
+        }
+    }
+
+  return worst_error;
+}
+
+
+/* Lists of array indices (well, that is what we use it for).  */
+
+static index_list_type
+new_index_list (void)
+{
+  index_list_type index_list;
+
+  index_list.data = NULL;
+  INDEX_LIST_LENGTH (index_list) = 0;
+
+  return index_list;
+}
+
+static void
+free_index_list (index_list_type *index_list)
+{
+  if (INDEX_LIST_LENGTH (*index_list) > 0)
+    {
+      free (index_list->data);
+      index_list->data = NULL;
+      INDEX_LIST_LENGTH (*index_list) = 0;
+    }
+}
+
+static void
+append_index (index_list_type *list, unsigned new_index)
+{
+  INDEX_LIST_LENGTH (*list)++;
+  REALLOCARRAY_NOFAIL(list->data, INDEX_LIST_LENGTH(*list));
+  list->data[INDEX_LIST_LENGTH (*list) - 1] = new_index;
+}
+
+
+/* Return the Euclidean distance between P1 and P2.  */
+
+static float
+distance (float_coord p1, float_coord p2)
+{
+  float x = p1.x - p2.x, y = p1.y - p2.y, z = p1.z - p2.z;
+  return (float) sqrt (SQR(x) + SQR(y) + SQR(z));
+}
diff --git a/converter/other/pamtosvg/fit.h b/converter/other/pamtosvg/fit.h
new file mode 100644
index 00000000..529da5c7
--- /dev/null
+++ b/converter/other/pamtosvg/fit.h
@@ -0,0 +1,34 @@
+/* fit.h: convert the pixel representation to splines. */
+
+#ifndef FIT_H_INCLUDED
+#define FIT_H_INCLUDED
+
+#include "autotrace.h"
+#include "image-proc.h"
+#include "pxl-outline.h"
+#include "spline.h"
+#include "exception.h"
+
+/* See fit.c for descriptions of these variables, all of which can be
+   set using options. 
+*/
+typedef at_fitting_opts_type fitting_opts_type;
+
+void
+fit_outlines_to_splines(pixel_outline_list_type  const pixelOutlineList,
+                        fitting_opts_type *      const fittingOptsP,
+                        distance_map_type *      const dist,
+                        unsigned short           const width,
+                        unsigned short           const height,
+                        at_exception_type *      const exception,
+                        at_progress_func               notifyProgress, 
+                        void *                   const progressData,
+                        at_testcancel_func             testCancel,
+                        void *                   const testcancelData,
+                        spline_list_array_type * const splineListArrayP);
+
+/* Get a new set of fitting options */
+fitting_opts_type
+new_fitting_opts(void);
+
+#endif
diff --git a/converter/other/pamtosvg/image-header.h b/converter/other/pamtosvg/image-header.h
new file mode 100644
index 00000000..adcf4771
--- /dev/null
+++ b/converter/other/pamtosvg/image-header.h
@@ -0,0 +1,19 @@
+/* image-header.h: declarations for a generic image header. */
+
+#ifndef IMAGE_HEADER_H
+#define IMAGE_HEADER_H
+
+
+/* The important general information about the image data.
+   See `get_{img,pbm}_header' for the full details of the headers for
+   the particular formats.  */
+typedef struct
+{
+  unsigned short hres, vres;	/* In pixels per inch.  */
+  unsigned short width, height;	/* In bits.  */
+  unsigned short depth;		/* Perhaps the depth?  */
+  unsigned format;		/* (for pbm) Whether packed or not.  */
+} image_header_type;
+
+#endif /* not IMAGE_HEADER_H */
+
diff --git a/converter/other/pamtosvg/image-proc.c b/converter/other/pamtosvg/image-proc.c
new file mode 100644
index 00000000..287e6384
--- /dev/null
+++ b/converter/other/pamtosvg/image-proc.c
@@ -0,0 +1,516 @@
+/* image-proc.c: image processing routines */
+
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+
+#include "mallocvar.h"
+
+#include "message.h"
+
+#include "image-proc.h"
+
+#define BLACK 0
+#define WHITE 0xff
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237
+#endif
+
+#if 0
+struct etyp { int t00, t11, t01, t01s; };
+
+
+static bool get_edge(bitmap_type, int y, int x, struct etyp *t);
+static void check(int v1, int v2, int v3, struct etyp *t);
+#endif
+
+
+/* Allocate storage for a new distance map with the same dimensions
+   as BITMAP and initialize it so that pixels in BITMAP with value
+   TARGET_VALUE are at distance zero and all other pixels are at
+   distance infinity.  Then compute the gray-weighted distance from
+   every non-target point to the nearest target point. */
+
+distance_map_type
+new_distance_map(bitmap_type bitmap, unsigned char target_value, bool padded, at_exception_type * exp)
+{
+    signed x, y;
+    float d, min;
+    distance_map_type dist;
+    unsigned char *b = bitmap.bitmap;
+    unsigned w = bitmap.width;
+    unsigned h = bitmap.height;
+    unsigned spp = bitmap.np;
+
+    dist.height = h; dist.width = w;
+    MALLOCARRAY(dist.d, h);
+    MALLOCARRAY(dist.weight, h);
+    if (dist.d == NULL || dist.weight == NULL)
+        pm_error("Unable to get memory for distance map");
+    for (y = 0; y < (signed) h; y++)
+    {
+        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));
+        
+        MALLOCARRAY(dist.weight[y], w);
+        if (dist.weight[y] == NULL)
+            pm_error("Unable to get memory for distance map");
+    }
+
+    if (spp == 3)
+    {
+      for (y = 0; y < (signed) h; y++)
+      {
+        for (x = 0; x < (signed) w; x++, b += spp)
+        {
+          int gray; float fgray;
+          gray = (int)LUMINANCE(b[0], b[1], b[2]);
+          dist.d[y][x] = (gray == target_value ? 0.0F : 1.0e10F);
+          fgray = gray * 0.0039215686F;  /* = gray / 255.0F */
+          dist.weight[y][x] = 1.0F - fgray;
+/*        dist.weight[y][x] = 1.0F - (fgray * fgray);*/
+/*        dist.weight[y][x] = (fgray < 0.5F ? 1.0F - fgray : -2.0F * fgray * (fgray - 1.0F));*/
+	    }
+      }
+    }
+    else
+    {
+      for (y = 0; y < (signed) h; y++)
+      {
+        for (x = 0; x < (signed) w; x++, b += spp)
+        {
+          int gray; float fgray;
+          gray = b[0];
+          dist.d[y][x] = (gray == target_value ? 0.0F : 1.0e10F);
+          fgray = gray * 0.0039215686F;  /* = gray / 255.0F */
+          dist.weight[y][x] = 1.0F - fgray;
+/*        dist.weight[y][x] = 1.0F - (fgray * fgray);*/
+/*        dist.weight[y][x] = (fgray < 0.5F ? 1.0F - fgray : -2.0F * fgray * (fgray - 1.0F)); */
+        }
+      }
+    }
+
+    /* If the image is padded then border points are all at most
+       one unit away from the nearest target point. */
+    if (padded)
+    {
+        for (y = 0; y < (signed) h; y++)
+        {
+            if (dist.d[y][0] > dist.weight[y][0])
+                dist.d[y][0] = dist.weight[y][0];
+            if (dist.d[y][w - 1] > dist.weight[y][w - 1])
+                dist.d[y][w - 1] = dist.weight[y][w - 1];
+        }
+        for (x = 0; x < (signed) w; x++)
+        {
+            if (dist.d[0][x] > dist.weight[0][x])
+                dist.d[0][x] = dist.weight[0][x];
+            if (dist.d[h - 1][x] > dist.weight[h - 1][x])
+                dist.d[h - 1][x] = dist.weight[h - 1][x];
+        }
+    }
+
+    /* Scan the image from left to right, top to bottom.
+       Examine the already-visited neighbors of each point (those
+       situated above or to the left of it).  Each neighbor knows
+       the distance to its nearest target point; add to this distance
+       the distance from the central point to the neighbor (either
+       sqrt(2) or one) multiplied by the central point's weight
+       (derived from its gray level).  Replace the distance already
+       stored at the central point if the new distance is smaller. */
+    for (y = 1; y < (signed) h; y++)
+    {
+        for (x = 1; x < (signed) w; x++)
+        {
+            if (dist.d[y][x] == 0.0F) continue;
+
+            min = dist.d[y][x];
+
+            /* upper-left neighbor */
+            d = dist.d[y - 1][x - 1] + (float) M_SQRT2 * dist.weight[y][x];
+            if (d < min) min = dist.d[y][x] = d;
+
+            /* upper neighbor */
+            d = dist.d[y - 1][x] + dist.weight[y][x];
+            if (d < min) min = dist.d[y][x] = d;
+
+            /* left neighbor */
+            d = dist.d[y][x - 1] + dist.weight[y][x];
+            if (d < min) min = dist.d[y][x] = d;
+
+            /* upper-right neighbor (except at the last column) */
+            if (x + 1 < (signed) w)
+            {
+                d = dist.d[y - 1][x + 1] + (float) M_SQRT2 * dist.weight[y][x];
+                if (d < min) min = dist.d[y][x] = d;
+            }
+        }
+    }
+
+    /* Same as above, but now scanning right to left, bottom to top. */
+    for (y = h - 2; y >= 0; y--)
+    {
+        for (x = w - 2; x >= 0; x--)
+        {
+            min = dist.d[y][x];
+
+            /* lower-right neighbor */
+            d = dist.d[y + 1][x + 1] + (float) M_SQRT2 * dist.weight[y][x];
+	        if (d < min) min = dist.d[y][x] = d;
+
+            /* lower neighbor */
+            d = dist.d[y + 1][x] + dist.weight[y][x];
+	        if (d < min) min = dist.d[y][x] = d;
+
+            /* right neighbor */
+            d = dist.d[y][x + 1] + dist.weight[y][x];
+	        if (d < min) min = dist.d[y][x] = d;
+
+            /* lower-left neighbor (except at the first column) */
+            if (x - 1 >= 0)
+            {
+                d = dist.d[y + 1][x - 1] + (float) M_SQRT2 * dist.weight[y][x];
+                if (d < min) min = dist.d[y][x] = d;
+            }
+        }
+    }
+    return dist;
+}
+
+
+/* Free the dynamically-allocated storage associated with a distance map. */
+
+void
+free_distance_map(distance_map_type *dist)
+{
+    unsigned y, h;
+
+    if (!dist) return;
+
+    h = dist->height;
+
+    if (dist->d != NULL)
+    {
+	for (y = 0; y < h; y++)
+	    free(dist->d[y]);
+        free(dist->d);
+    }
+    if (dist->weight != NULL)
+    {
+	for (y = 0; y < h; y++)
+	    free(dist->weight[y]);
+        free(dist->weight);
+    }
+}
+
+
+#if 0
+void
+medial_axis(bitmap_type *bitmap, distance_map_type *dist,
+            bool bgSpec, pixel bg_color)
+{
+    unsigned x, y, test;
+    unsigned w, h;
+    unsigned char *b;
+    float **d, f;
+    pixel bg;
+
+    assert(bitmap != NULL);
+
+    assert(BITMAP_PLANES(*bitmap) == 1);
+
+    b = BITMAP_BITS(*bitmap);
+    assert(b != NULL);
+    assert(dist != NULL);
+    d = dist->d;
+    assert(d != NULL);
+
+    h = BITMAP_HEIGHT(*dist);
+    w = BITMAP_WIDTH(*dist);
+    assert(BITMAP_WIDTH(*bitmap) == w && BITMAP_HEIGHT(*bitmap) == h);
+
+    if (bgSpec)
+        bg = bg_color;
+    else 
+        PPM_ASSIGN(bg, 255, 255, 255);
+
+    f = d[0][0] + 0.5;
+    test = (f < d[1][0]) + (f < d[1][1]) + (f < d[0][1]);
+    if (test > 1) b[0] = PPM_GETR(bg);
+
+    f = d[0][w-1] + 0.5;
+    test = (f < d[1][w-1]) + (f < d[1][w-2]) + (f < d[0][w-2]);
+    if (test > 1) b[w-1] = PPM_GETR(bg);
+
+    for (x = 1; x < w - 1; x++)
+    {
+	    f = d[0][x] + 0.5;
+	    test = (f < d[0][x-1]) + (f < d[0][x+1]) + (f < d[1][x-1])
+	        + (f < d[1][x]) + (f < d[1][x+1]);
+	    if (test > 1) b[x] = PPM_GETR(bg);
+    }
+    b += w;
+
+    for (y = 1; y < h - 1; y++)
+    {
+	    f = d[y][0] + 0.5;
+	    test = (f < d[y-1][0]) + (f < d[y-1][1]) + (f < d[y][1])
+	        + (f < d[y+1][0]) + (f < d[y+1][1]);
+	    if (test > 1) b[0] = PPM_GETR(bg);
+
+	    for (x = 1; x < w - 1; x++)
+		{
+	        f = d[y][x] + 0.5;
+	        test = (f < d[y-1][x-1]) + (f < d[y-1][x]) + (f < d[y-1][x+1])
+		    + (f < d[y][x-1]) + (f < d[y][x+1])
+		    + (f < d[y+1][x-1]) + (f < d[y+1][x]) + (f < d[y+1][x+1]);
+	        if (test > 1) b[x] = PPM_GETR(bg)
+		}
+
+	    f = d[y][w-1] + 0.5;
+	    test = (f < d[y-1][w-1]) + (f < d[y-1][w-2]) + (f < d[y][w-2])
+	        + (f < d[y+1][w-1]) + (f < d[y+1][w-2]);
+	    if (test > 1)
+	        b[w-1] = PPM_GETR(bg);
+
+        b += w;
+    }
+
+    for (x = 1; x < w - 1; x++)
+    {
+	    f = d[h-1][x] + 0.5;
+	    test = (f < d[h-1][x-1]) + (f < d[h-1][x+1])
+	        + (f < d[h-2][x-1]) + (f < d[h-2][x]) + (f < d[h-2][x+1]);
+	    if (test > 1) b[x] = PPM_GETR(bg);
+    }
+
+    f = d[h-1][0] + 0.5;
+    test = (f < d[h-2][0]) + (f < d[h-2][1]) + (f < d[h-1][1]);
+    if (test > 1) b[0] = PPM_GETR(bg);
+
+    f = d[h-1][w-1] + 0.5;
+    test = (f < d[h-2][w-1]) + (f < d[h-2][w-2]) + (f < d[h-1][w-2]);
+    if (test > 1) b[w-1] = PPM_GETR(bg);
+}
+#endif
+
+
+/* Binarize a grayscale or color image. */
+
+void
+binarize(bitmap_type *bitmap)
+{
+    unsigned i, npixels, spp;
+    unsigned char *b;
+
+    assert(bitmap != NULL);
+    assert(bitmap->bitmap != NULL);
+
+    b = bitmap->bitmap;
+    spp = bitmap->np;
+    npixels = bitmap->width * bitmap->height;
+
+    if (spp == 1)
+    {
+	    for (i = 0; i < npixels; i++)
+	        b[i] = (b[i] > GRAY_THRESHOLD ? WHITE : BLACK);
+    }
+    else if (spp == 3)
+    {
+	    unsigned char *rgb = b;
+	    for (i = 0; i < npixels; i++, rgb += 3)
+		{
+	        b[i] = (LUMINANCE(rgb[0], rgb[1], rgb[2]) > GRAY_THRESHOLD
+		        ? WHITE : BLACK);
+		}
+	    REALLOCARRAY_NOFAIL(bitmap->bitmap, npixels);
+	    bitmap->np = 1;
+    }
+    else
+    {
+	    WARNING1("binarize: %u-plane images are not supported", spp);
+    }
+}
+
+
+#if 0
+/* Thin a binary image, replacing the original image with the thinned one. */
+
+bitmap_type
+ip_thin(bitmap_type input_b)
+{
+    unsigned y, x, i;
+    bool k, again;
+    struct etyp t;
+    unsigned w = BITMAP_WIDTH(input_b);
+    unsigned h = BITMAP_HEIGHT(input_b);
+    size_t num_bytes = w * h;
+    bitmap_type b = input_b;
+
+    if (BITMAP_PLANES(input_b) != 1)
+    {
+	    FATAL1("thin: single-plane image required; "
+	        "%u-plane images cannot be thinned", BITMAP_PLANES(input_b));
+	    return b;
+    }
+
+    /* Process and return a copy of the input image. */
+    MALLOCARRAY(b.bitmap, num_bytes);
+    if (b.bitmap == NULL)
+        pm_error("Unable to get memory for bitmap");
+    memcpy(b.bitmap, input_b.bitmap, num_bytes);
+
+    /* Set background pixels to zero, foreground pixels to one. */
+    for (i = 0; i < num_bytes; i++)
+	b.bitmap[i] = (b.bitmap[i] == BLACK ? 1 : 0);
+
+    again = true;
+    while (again)
+    {
+	again = false;
+
+	for (y = 1; y < h - 1; y++)
+	{
+	    for (x = 1; x < w - 1; x++)
+	    {
+		    /* During processing, pixels are used to store edge
+		       type codes, so we can't just test for WHITE or BLACK. */
+		    if (*BITMAP_PIXEL(b, y, x) == 0) continue;
+
+		    k = (!get_edge(b, y, x, &t)
+		        || (get_edge(b, y, x+1, &t) && *BITMAP_PIXEL(b, y-1, x)
+			    && *BITMAP_PIXEL(b, y+1, x))
+		        || (get_edge(b, y+1, x, &t) && *BITMAP_PIXEL(b, y, x-1)
+			    && *BITMAP_PIXEL(b, y, x+1))
+		        || (get_edge(b, y, x+1, &t) && get_edge(b, y+1, x+1, &t)
+			    && get_edge(b, y+1, x, &t)));
+		    if (k) continue;
+
+		    get_edge(b, y, x, &t);
+		    if (t.t01) *BITMAP_PIXEL(b, y, x) |= 4;
+		    *BITMAP_PIXEL(b, y, x) |= 2;
+		    again = true;
+	    }
+	}
+
+	for (y = 0; y < h; y++)
+	    for (x = 0; x < w; x++)
+		    if (*BITMAP_PIXEL(b, y, x) & 02) *BITMAP_PIXEL(b, y, x) = 0;
+
+	for (y = 1; y < h - 1; y++)
+	{
+	    for (x = 1; x < w - 1; x++)
+	    {
+		    if (*BITMAP_PIXEL(b, y, x) == 0) continue;
+
+		    k = (!get_edge(b, y, x, &t)
+		        || ((*BITMAP_PIXEL(b, y, x) & 04) == 0)
+		        || (get_edge(b, y+1, x, &t) && (*BITMAP_PIXEL(b, y, x-1))
+			    && *BITMAP_PIXEL(b, y, x+1))
+		        || (get_edge(b, y, x+1, &t) && *BITMAP_PIXEL(b, y-1, x)
+			    && *BITMAP_PIXEL(b, y+1, x))
+		        || (get_edge(b, y+1, x, &t) && get_edge(b, y, x+1, &t)
+			    && get_edge(b, y+1, x+1, &t)));
+		    if (k) continue;
+
+		    *BITMAP_PIXEL(b, y, x) |= 02;
+		    again = true;
+	    }
+	}
+
+	for (y = 0; y < h; y++)
+	{
+	    for (x = 0; x < w; x++)
+	    {
+		    if (*BITMAP_PIXEL(b, y, x) & 02) *BITMAP_PIXEL(b, y, x) = 0;
+		    else if (*BITMAP_PIXEL(b, y, x) > 0) *BITMAP_PIXEL(b, y, x) = 1;
+	    }
+	}
+    }
+
+    /* Staircase removal; northward bias. */
+    for (y = 1; y < h - 1; y++)
+    {
+	    for (x = 1; x < w - 1; x++)
+		{
+	        if (*BITMAP_PIXEL(b, y, x) == 0) continue;
+
+	        k = !(*BITMAP_PIXEL(b, y-1, x)
+		        && ((*BITMAP_PIXEL(b, y, x+1) && !*BITMAP_PIXEL(b, y-1, x+1)
+		        && !*BITMAP_PIXEL(b, y+1, x-1)
+		        && (!*BITMAP_PIXEL(b, y, x-1) || !*BITMAP_PIXEL(b, y+1, x)))
+		        || (*BITMAP_PIXEL(b, y, x-1) && !*BITMAP_PIXEL(b, y-1, x-1)
+		        && !*BITMAP_PIXEL(b, y+1, x+1) &&
+		        (!*BITMAP_PIXEL(b, y, x+1) || !*BITMAP_PIXEL(b, y+1, x)))));
+	        if (k) continue;
+
+	        *BITMAP_PIXEL(b, y, x) |= 02;
+		}
+    }
+    for (y = 0; y < h; y++)
+    {
+	    for (x = 0; x < w; x++)
+		{
+	        if (*BITMAP_PIXEL(b, y, x) & 02) *BITMAP_PIXEL(b, y, x) = 0;
+	        else if (*BITMAP_PIXEL(b, y, x) > 0) *BITMAP_PIXEL(b, y, x) = 1;
+		}
+    }
+
+    /* Southward bias */
+    for (y = 1; y < h - 1; y++)
+    {
+	    for (x = 1; x < w - 1; x++)
+		{
+	        if (*BITMAP_PIXEL(b, y, x) == 0) continue;
+
+	        k = !(*BITMAP_PIXEL(b, y+1, x)
+		    && ((*BITMAP_PIXEL(b, y, x+1) && !*BITMAP_PIXEL(b, y+1, x+1)
+		    && !*BITMAP_PIXEL(b, y-1, x-1) && (!*BITMAP_PIXEL(b, y, x-1)
+		    || !*BITMAP_PIXEL(b, y-1, x))) || (*BITMAP_PIXEL(b, y, x-1)
+		    && !*BITMAP_PIXEL(b, y+1, x-1) && !*BITMAP_PIXEL(b, y-1, x+1)
+		    && (!*BITMAP_PIXEL(b, y, x+1) || !*BITMAP_PIXEL(b, y-1, x)) )));
+	        if (k) continue;
+
+	        *BITMAP_PIXEL(b, y, x) |= 02;
+		}
+    }
+    for (y = 0; y < h; y++)
+    {
+	    for (x = 0; x < w; x++)
+		{
+	        if (*BITMAP_PIXEL(b, y, x) & 02) *BITMAP_PIXEL(b, y, x) = 0;
+	        else if (*BITMAP_PIXEL(b, y, x) > 0) *BITMAP_PIXEL(b, y, x) = 1;
+		}
+    }
+
+    /* Set background pixels to WHITE, foreground pixels to BLACK. */
+    for (i = 0; i < num_bytes; i++)
+	b.bitmap[i] = (b.bitmap[i] == 0 ? WHITE : BLACK);
+    return b;
+}
+
+
+bool get_edge(bitmap_type b, int y, int x, struct etyp *t)
+{
+    t->t00 = 0; t->t01 = 0; t->t01s = 0; t->t11 = 0;
+    check(*BITMAP_PIXEL(b, y - 1, x - 1), *BITMAP_PIXEL(b, y - 1, x),
+	*BITMAP_PIXEL(b, y - 1, x + 1), t);
+    check(*BITMAP_PIXEL(b, y - 1, x + 1), *BITMAP_PIXEL(b, y, x + 1),
+	*BITMAP_PIXEL(b, y + 1, x + 1), t);
+    check(*BITMAP_PIXEL(b, y + 1, x + 1), *BITMAP_PIXEL(b, y + 1, x),
+	*BITMAP_PIXEL(b, y + 1, x - 1), t);
+    check(*BITMAP_PIXEL(b, y + 1, x - 1), *BITMAP_PIXEL(b, y, x - 1),
+	*BITMAP_PIXEL(b, y - 1, x - 1), t);
+    return *BITMAP_PIXEL(b, y, x) && t->t00 && t->t11 && !t->t01s;
+}
+
+
+void check(int v1, int v2, int v3, struct etyp *t)
+{
+    if (!v2 && (!v1 || !v3)) t->t00 = 1;
+    if (v2 && (v1 || v3)) t->t11 = 1;
+    if ((!v1 && v2) || (!v2 && v3)) { t->t01s = t->t01; t->t01 = 1; }
+}
+#endif
diff --git a/converter/other/pamtosvg/image-proc.h b/converter/other/pamtosvg/image-proc.h
new file mode 100644
index 00000000..a5b86ec1
--- /dev/null
+++ b/converter/other/pamtosvg/image-proc.h
@@ -0,0 +1,42 @@
+/* image-proc.h: image processing routines */
+
+#ifndef IMAGE_PROC_H
+#define IMAGE_PROC_H
+
+#include "bitmap.h"
+#include "exception.h"
+
+
+/* Threshold for binarizing a monochrome image */
+#define GRAY_THRESHOLD 225
+
+/* RGB to grayscale */
+#define LUMINANCE(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11 + 0.5)
+
+
+typedef struct
+{
+  unsigned height, width;
+  float **weight;
+  float **d;
+} distance_map_type;
+
+
+/* Allocate and compute a new distance map. */
+extern distance_map_type new_distance_map(bitmap_type,
+    unsigned char target_value, bool padded,
+					  at_exception_type * exp);
+
+/* Free the dynamically-allocated storage associated with a distance map. */
+extern void free_distance_map(distance_map_type*);
+
+
+/* Binarize a grayscale or color image. */
+extern void binarize(bitmap_type*);
+
+
+/* Thin a binary image, replacing the original image with the thinned one. */
+extern bitmap_type ip_thin(bitmap_type);
+
+#endif /* not IMAGE_PROC_H */
+
diff --git a/converter/other/pamtosvg/logreport.c b/converter/other/pamtosvg/logreport.c
new file mode 100644
index 00000000..7d726584
--- /dev/null
+++ b/converter/other/pamtosvg/logreport.c
@@ -0,0 +1,17 @@
+/* logreport.c: showing information to the user. */
+
+#include "logreport.h"
+#include "message.h"
+
+/* Says whether to output detailed progress reports, i.e., all the data
+   on the fitting, as we run.  (-log)  */
+FILE *log_file = NULL;
+
+
+void
+flush_log_output (void)
+{
+  if (log_file)
+    fflush (log_file);
+}
+
diff --git a/converter/other/pamtosvg/logreport.h b/converter/other/pamtosvg/logreport.h
new file mode 100644
index 00000000..577da8df
--- /dev/null
+++ b/converter/other/pamtosvg/logreport.h
@@ -0,0 +1,28 @@
+/* logreport.h: status reporting routines. */
+
+#ifndef LOGREPORT_H
+#define LOGREPORT_H
+
+#include <stdio.h>
+
+/* The file we write information to.  */
+extern FILE *at_log_file;
+#define log_file at_log_file
+
+extern void flush_log_output (void);
+
+#define LOG(s)								\
+  do { if (log_file) fputs (s, log_file); } while (0)
+#define LOG1(s, e)							\
+  do { if (log_file) fprintf (log_file, s, e); } while (0)
+#define LOG2(s, e1, e2)							\
+  do { if (log_file) fprintf (log_file, s, e1, e2); } while (0)
+#define LOG3(s, e1, e2, e3)						\
+  do { if (log_file) fprintf (log_file, s, e1, e2, e3); } while (0)
+#define LOG4(s, e1, e2, e3, e4)						\
+  do { if (log_file) fprintf (log_file, s, e1, e2, e3, e4); } while (0)
+#define LOG5(s, e1, e2, e3, e4, e5)					\
+  do { if (log_file) fprintf (log_file, s, e1, e2, e3, e4, e5); } while (0)
+
+#endif /* not LOGREPORT_H */
+
diff --git a/converter/other/pamtosvg/message.h b/converter/other/pamtosvg/message.h
new file mode 100644
index 00000000..0a226206
--- /dev/null
+++ b/converter/other/pamtosvg/message.h
@@ -0,0 +1,47 @@
+/* message.h: extend the standard programming environment a little. */
+
+#ifndef MESSAGE_H
+#define MESSAGE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "logreport.h"
+
+/* 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)
+
+#define FATAL(s)							\
+  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: ")
+#define END_WARNING() fputs (".\n", stderr); } while (0)
+
+#define WARNING(s)							\
+  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/output-svg.c b/converter/other/pamtosvg/output-svg.c
new file mode 100644
index 00000000..53a8d4fd
--- /dev/null
+++ b/converter/other/pamtosvg/output-svg.c
@@ -0,0 +1,130 @@
+/* output-svg.h - output in SVG format
+
+   Copyright (C) 1999, 2000, 2001 Bernhard Herzog
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser 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. */
+
+#include "spline.h"
+#include "output-svg.h"
+
+
+
+static void
+outSplineList(FILE *           const fileP,
+              spline_list_type const splineList,
+              unsigned int     const height) {
+              
+    unsigned splineSeq;
+        
+    for (splineSeq = 0;
+         splineSeq < SPLINE_LIST_LENGTH(splineList);
+         ++splineSeq) {
+        
+        spline_type const spline = SPLINE_LIST_ELT(splineList, splineSeq);
+        
+        if (SPLINE_DEGREE(spline) == LINEARTYPE) {
+            fprintf(fileP, "L%g %g",
+                    END_POINT(spline).x, height - END_POINT(spline).y);
+        } else
+            fprintf(fileP, "C%g %g %g %g %g %g",
+                    CONTROL1(spline).x, height  - CONTROL1(spline).y,
+                    CONTROL2(spline).x, height  - CONTROL2(spline).y,
+                    END_POINT(spline).x, height - END_POINT(spline).y);
+    }
+}
+
+
+
+static void
+out_splines(FILE *                 const fileP,
+            spline_list_array_type const shape,
+            unsigned int           const height) {
+
+    unsigned listSeq;
+    pixel lastColor;
+    
+    PPM_ASSIGN(lastColor, 0, 0, 0);
+    
+    for (listSeq = 0;
+         listSeq < SPLINE_LIST_ARRAY_LENGTH(shape);
+         ++listSeq) {
+        
+        spline_list_type const splineList =
+            SPLINE_LIST_ARRAY_ELT(shape, listSeq);
+        spline_type const first = SPLINE_LIST_ELT(splineList, 0);
+
+        if (listSeq == 0 || !PPM_EQUAL(splineList.color, lastColor)) {
+            if (listSeq > 0) {
+                /* Close previous <path> element */
+                if (!(shape.centerline || splineList.open))
+                    fputs("z", fileP);
+                fputs("\"/>\n", fileP);
+            }
+            /* Open new <path> element */
+            fprintf(fileP, "<path style=\"%s:#%02x%02x%02x; %s:none;\" d=\"",
+                    (shape.centerline || splineList.open) ? "stroke" : "fill",
+                    PPM_GETR(splineList.color),
+                    PPM_GETG(splineList.color),
+                    PPM_GETB(splineList.color),
+                    (shape.centerline || splineList.open) ? "fill" : "stroke");
+        }
+        fprintf(fileP, "M%g %g",
+                START_POINT(first).x, height - START_POINT(first).y);
+
+        outSplineList(fileP, splineList, height);
+
+        lastColor = splineList.color;
+    }
+
+    if (SPLINE_LIST_ARRAY_LENGTH(shape) > 0) {
+        spline_list_type const lastSplineList =
+            SPLINE_LIST_ARRAY_ELT(shape, SPLINE_LIST_ARRAY_LENGTH(shape)-1);
+
+        if (!(shape.centerline || lastSplineList.open))
+            fputs("z", fileP);
+
+        /* Close last <path> element */
+        fputs("\"/>\n", fileP);
+    }
+}
+
+
+
+int
+output_svg_writer(FILE *                    const fileP,
+                  const char *              const name,
+                  int                       const llx,
+                  int                       const lly,
+                  int                       const urx,
+                  int                       const ury, 
+                  at_output_opts_type *     const opts,
+                  at_spline_list_array_type const shape,
+                  at_msg_func                     msg_func, 
+                  void *                    const msg_data) {
+
+    int const width  = urx - llx;
+    int const height = ury - lly;
+
+    fputs("<?xml version=\"1.0\" standalone=\"yes\"?>\n", fileP);
+
+    fprintf(fileP, "<svg width=\"%d\" height=\"%d\">\n", width, height);
+
+    out_splines(fileP, shape, height);
+
+    fputs("</svg>\n", fileP);
+    
+    return 0;
+}
diff --git a/converter/other/pamtosvg/output-svg.h b/converter/other/pamtosvg/output-svg.h
new file mode 100644
index 00000000..46fc8f8f
--- /dev/null
+++ b/converter/other/pamtosvg/output-svg.h
@@ -0,0 +1,37 @@
+/* output-svg.h - output in SVG format
+
+   Copyright (C) 1999, 2000, 2001 Bernhard Herzog
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser 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. */
+
+#ifndef OUTPUT_SVG_H
+#define OUTPUT_SVG_H
+
+int
+output_svg_writer(FILE *                    const file,
+                  const char *              const name,
+                  int                       const llx,
+                  int                       const lly,
+                  int                       const urx,
+                  int                       const ury, 
+                  at_output_opts_type *     const opts,
+                  at_spline_list_array_type const shape,
+                  at_msg_func                     msg_func, 
+                  void *                    const msg_data);
+
+
+#endif /* not OUTPUT_SVG_H */
+
diff --git a/converter/other/pamtosvg/pamtosvg.c b/converter/other/pamtosvg/pamtosvg.c
new file mode 100644
index 00000000..31597a4a
--- /dev/null
+++ b/converter/other/pamtosvg/pamtosvg.c
@@ -0,0 +1,395 @@
+/* main.c: main driver for autotrace -- convert bitmaps to splines. */
+
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+
+#include "autotrace.h"
+#include "message.h"
+#include "logreport.h"
+#include "output-svg.h"
+#include "bitmap.h"
+
+#define dot_printer_max_column 50
+#define dot_printer_char '|'
+
+
+
+static void
+readImageToBitmap(FILE *            const ifP,
+                  at_bitmap_type ** const bitmapPP) {
+
+    at_bitmap_type * bitmapP;
+    struct pam pam;
+    tuple ** tuples;
+    uint row;
+    tuple * row255;
+
+    MALLOCVAR_NOFAIL(bitmapP);
+
+    tuples = pnm_readpam(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+
+    bitmapP->width  = pam.width;
+    bitmapP->height = pam.height;
+    bitmapP->np     = pam.depth;
+
+    MALLOCARRAY(bitmapP->bitmap, pam.width * pam.height * pam.depth);
+
+    row255 = pnm_allocpamrow(&pam);
+
+    for (row = 0; row < pam.height; ++row) {
+        unsigned int col;
+
+        pnm_scaletuplerow(&pam, row255, tuples[row], 255);
+        
+        for (col = 0; col < pam.width; ++col) {
+            unsigned int plane;
+
+            for (plane = 0; plane < pam.depth; ++plane) {
+                unsigned int const bitmapIndex = 
+                    (row * pam.width + col) * pam.depth + plane;
+                bitmapP->bitmap[bitmapIndex] = row255[col][plane];
+            }
+        }
+    }
+    pnm_freepamrow(row255);
+    pnm_freepamarray(tuples, &pam);
+    
+    *bitmapPP = bitmapP;
+}
+
+
+
+static void
+dotPrinter(float  const percentage,
+           void * const clientData) {
+
+    int * const currentP = (int *)clientData;
+    float const unit     = (float)1.0 / (float)(dot_printer_max_column) ;
+    int   const maximum  = (int)(percentage / unit);
+    
+    while (*currentP < maximum) {
+        fputc(dot_printer_char, stderr);
+        (*currentP)++;
+    }
+}
+
+
+
+static void
+exceptionHandler(const char * const msg,
+                 at_msg_type  const type,
+                 void *       const data) {
+
+    if (type == AT_MSG_FATAL)
+        pm_error("%s", msg);
+    else if (type == AT_MSG_WARNING)
+        pm_message("%s", msg);
+    else
+        exceptionHandler("Wrong type of msg", AT_MSG_FATAL, NULL);
+}
+
+
+
+struct cmdlineInfo {
+    const char * inputFileName;
+    float        align_threshold;
+    unsigned int backgroundSpec;
+    pixel        background_color;
+    unsigned int centerline;
+    float        corner_always_threshold;
+    unsigned int corner_surround;
+    float        corner_threshold;
+    unsigned int dpi;
+    float        error_threshold;
+    unsigned int filter_iterations;
+    float        line_reversion_threshold;
+    float        line_threshold;
+    unsigned int log;
+    unsigned int preserve_width;
+    unsigned int remove_adjacent_corners;
+    unsigned int tangent_surround;
+    unsigned int report_progress;
+    float        width_weight_factor;
+};
+
+
+static void 
+parseCommandLine(int argc, 
+                 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 optParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+
+    const char * background_colorOpt;
+  
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "align-threshold",     OPT_FLOAT,
+            &cmdlineP->align_threshold,  NULL,                              0);
+    OPTENT3(0, "background-color",    OPT_STRING,
+            &background_colorOpt,        &cmdlineP->backgroundSpec,         0);
+    OPTENT3(0, "centerline",          OPT_FLAG,
+            NULL,                        &cmdlineP->centerline,             0);
+    OPTENT3(0, "corner-always-threshold", OPT_FLOAT, 
+            &cmdlineP->corner_always_threshold, NULL,                       0);
+    OPTENT3(0, "corner-surround",     OPT_UINT,
+            &cmdlineP->corner_surround,  NULL,                              0);
+    OPTENT3(0, "corner-threshold",    OPT_FLOAT,
+            &cmdlineP->corner_threshold, NULL,                              0);
+    OPTENT3(0, "dpi",                 OPT_UINT,
+            &cmdlineP->dpi,              NULL,                              0);
+    OPTENT3(0, "error-threshold",     OPT_FLOAT,
+            &cmdlineP->error_threshold,  NULL,                              0);
+    OPTENT3(0, "filter-iterations",   OPT_UINT,
+            &cmdlineP->filter_iterations, NULL,                             0);
+    OPTENT3(0, "line-reversion-threshold", OPT_FLOAT,
+            &cmdlineP->line_reversion_threshold, NULL,                    0);
+    OPTENT3(0, "line-threshold",      OPT_FLOAT,
+            &cmdlineP->line_threshold, NULL,                                0);
+    OPTENT3(0, "log",                 OPT_FLAG,
+            NULL,                         &cmdlineP->log,                   0);
+    OPTENT3(0, "preserve-width",      OPT_FLAG,
+            NULL,                         &cmdlineP->preserve_width,        0);
+    OPTENT3(0, "remove-adjacent-corners", OPT_UINT,
+            NULL,                       &cmdlineP->remove_adjacent_corners, 0);
+    OPTENT3(0, "tangent-surround",    OPT_UINT,    
+            &cmdlineP->tangent_surround, NULL,                              0);
+    OPTENT3(0, "report-progress",     OPT_FLAG,
+            NULL,                       &cmdlineP->report_progress,         0);
+    OPTENT3(0, "width-weight-factor", OPT_FLOAT,    
+            &cmdlineP->width_weight_factor, NULL,                           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 */
+
+    /* Set some defaults the lazy way (using multiple setting of variables) */
+
+    cmdlineP->corner_always_threshold  = 60.0;
+    cmdlineP->corner_surround          = 4;
+    cmdlineP->corner_threshold         = 100.0;
+    cmdlineP->error_threshold          = 2.0;
+    cmdlineP->filter_iterations        = 4;
+    cmdlineP->line_reversion_threshold = 0.01;
+    cmdlineP->line_threshold           = 1.0;
+    cmdlineP->tangent_surround         = 3;
+    cmdlineP->width_weight_factor      = 6.0;
+
+    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (cmdlineP->backgroundSpec)
+        cmdlineP->background_color = ppm_parsecolor(background_colorOpt, 255);
+
+    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);
+    }
+}
+
+
+
+static void
+fitSplines(at_bitmap_type *             const bitmapP,
+           struct cmdlineInfo           const cmdline,
+           at_msg_func                        exceptionHandler,
+           at_progress_func                   progressFunc,
+           at_spline_list_array_type ** const splinesPP) {
+
+    unsigned int progressStat;
+    at_fitting_opts_type * fittingOptsP;
+
+    progressStat = 0;
+           
+    fittingOptsP = at_fitting_opts_new();
+
+    fittingOptsP->backgroundSpec           = cmdline.backgroundSpec;
+    fittingOptsP->background_color         = cmdline.background_color;
+    fittingOptsP->corner_always_threshold  = cmdline.corner_always_threshold;
+    fittingOptsP->corner_surround          = cmdline.corner_surround;
+    fittingOptsP->corner_threshold         = cmdline.corner_threshold;
+    fittingOptsP->error_threshold          = cmdline.error_threshold;
+    fittingOptsP->filter_iterations        = cmdline.filter_iterations;
+    fittingOptsP->line_reversion_threshold = cmdline.line_reversion_threshold;
+    fittingOptsP->line_threshold           = cmdline.line_threshold;
+    fittingOptsP->remove_adjacent_corners  = cmdline.remove_adjacent_corners;
+    fittingOptsP->tangent_surround         = cmdline.tangent_surround;
+    fittingOptsP->centerline               = cmdline.centerline;
+    fittingOptsP->preserve_width           = cmdline.preserve_width;
+    fittingOptsP->width_weight_factor      = cmdline.width_weight_factor;
+
+    *splinesPP = at_splines_new_full(bitmapP, fittingOptsP,
+                                     exceptionHandler, NULL,
+                                     progressFunc, &progressStat,
+                                     NULL, NULL);
+
+    at_fitting_opts_free(fittingOptsP);
+}
+  
+
+
+static void
+writeSplines(at_spline_list_array_type * const splinesP,
+             struct cmdlineInfo          const cmdline,
+             at_output_write_func              outputWriter,
+             FILE *                      const ofP,
+             at_msg_func                       exceptionHandler) {
+
+    at_output_opts_type * outputOptsP;
+
+    outputOptsP = at_output_opts_new();
+    outputOptsP->dpi = cmdline.dpi;
+    
+    at_splines_write(outputWriter, ofP, outputOptsP,
+                     splinesP, exceptionHandler, NULL);
+
+    at_output_opts_free(outputOptsP);
+}  
+
+
+
+static const char *
+filenameRoot(const char * const filename) {
+/*----------------------------------------------------------------------------
+   Return the root of the filename.  E.g. for /home/bryanh/foo.ppm,
+   return 'foo'.
+-----------------------------------------------------------------------------*/
+    char * buffer;
+    bool foundSlash;
+    unsigned int slashPos;
+    bool foundDot;
+    unsigned int dotPos;
+    unsigned int rootStart, rootEnd;
+    unsigned int i, j;
+
+    for (i = 0, foundSlash = FALSE; i < strlen(filename); ++i) {
+        if (filename[i] == '/') {
+            foundSlash = TRUE;
+            slashPos = i;
+        }
+    }
+
+    if (foundSlash)
+        rootStart = slashPos + 1;
+    else
+        rootStart = 0;
+
+    for (i = rootStart, foundDot = FALSE; i < strlen(filename); ++i) {
+        if (filename[i] == '.') {
+            foundDot = TRUE;
+            dotPos = i;
+        }
+    }
+
+    if (foundDot)
+        rootEnd = dotPos;
+    else
+        rootEnd = strlen(filename);
+
+    MALLOCARRAY(buffer, rootEnd - rootStart + 1);
+    
+    j = 0;
+    for (i = rootStart; i < rootEnd; ++i)
+        buffer[j++] = filename[i];
+
+    buffer[j] = '\0';
+    
+    return buffer;
+}
+
+
+
+static void
+openLogFile(FILE **      const logFileP,
+            const char * const inputRootName) {
+
+    const char * logfileName;
+
+    asprintfN(&logfileName, "%s.log", inputRootName);
+
+    *logFileP = pm_openw(logfileName);
+
+    strfree(logfileName);
+}
+    
+
+
+int
+main(int argc, char * argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    at_bitmap_type * bitmapP;
+    at_spline_list_array_type * splinesP;
+    at_progress_func progressReporter;
+    const char * inputRootName;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    inputRootName = filenameRoot(cmdline.inputFileName);
+    if (inputRootName == NULL)
+        pm_error("Can't find the root portion of file name '%s'",
+                 cmdline.inputFileName);
+    
+    if (cmdline.log)
+        openLogFile(&log_file, inputRootName);
+
+    readImageToBitmap(ifP, &bitmapP);
+    
+    if (cmdline.report_progress) {
+        progressReporter = dotPrinter;
+        fprintf(stderr, "%-15s", cmdline.inputFileName);
+    } else
+        progressReporter = NULL;
+
+    fitSplines(bitmapP, cmdline, exceptionHandler,
+               progressReporter, &splinesP);
+
+    writeSplines(splinesP, cmdline, output_svg_writer, stdout,
+                 exceptionHandler);
+
+    strfree(inputRootName);
+
+    pm_close(stdout);
+    pm_close(ifP);
+    if (cmdline.log)
+        pm_close(log_file);
+    
+    at_splines_free(splinesP);
+    at_bitmap_free(bitmapP);
+
+    if (cmdline.report_progress)
+        fputs("\n", stderr);
+    
+    return 0;
+}
diff --git a/converter/other/pamtosvg/pamtosvg.test b/converter/other/pamtosvg/pamtosvg.test
new file mode 100644
index 00000000..df3a07d3
--- /dev/null
+++ b/converter/other/pamtosvg/pamtosvg.test
@@ -0,0 +1,6 @@
+# This will print nothing if successful (diff will find no difference)
+ppmmake black 20 20 | ppmdraw -script="line 5 2 15 17" | pamtosvg | \
+  diff testline.svg -
+
+# This will print nothing if successful (diff will find no difference)
+pamtosvg ../../../../testgrid.pbm | diff testgrid.svg -
diff --git a/converter/other/pamtosvg/point.h b/converter/other/pamtosvg/point.h
new file mode 100644
index 00000000..037ec8a0
--- /dev/null
+++ b/converter/other/pamtosvg/point.h
@@ -0,0 +1,8 @@
+#ifndef POINT_H_INCLUDED
+#define POINT_H_INCLUDED
+
+typedef struct {
+  float x, y, z;
+} float_coord;
+
+#endif
diff --git a/converter/other/pamtosvg/pxl-outline.c b/converter/other/pamtosvg/pxl-outline.c
new file mode 100644
index 00000000..68cd0565
--- /dev/null
+++ b/converter/other/pamtosvg/pxl-outline.c
@@ -0,0 +1,1370 @@
+/* pxl-outline.c: find the outlines of a bitmap image; each outline is
+   made up of one or more pixels; and each pixel participates via one
+   or more edges.
+*/
+
+#include <assert.h>
+
+#include "mallocvar.h"
+
+#include "message.h"
+#include "bitmap.h"
+#include "bitmap.h"
+#include "logreport.h"
+#include "pxl-outline.h"
+
+/* We consider each pixel to consist of four edges, and we travel along
+   edges, instead of through pixel centers.  This is necessary for those
+   unfortunate times when a single pixel is on both an inside and an
+   outside outline.
+
+   The numbers chosen here are not arbitrary; the code that figures out
+   which edge to move to depends on particular values.  See the
+   `TRY_PIXEL' macro in `edge.c'.  To emphasize this, I've written in the
+   numbers we need for each edge value.  */
+
+typedef enum
+  {
+    TOP = 1, LEFT = 2, BOTTOM = 3, RIGHT = 0, NO_EDGE = 4
+  } edge_type;
+
+/* This choice is also not arbitrary: starting at the top edge makes the
+   code find outside outlines before inside ones, which is certainly
+   what we want.  */
+#define START_EDGE  top
+
+typedef enum
+  {
+    NORTH = 0, NORTHWEST = 1, WEST = 2, SOUTHWEST = 3, SOUTH = 4,
+    SOUTHEAST = 5, EAST = 6, NORTHEAST = 7
+  } direction_type;
+
+#define NUM_EDGES NO_EDGE
+
+#define COMPUTE_DELTA(axis, dir)                        \
+  ((dir) % 2 != 0                                       \
+    ? COMPUTE_##axis##_DELTA ((dir) - 1)                \
+      + COMPUTE_##axis##_DELTA (((dir) + 1) % 8)        \
+    : COMPUTE_##axis##_DELTA (dir)                      \
+  )
+
+#define COMPUTE_ROW_DELTA(dir)                          \
+  ((dir) == NORTH ? -1 : (dir) == SOUTH ? +1 : 0)
+
+#define COMPUTE_COL_DELTA(dir)                  \
+  ((dir) == WEST ? -1 : (dir) == EAST ? +1 : 0)
+
+static void append_pixel_outline (pixel_outline_list_type *,
+                                  pixel_outline_type);
+static pixel_outline_type new_pixel_outline (void);
+static void free_pixel_outline (pixel_outline_type *);
+static void concat_pixel_outline (pixel_outline_type *,
+                                  const pixel_outline_type*);
+static bool is_marked_edge (edge_type, unsigned short, unsigned short, bitmap_type);
+
+static void
+mark_edge (edge_type e, unsigned short, unsigned short, bitmap_type *);
+
+static bool is_marked_dir(unsigned short, unsigned short, direction_type, bitmap_type);
+static bool is_other_dir_marked(unsigned short, unsigned short, direction_type, bitmap_type);
+static void mark_dir(unsigned short, unsigned short, direction_type, bitmap_type *);
+
+static unsigned
+num_neighbors(unsigned short, unsigned short, bitmap_type);
+
+#define CHECK_FATAL() if (at_exception_got_fatal(exp)) goto cleanup;
+#define RETURN_IF_FATAL() if (at_exception_got_fatal(exp)) return;
+
+
+
+
+static pixel
+getBitmapColor(bitmap_type  const bitmap,
+               unsigned int const row,
+               unsigned int const col) {
+
+    pixel pix;
+    unsigned char *p = BITMAP_PIXEL (bitmap, row, col);
+  
+    if (bitmap.np >= 3)
+        PPM_ASSIGN(pix, p[0], p[1], p[2]);
+    else
+        PPM_ASSIGN(pix, p[0], p[0], p[0]);
+
+    return pix;
+}
+
+
+
+
+static void
+append_outline_pixel(pixel_outline_type * const pixelOutlineP,
+                     pm_pixelcoord        const coord) {
+/*----------------------------------------------------------------------------
+  Add a point to the pixel list.
+-----------------------------------------------------------------------------*/
+
+    O_LENGTH(*pixelOutlineP)++;
+    REALLOCARRAY_NOFAIL(pixelOutlineP->data, O_LENGTH(*pixelOutlineP));
+
+    O_COORDINATE(*pixelOutlineP, O_LENGTH(*pixelOutlineP) - 1) = coord;
+}
+
+
+
+/* We check to see if the edge of the pixel at position ROW and COL
+   is an outline edge */
+
+static bool
+is_outline_edge (edge_type edge, bitmap_type bitmap,
+                 unsigned short row, unsigned short col, pixel color,
+                 at_exception_type * exp)
+{
+  /* If this pixel isn't of the same color, it's not part of the outline. */
+  if (!PPM_EQUAL (getBitmapColor (bitmap, row, col), color))
+    return false;
+
+  switch (edge)
+    {
+    case LEFT:
+      return (bool)
+          (col == 0 ||
+           !PPM_EQUAL (getBitmapColor (bitmap, row, col - 1), color));
+
+    case TOP:
+      return (bool)
+          (row == 0 ||
+           !PPM_EQUAL (getBitmapColor (bitmap, row - 1, col), color));
+
+    case RIGHT:
+        return (bool)
+            (col == bitmap.width - 1
+             || !PPM_EQUAL(getBitmapColor(bitmap, row, col + 1), color));
+
+    case BOTTOM:
+        return (bool)
+            (row == bitmap.height - 1
+             || !PPM_EQUAL(getBitmapColor (bitmap, row + 1, col), color));
+
+    case NO_EDGE:
+    default:
+      LOG1 ("is_outline_edge: Bad edge value(%d)", edge);
+      at_exception_fatal(exp, "is_outline_edge: Bad edge value");
+    }
+
+  return false; /* NOT REACHED */
+}
+
+
+/* Is this really an edge and is it still unmarked? */
+
+static bool
+is_unmarked_outline_edge(unsigned short row,
+                         unsigned short col,
+                         edge_type edge,
+                         bitmap_type bitmap,
+                         bitmap_type marked,
+                         pixel color,
+                         at_exception_type * exp)
+{
+  return
+    (bool)(!is_marked_edge (edge, row, col, marked)
+              && is_outline_edge (edge, bitmap, row, col, color, exp));
+}
+
+
+static bool
+is_valid_dir(unsigned int   const row,
+             unsigned int   const col,
+             direction_type const dir,
+             bitmap_type    const bitmap,
+             bitmap_type    const marked) {
+  
+    return(!is_marked_dir(row, col, dir, marked)
+           && COMPUTE_DELTA(ROW, dir)+row > 0
+           && COMPUTE_DELTA(COL, dir)+col > 0
+           && BITMAP_VALID_PIXEL(bitmap,
+                                 COMPUTE_DELTA(ROW, dir) + row,
+                                 COMPUTE_DELTA(COL, dir) + col)
+           && PPM_EQUAL(getBitmapColor(bitmap,
+                                       COMPUTE_DELTA(ROW, dir) + row,
+                                       COMPUTE_DELTA(COL, dir) + col),
+                        getBitmapColor(bitmap, row, col)));
+}
+
+
+
+static bool
+next_unmarked_pixel(unsigned int *   const row,
+                    unsigned int *   const col,
+                    direction_type * const dir,
+                    bitmap_type      const bitmap,
+                    bitmap_type *    const marked) {
+
+    unsigned int   const orig_row = *row;
+    unsigned int   const orig_col = *col;
+    direction_type const orig_dir = *dir;
+
+    direction_type test_dir;
+    pixel color;
+
+    test_dir = *dir;  /* initial value */
+    color = getBitmapColor(bitmap, *row, *col);
+
+    do {
+        if (is_valid_dir(orig_row, orig_col, test_dir, bitmap, *marked)) {
+            *row = orig_row + COMPUTE_DELTA(ROW, test_dir);
+            *col = orig_col + COMPUTE_DELTA(COL, test_dir);
+            *dir = test_dir;
+            break;
+        }
+
+        if (orig_dir == test_dir)
+            test_dir = (orig_dir + 2) % 8;
+        else if ((orig_dir + 2) % 8 == test_dir)
+            test_dir = (orig_dir + 6) % 8;
+        else if ((orig_dir + 6) % 8 == test_dir)
+            test_dir = (orig_dir + 1) % 8;
+        else if ((orig_dir + 1) % 8 == test_dir)
+            test_dir = (orig_dir + 7) % 8;
+        else if ((orig_dir + 7) % 8 == test_dir)
+            test_dir = (orig_dir + 3) % 8;
+        else if ((orig_dir + 3) % 8 == test_dir)
+            test_dir = (orig_dir + 5) % 8;
+        else if ((orig_dir + 5) % 8 == test_dir)
+            break;
+    } while (1);
+
+    if ((*row != orig_row || *col != orig_col) && 
+        (!(is_other_dir_marked(orig_row, orig_col, test_dir, *marked) &&
+           is_other_dir_marked(orig_row + COMPUTE_DELTA(ROW, test_dir),
+                               orig_col + COMPUTE_DELTA(COL, test_dir),
+                               test_dir,*marked))))
+        return true;
+    else
+        return false;
+}
+
+
+
+static pixel_outline_type
+find_one_centerline(bitmap_type    const bitmap,
+                    direction_type const original_dir,
+                    unsigned int   const original_row,
+                    unsigned int   const original_col,
+                    bitmap_type *  const marked) {
+
+    direction_type search_dir;
+    unsigned int row, col;
+    pixel_outline_type outline;
+
+    outline = new_pixel_outline();
+    outline.open  = false;
+    outline.color = getBitmapColor(bitmap, row, col);
+
+    /* Add the starting pixel to the output list, changing from bitmap
+       to Cartesian coordinates and specifying the left edge so that
+       the coordinates won't be adjusted.
+    */
+    {
+        pm_pixelcoord pos;
+        pos.col = col; pos.row = bitmap.height - row - 1;
+        LOG2(" (%d,%d)", pos.col, pos.row);
+        append_outline_pixel(&outline, pos);
+    }
+    search_dir = original_dir;  /* initial value */
+    row = original_row;         /* initial value */
+    col = original_col;         /* initial values */
+
+    for ( ; ; ) {
+        unsigned int const prev_row = row;
+        unsigned int const prev_col = col;
+
+        /* If there is no adjacent, unmarked pixel, we can't proceed
+           any further, so return an open outline.
+        */
+        if (!next_unmarked_pixel(&row, &col, &search_dir, bitmap, marked)) {
+            outline.open = true;
+            break;
+        }
+
+        /* If we've moved to a new pixel, mark all edges of the previous
+           pixel so that it won't be revisited.
+        */
+        if (!(prev_row == original_row && prev_col == original_col))
+            mark_dir(prev_row, prev_col, search_dir, marked);
+        mark_dir(row, col, (search_dir + 4) % 8, marked);
+
+        /* If we've returned to the starting pixel, we're done. */
+        if (row == original_row && col == original_col)
+            break;
+
+        
+        {
+            /* Add the new pixel to the output list. */
+            pm_pixelcoord pos;
+            pos.col = col; pos.row = bitmap.height - row - 1;
+            LOG2(" (%d,%d)", pos.col, pos.row);
+            append_outline_pixel(&outline, pos);
+        }
+    }
+    mark_dir(original_row, original_col, original_dir, marked);
+
+    return outline;
+}
+
+
+
+static bool
+wrongDirection(unsigned int   const row,
+               unsigned int   const col,
+               direction_type const dir,
+               bitmap_type    const bitmap,
+               bitmap_type    const marked) {
+
+    return (!is_valid_dir(row, col, dir, bitmap, marked)
+            || (!is_valid_dir(COMPUTE_DELTA(ROW, dir) + row,
+                              COMPUTE_DELTA(COL, dir) + col,
+                              dir, bitmap, marked)
+                && num_neighbors(row, col, bitmap) > 2)
+            || num_neighbors(row, col, bitmap) > 4
+            || num_neighbors(COMPUTE_DELTA(ROW, dir) + row,
+                             COMPUTE_DELTA(COL, dir) + col, bitmap) > 4
+            || (is_other_dir_marked(row, col, dir, marked)
+                && is_other_dir_marked(row + COMPUTE_DELTA(ROW, dir),
+                                       col + COMPUTE_DELTA(COL, dir),
+                                       dir, marked)));
+}
+
+
+
+pixel_outline_list_type
+find_centerline_pixels(bitmap_type         const bitmap,
+                       pixel               const bg_color, 
+                       at_progress_func          notify_progress,
+                       void *              const progress_data,
+                       at_testcancel_func        test_cancel,
+                       void *              const testcancel_data,
+                       at_exception_type * const exp) {
+
+  pixel_outline_list_type outline_list;
+  signed short row;
+  bitmap_type marked = new_bitmap(bitmap.width, bitmap.height);
+  unsigned int const max_progress = bitmap.height * bitmap.width;
+    
+  O_LIST_LENGTH(outline_list) = 0;
+  outline_list.data = NULL;
+
+  for (row = 0; row < bitmap.height; ++row) {
+      signed short col;
+      for (col = 0; col < bitmap.width; ) {
+          bool           const clockwise = false;
+
+          direction_type dir;
+          pixel_outline_type outline;
+
+          if (notify_progress)
+              notify_progress((float)(row * bitmap.width + col) /
+                              ((float) max_progress * (float)3.0),
+                              progress_data);
+
+		  if (PPM_EQUAL(getBitmapColor(bitmap, row, col), bg_color)) {
+	          ++col;
+			  continue;
+          }
+
+          dir = EAST;
+
+          if (wrongDirection(row, col, dir, bitmap, marked)) {
+              dir = SOUTHEAST;
+              if (wrongDirection(row, col, dir, bitmap, marked)) {
+                  dir = SOUTH;
+                  if (wrongDirection(row, col, dir, bitmap, marked)) {
+                      dir = SOUTHWEST;
+                      if (wrongDirection(row, col, dir, bitmap, marked)) {
+						  ++col;
+						  continue;
+                      }
+                  }
+              }
+          }
+
+          LOG2("#%u: (%sclockwise) ", O_LIST_LENGTH(outline_list),
+               clockwise ? "" : "counter");
+
+          outline = find_one_centerline(bitmap, dir, row, col, &marked);
+
+          /* If the outline is open (i.e., we didn't return to the
+             starting pixel), search from the starting pixel in the
+             opposite direction and concatenate the two outlines.
+          */
+
+          if (outline.open) {
+              pixel_outline_type partial_outline;
+              bool okay = false;
+
+              if (dir == EAST) {
+                  dir = SOUTH;
+                  okay = is_valid_dir(row, col, dir, bitmap, marked);
+                  if (!okay) {
+                      dir = SOUTHWEST;
+                      okay = is_valid_dir(row, col, dir, bitmap, marked);
+                      if (!okay) {
+                          dir = SOUTHEAST;
+                          okay = is_valid_dir(row, col, dir, bitmap, marked);
+                      }
+                  }
+              } else if (dir == SOUTHEAST) {
+                  dir = SOUTHWEST;
+                  okay = is_valid_dir(row, col, dir, bitmap, marked);
+                  if (!okay) {
+                      dir = EAST;
+                      okay=is_valid_dir(row, col, dir, bitmap, marked);
+                      if (!okay) {
+                          dir = SOUTH;
+                          okay = is_valid_dir(row, col, dir, bitmap, marked);
+                      }
+                  }
+              } else if (dir == SOUTH) {
+                  dir = EAST;
+                  okay = is_valid_dir(row, col, dir, bitmap, marked);
+                  if (!okay) {
+                      dir = SOUTHEAST;
+                      okay = is_valid_dir(row, col, dir, bitmap, marked);
+                      if (!okay) {
+                          dir = SOUTHWEST;
+                          okay = is_valid_dir(row, col, dir, bitmap, marked);
+                      }
+                  }
+              } else if (dir == SOUTHWEST) {
+                  dir = SOUTHEAST;
+                  okay = is_valid_dir(row, col, dir, bitmap, marked);
+                  if (!okay) {
+                      dir = EAST;
+                      okay = is_valid_dir(row, col, dir, bitmap, marked);
+                      if (!okay) {
+                          dir = SOUTH;
+                          okay = is_valid_dir(row, col, dir, bitmap, marked);
+                      }
+                  }
+              }
+              if (okay) {
+                  partial_outline =
+                      find_one_centerline(bitmap, dir, row, col, &marked);
+                  concat_pixel_outline(&outline, &partial_outline);
+                  if (partial_outline.data)
+                      free(partial_outline.data);
+              } else
+                  ++col;
+          }        
+            
+          /* Outside outlines will start at a top edge, and move
+             counterclockwise, and inside outlines will start at a
+             bottom edge, and move clockwise.  This happens because of
+             the order in which we look at the edges.
+          */
+          O_CLOCKWISE(outline) = clockwise;
+          if (O_LENGTH(outline) > 1)
+              append_pixel_outline(&outline_list, outline);
+          LOG1("(%s)", (outline.open ? " open" : " closed"));
+          LOG1(" [%u].\n", O_LENGTH(outline));
+          if (O_LENGTH(outline) == 1)
+              free_pixel_outline(&outline);
+        }
+  }
+  if (test_cancel && test_cancel(testcancel_data)) {
+      if (O_LIST_LENGTH (outline_list) != 0)
+          free_pixel_outline_list (&outline_list);
+  }
+  free_bitmap(&marked);
+  flush_log_output();
+  return outline_list;
+}
+
+
+
+/* Add an outline to an outline list. */
+
+static void
+append_pixel_outline (pixel_outline_list_type *outline_list,
+                      pixel_outline_type outline)
+{
+  O_LIST_LENGTH (*outline_list)++;
+  REALLOCARRAY_NOFAIL(outline_list->data, outline_list->length);
+  O_LIST_OUTLINE (*outline_list, O_LIST_LENGTH (*outline_list) - 1) = outline;
+}
+
+
+/* Free the list of outline lists. */
+
+void
+free_pixel_outline_list (pixel_outline_list_type *outline_list)
+{
+  unsigned this_outline;
+
+  for (this_outline = 0; this_outline < outline_list->length; this_outline++)
+    {
+      pixel_outline_type o = outline_list->data[this_outline];
+      free_pixel_outline (&o);
+    }
+  outline_list->length = 0;
+
+  if (outline_list->data != NULL)
+    {
+      free (outline_list->data);
+      outline_list->data = NULL;
+    }
+
+  flush_log_output ();
+}
+
+
+/* Return an empty list of pixels.  */
+
+
+static pixel_outline_type
+new_pixel_outline (void)
+{
+  pixel_outline_type pixel_outline;
+
+  O_LENGTH (pixel_outline) = 0;
+  pixel_outline.data = NULL;
+  pixel_outline.open = false;
+
+  return pixel_outline;
+}
+
+static void
+free_pixel_outline (pixel_outline_type * outline)
+{
+  if (outline->data)
+    {
+      free (outline->data) ;
+      outline->data   = NULL;
+      outline->length = 0;
+    }
+}
+
+/* Concatenate two pixel lists. The two lists are assumed to have the
+   same starting pixel and to proceed in opposite directions therefrom. */
+
+static void
+concat_pixel_outline(pixel_outline_type *o1, const pixel_outline_type *o2)
+{
+  int src, dst;
+  unsigned o1_length, o2_length;
+  if (!o1 || !o2 || O_LENGTH(*o2) <= 1) return;
+
+  o1_length = O_LENGTH(*o1);
+  o2_length = O_LENGTH(*o2);
+  O_LENGTH(*o1) += o2_length - 1;
+  /* Resize o1 to the sum of the lengths of o1 and o2 minus one (because
+     the two lists are assumed to share the same starting pixel). */
+  REALLOCARRAY_NOFAIL(o1->data, O_LENGTH(*o1));
+  /* Shift the contents of o1 to the end of the new array to make room
+     to prepend o2. */
+  for (src = o1_length - 1, dst = O_LENGTH(*o1) - 1; src >= 0; src--, dst--)
+    O_COORDINATE(*o1, dst) = O_COORDINATE(*o1, src);
+  /* Prepend the contents of o2 (in reverse order) to o1. */
+  for (src = o2_length - 1, dst = 0; src > 0; src--, dst++)
+    O_COORDINATE(*o1, dst) = O_COORDINATE(*o2, src);
+}
+
+
+/* If EDGE is not already marked, we mark it; otherwise, it's a fatal error.
+   The position ROW and COL should be inside the bitmap MARKED. EDGE can be
+   NO_EDGE. */
+
+static void
+mark_edge (edge_type edge, unsigned short row,
+           unsigned short col, bitmap_type *marked)
+{
+  *BITMAP_PIXEL (*marked, row, col) |= 1 << edge;
+}
+
+
+/* Mark the direction of the pixel ROW/COL in MARKED. */
+
+static void
+mark_dir(unsigned short row, unsigned short col, direction_type dir, bitmap_type *marked)
+{
+  *BITMAP_PIXEL(*marked, row, col) |= 1 << dir;
+}
+
+
+/* Test if the direction of pixel at ROW/COL in MARKED is marked. */
+
+static bool
+is_marked_dir(unsigned short row, unsigned short col, direction_type dir, bitmap_type marked)
+{
+  return (bool)((*BITMAP_PIXEL(marked, row, col) & 1 << dir) != 0);
+}
+
+
+static bool
+is_other_dir_marked(unsigned short row, unsigned short col, direction_type dir, bitmap_type marked)
+{
+  return (bool)((*BITMAP_PIXEL(marked, row, col) & (255 - (1 << dir) - (1 << ((dir + 4) % 8))) ) != 0);
+}
+
+
+/* Return the number of pixels adjacent to pixel ROW/COL that are black. */
+
+static unsigned
+num_neighbors(unsigned short row, unsigned short col, bitmap_type bitmap)
+{
+    unsigned dir, count = 0;
+    pixel color = getBitmapColor(bitmap, row, col);
+    for (dir = NORTH; dir <= NORTHEAST; dir++)
+    {
+	int delta_r = COMPUTE_DELTA(ROW, dir);
+	int delta_c = COMPUTE_DELTA(COL, dir);
+	unsigned int test_row = row + delta_r;
+	unsigned int test_col = col + delta_c;
+	if (BITMAP_VALID_PIXEL(bitmap, test_row, test_col)
+	    && PPM_EQUAL(getBitmapColor(bitmap, test_row, test_col), color))
+	    ++count;
+    }
+    return count;
+}
+
+
+/* Test if the edge EDGE at ROW/COL in MARKED is marked.  */
+
+static bool
+is_marked_edge (edge_type edge, unsigned short row, unsigned short col, bitmap_type marked)
+{
+  return
+    (bool)(edge == NO_EDGE ? false : (*BITMAP_PIXEL (marked, row, col) & (1 << edge)) != 0);
+}
+
+
+
+static void
+nextClockwisePointTop(bitmap_type         const bitmap,
+                      edge_type *         const edge,
+                      unsigned int *      const row,
+                      unsigned int *      const col,
+                      pixel               const color,
+                      bitmap_type         const marked,
+                      at_exception_type * const exp,
+                      pm_pixelcoord *     const posP) {
+
+    if ((*col >= 1 && !is_marked_edge(TOP, *row, *col-1, marked) &&
+             is_outline_edge(TOP, bitmap, *row, *col-1, color, exp))) {
+
+        /* WEST */
+
+        *edge = TOP;
+        --*col;
+        posP->col = *col;
+        posP->row = bitmap.height - *row;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    if ((*col >= 1 && *row >= 1 &&
+         !is_marked_edge(RIGHT, *row-1, *col-1, marked) &&
+         is_outline_edge(RIGHT, bitmap, *row-1, *col-1,
+                         color, exp)) &&
+        !(is_marked_edge(LEFT, *row-1, *col, marked) &&
+          is_marked_edge(TOP, *row,*col-1, marked)) &&
+        !(is_marked_edge(BOTTOM, *row-1, *col, marked) &&
+          is_marked_edge(RIGHT, *row, *col-1, marked))) {
+
+        /* NORTHWEST */
+
+        *edge = RIGHT;
+        --*col;
+        --*row;
+        posP->col = *col + 1;
+        posP->row = bitmap.height - *row;
+        return;
+    } 
+
+    RETURN_IF_FATAL();
+
+    if ((!is_marked_edge(LEFT, *row, *col, marked)
+         && is_outline_edge(LEFT, bitmap, *row, *col, color, exp))) {
+
+        *edge = LEFT;
+        posP->col = *col;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    *edge = NO_EDGE;
+}
+
+
+
+static void
+nextClockwisePointRight(bitmap_type         const bitmap,
+                        edge_type *         const edge,
+                        unsigned int *      const row,
+                        unsigned int *      const col,
+                        pixel               const color,
+                        bitmap_type         const marked,
+                        at_exception_type * const exp,
+                        pm_pixelcoord *     const posP) {
+
+    if ((*row >= 1 &&
+         !is_marked_edge(RIGHT, *row-1, *col, marked) &&
+         is_outline_edge(RIGHT, bitmap, *row-1, *col, color, exp))) {
+
+         /* NORTH */
+        
+        *edge = RIGHT;
+        --*row;
+        posP->col = *col+1;
+        posP->row = bitmap.height - *row;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+    
+    if ((*col+1 < marked.width && *row >= 1 &&
+         !is_marked_edge(BOTTOM, *row-1, *col+1, marked) &&
+         is_outline_edge(BOTTOM, bitmap, *row-1, *col+1,
+                         color, exp)) &&
+        !(is_marked_edge(LEFT, *row, *col+1, marked) &&
+          is_marked_edge(BOTTOM, *row-1, *col, marked)) &&
+        !(is_marked_edge(TOP, *row, *col+1, marked) &&
+          is_marked_edge(RIGHT, *row-1, *col, marked))) {
+
+        /* NORTHEAST */
+        *edge = BOTTOM;
+        ++*col;
+        --*row;
+        posP->col = *col + 1;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    } 
+
+    RETURN_IF_FATAL();
+
+    if ((!is_marked_edge(TOP, *row, *col, marked) &&
+         is_outline_edge(TOP, bitmap, *row, *col, color, exp))) {
+
+        *edge = TOP;
+        posP->col = *col;
+        posP->row = bitmap.height - *row;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    *edge = NO_EDGE;
+}
+
+
+
+static void
+nextClockwisePointBottom(bitmap_type         const bitmap,
+                         edge_type *         const edge,
+                         unsigned int *      const row,
+                         unsigned int *      const col,
+                         pixel               const color,
+                         bitmap_type         const marked,
+                         at_exception_type * const exp,
+                         pm_pixelcoord *     const posP) {
+    
+    if ((*col+1 < marked.width &&
+         !is_marked_edge(BOTTOM, *row, *col+1, marked) &&
+         is_outline_edge(BOTTOM, bitmap, *row, *col+1, color, exp))) {
+
+        /* EAST */
+
+        *edge = BOTTOM;
+        ++*col;
+        posP->col = *col+1;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    if ((*col + 1 < marked.width && *row+1 < marked.height &&
+         !is_marked_edge(LEFT, *row+1,*col+1, marked) &&
+         is_outline_edge(LEFT, bitmap, *row+1, *col+1, color, exp)) &&
+        !(is_marked_edge(TOP, *row+1, *col, marked) &&
+          is_marked_edge(LEFT, *row, *col+1, marked)) &&
+        !(is_marked_edge(RIGHT, *row+1, *col, marked) &&
+          is_marked_edge(BOTTOM, *row, *col+1, marked))) {
+
+        /* SOUTHEAST */
+
+        *edge = LEFT;
+        ++*col;
+        ++*row;
+        posP->col = *col;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    if ((!is_marked_edge(RIGHT, *row, *col, marked) &&
+         is_outline_edge(RIGHT, bitmap, *row, *col, color, exp))) {
+
+        *edge = RIGHT;
+        posP->col = *col+1;
+        posP->row = bitmap.height - *row;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    *edge = NO_EDGE;
+}
+
+
+
+static void
+nextClockwisePointLeft(bitmap_type         const bitmap,
+                       edge_type *         const edge,
+                       unsigned int *      const row,
+                       unsigned int *      const col,
+                       pixel               const color,
+                       bitmap_type         const marked,
+                       at_exception_type * const exp,
+                       pm_pixelcoord *     const posP) {
+
+    if ((*row+1 < marked.height &&
+         !is_marked_edge(LEFT, *row+1, *col, marked) &&
+         is_outline_edge(LEFT, bitmap, *row+1, *col, color, exp))) {
+
+        /* SOUTH */
+
+        *edge = LEFT;
+        ++*row;
+        posP->col = *col;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    if ((*col >= 1 && *row+1 < marked.height &&
+         !is_marked_edge(TOP, *row+1, *col-1, marked) &&
+         is_outline_edge(TOP, bitmap, *row+1, *col-1, color, exp)) &&
+        !(is_marked_edge(RIGHT, *row, *col-1, marked) &&
+          is_marked_edge(TOP, *row+1, *col, marked)) &&
+        !(is_marked_edge(BOTTOM, *row, *col-1, marked) &&
+          is_marked_edge(LEFT, *row+1, *col, marked))) {
+        
+        /* SOUTHWEST */
+        
+        *edge = TOP;
+        --*col;
+        ++*row;
+        posP->col = *col;
+        posP->row = bitmap.height - *row;
+        return;
+    } 
+
+    RETURN_IF_FATAL();
+
+    if ((!is_marked_edge(BOTTOM, *row, *col, marked) &&
+         is_outline_edge(BOTTOM, bitmap, *row, *col, color, exp))) {
+        *edge = BOTTOM;
+        posP->col = *col+1;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+    RETURN_IF_FATAL();
+
+    *edge = NO_EDGE;
+}
+
+
+
+static void
+nextClockwisePoint(bitmap_type         const bitmap,
+                   edge_type *         const edge,
+                   unsigned int *      const row,
+                   unsigned int *      const col,
+                   pixel               const color,
+                   bitmap_type         const marked,
+                   at_exception_type * const exp,
+                   pm_pixelcoord *     const posP) {
+    
+    switch (*edge) {
+    case TOP:
+        nextClockwisePointTop(  bitmap, edge, row, col, color,
+                                marked, exp, posP);
+        break;
+    case RIGHT: 
+        nextClockwisePointRight(bitmap, edge, row, col, color,
+                                marked, exp, posP);
+        break;
+    case BOTTOM: 
+        nextClockwisePointBottom(bitmap, edge, row, col, color,
+                                 marked, exp, posP);
+        break;
+    case LEFT: 
+        nextClockwisePointLeft(  bitmap, edge, row, col, color,
+                                 marked, exp, posP);
+        break;
+    case NO_EDGE:
+        break;
+    default:
+        *edge = NO_EDGE;
+        break;
+    }
+}
+
+
+
+static void
+nextCcwPointTop(bitmap_type         const bitmap,
+                edge_type *         const edge,
+                unsigned int *      const row,
+                unsigned int *      const col,
+                pixel               const color,
+                bitmap_type         const marked,
+                at_exception_type * const exp,
+                pm_pixelcoord *     const posP) {
+
+    if ((!is_marked_edge(LEFT, *row, *col, marked) &&
+         is_outline_edge(LEFT,bitmap,*row,*col, color, exp))) {
+
+        *edge = LEFT;
+        posP->col = *col;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    if ((*col >= 1 &&
+         !is_marked_edge(TOP, *row, *col-1, marked) &&
+         is_outline_edge(TOP, bitmap, *row, *col-1, color, exp))) {
+
+        /* WEST */
+
+        *edge = TOP;
+        --*col;
+        posP->col = *col;
+        posP->row = bitmap.height - *row;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+    
+    if ((*col >= 1 && *row >= 1 &&
+         !is_marked_edge(RIGHT, *row-1, *col-1, marked) &&
+         is_outline_edge(RIGHT, bitmap, *row-1, *col-1, color, exp))) {
+
+        /* NORTHWEST */
+
+        *edge = RIGHT;
+        --*col;
+        --*row;
+        posP->col = *col + 1;
+        posP->row = bitmap.height - *row;
+        return;
+    } 
+
+    RETURN_IF_FATAL();
+
+    *edge = NO_EDGE;
+}
+
+
+
+static void
+nextCcwPointRight(bitmap_type         const bitmap,
+                  edge_type *         const edge,
+                  unsigned int *      const row,
+                  unsigned int *      const col,
+                  pixel               const color,
+                  bitmap_type         const marked,
+                  at_exception_type * const exp,
+                  pm_pixelcoord *     const posP) {
+
+    if ((!is_marked_edge(TOP, *row, *col, marked) &&
+         is_outline_edge(TOP, bitmap, *row, *col, color, exp))) {
+
+        *edge = TOP;
+        posP->col = *col;
+        posP->row = bitmap.height - *row;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    if ((*row >= 1 &&
+         !is_marked_edge(RIGHT, *row-1, *col, marked) &&
+         is_outline_edge(RIGHT, bitmap, *row-1, *col, color, exp))) {
+
+        /* NORTH */
+        
+        *edge = RIGHT;
+        --*row;
+        posP->col = *col + 1;
+        posP->row = bitmap.height - *row;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    if ((*col + 1 < marked.width && *row >= 1 &&
+         !is_marked_edge(BOTTOM, *row-1, *col+1, marked) &&
+         is_outline_edge(BOTTOM, bitmap, *row-1, *col+1, color, exp))) {
+
+        /* NORTHEAST */
+
+        *edge = BOTTOM;
+        ++*col;
+        ++*row;
+        posP->col = *col + 1;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    *edge = NO_EDGE;
+}
+
+
+
+static void
+nextCcwPointBottom(bitmap_type         const bitmap,
+                   edge_type *         const edge,
+                   unsigned int *      const row,
+                   unsigned int *      const col,
+                   pixel               const color,
+                   bitmap_type         const marked,
+                   at_exception_type * const exp,
+                   pm_pixelcoord *     const posP) {
+
+    if ((!is_marked_edge(RIGHT, *row, *col, marked) &&
+         is_outline_edge(RIGHT, bitmap, *row, *col, color, exp))) {
+
+        *edge = RIGHT;
+        posP->col = *col + 1;
+        posP->row = bitmap.height - *row;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    if ((*col + 1 < marked.width &&
+         !is_marked_edge(BOTTOM, *row, *col+1, marked) &&
+         is_outline_edge(BOTTOM, bitmap, *row, *col+1, color, exp))) {
+
+        /* EAST */
+
+        *edge = BOTTOM;
+        ++*col;
+        posP->col = *col + 1;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    if ((*col + 1 < marked.width && *row + 1 < marked.height &&
+         !is_marked_edge(LEFT, *row+1, *col+1, marked) &&
+         is_outline_edge(LEFT, bitmap, *row+1, *col+1, color, exp))) {
+
+        /* SOUTHEAST */
+
+        *edge = LEFT;
+        ++*col;
+        ++*row;
+        posP->col = *col;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+    
+    *edge = NO_EDGE;
+}
+
+
+
+static void
+nextCcwPointLeft(bitmap_type         const bitmap,
+                 edge_type *         const edge,
+                 unsigned int *      const row,
+                 unsigned int *      const col,
+                 pixel               const color,
+                 bitmap_type         const marked,
+                 at_exception_type * const exp,
+                 pm_pixelcoord *     const posP) {
+
+
+    if ((!is_marked_edge(BOTTOM, *row, *col, marked) &&
+         is_outline_edge(BOTTOM, bitmap, *row, *col, color, exp))) {
+
+        *edge = BOTTOM;
+        posP->col = *col + 1;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    if ((*row + 1 < marked.height &&
+         !is_marked_edge(LEFT, *row+1, *col, marked) &&
+         is_outline_edge(LEFT, bitmap, *row+1, *col, color, exp))) {
+
+        /* SOUTH */
+
+        *edge = LEFT;
+        ++*row;
+        posP->col = *col;
+        posP->row = bitmap.height - *row - 1;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+    
+    if ((*col >= 1 && *row + 1 < marked.height &&
+         !is_marked_edge(TOP, *row+1, *col-1, marked) &&
+         is_outline_edge(TOP, bitmap, *row+1, *col-1, color, exp))) {
+
+        /* SOUTHWEST */
+
+        *edge = TOP;
+        --*col;
+        ++*row;
+        posP->col = *col;
+        posP->row = bitmap.height - *row;
+        return;
+    }
+
+    RETURN_IF_FATAL();
+
+    *edge = NO_EDGE;
+}
+
+static void
+nextCounterClockwisePoint(bitmap_type         const bitmap,
+                          edge_type *         const edge,
+                          unsigned int *      const row,
+                          unsigned int *      const col,
+                          pixel               const color,
+                          bitmap_type         const marked,
+                          at_exception_type * const exp,
+                          pm_pixelcoord *     const posP) {
+
+    switch (*edge) {
+    case TOP:
+        nextCcwPointTop(   bitmap, edge, row, col, color, marked, exp, posP);
+        break;
+    case RIGHT: 
+        nextCcwPointRight( bitmap, edge, row, col, color, marked, exp, posP);
+        break;
+    case BOTTOM: 
+        nextCcwPointBottom(bitmap, edge, row, col, color, marked, exp, posP);
+        break;
+    case LEFT: 
+        nextCcwPointLeft(  bitmap, edge, row, col, color, marked, exp, posP);
+        break;
+    case NO_EDGE:
+        break;
+    default: 
+        *edge = NO_EDGE;
+        break;
+    }
+}
+
+
+
+static void
+nextPoint(bitmap_type         const bitmap,
+          edge_type *         const edge,
+          unsigned int *      const row,
+          unsigned int *      const col,
+          pm_pixelcoord *     const nextPointP,
+          pixel               const color,
+          bool                const clockwise,
+          bitmap_type         const marked,
+          at_exception_type * const exp) {
+
+    if (!clockwise)
+        nextClockwisePoint(       bitmap, edge, row, col, color,
+                                  marked, exp, nextPointP);
+    else
+        nextCounterClockwisePoint(bitmap, edge, row, col, color,
+                                  marked, exp, nextPointP);
+}
+
+
+
+static pixel_outline_type
+find_one_outline(bitmap_type         const bitmap,
+                 edge_type           const originalEdge,
+                 unsigned int        const originalRow,
+                 unsigned int        const originalCol,
+                 bitmap_type *       const marked,
+                 bool                const clockwise,
+                 bool                const ignore,
+                 at_exception_type * const exp) {
+/*----------------------------------------------------------------------------
+  Calculate one single outline.  We pass the position of the
+  starting pixel and the starting edge.  We mark all edges we track along
+  and append the outline pixels to the coordinate list.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+    unsigned int col;
+    edge_type    edge;
+
+    pixel_outline_type outline;
+    pm_pixelcoord pos;
+    
+    outline = new_pixel_outline();
+    outline.color = getBitmapColor(bitmap, originalRow, originalCol);
+
+    row  = originalRow;   /* initial value */
+    col  = originalCol;   /* initial value */
+    edge = originalEdge;  /* initial value */
+
+    /* Set initial position */
+    pos.col = col + ((edge == RIGHT) || (edge == BOTTOM) ? 1 : 0);
+    pos.row = bitmap.height - row - 1 + 
+        (edge == TOP || edge == RIGHT ? 1 : 0);
+
+    do {
+        /* Put this edge into the output list */
+        if (!ignore) {
+            LOG2(" (%d,%d)", pos.col, pos.row);
+            append_outline_pixel(&outline, pos);
+        }
+        
+        mark_edge(edge, row, col, marked);
+        nextPoint(bitmap, &edge, &row, &col, &pos, outline.color, clockwise,
+                  *marked, exp);
+            /* edge, row, and col are both input and output in the above */
+    } while (edge != NO_EDGE && !at_exception_got_fatal(exp));
+
+    if (ignore || at_exception_got_fatal(exp))
+        free_pixel_outline(&outline);
+
+    return outline;
+}
+
+
+
+pixel_outline_list_type
+find_outline_pixels(bitmap_type         const bitmap,
+                    bool                const bg_spec,
+                    pixel               const bg_color, 
+                    at_progress_func          notify_progress,
+                    void *              const progress_data,
+                    at_testcancel_func        test_cancel,
+                    void *              const testcancel_data,
+                    at_exception_type * const exp) {
+/*----------------------------------------------------------------------------
+   Return a list of outlines in the image whose raster is 'bitmap'.
+
+   The background color of the image is 'bg_color' if 'bg_spec' is true;
+   otherwise, there is no background color.
+-----------------------------------------------------------------------------*/
+    /* We go through a bitmap TOP to BOTTOM, LEFT to RIGHT, looking for
+       each pixel with an unmarked edge that we consider a starting point
+       of an outline.  When we find one, we trace the outline and add it
+       to the list, marking the edges in it as we go.
+    */
+    unsigned int const max_progress = bitmap.height * bitmap.width;
+    
+    pixel_outline_list_type outline_list;
+    unsigned int row;
+    bitmap_type marked;
+    
+    marked = new_bitmap (bitmap.width, bitmap.height);
+    
+    O_LIST_LENGTH(outline_list) = 0;
+    outline_list.data = NULL;
+    
+    for (row = 0; row < bitmap.height; ++row) {
+        unsigned int col;
+        for (col = 0; col < bitmap.width; ++col) {
+            pixel const color = getBitmapColor(bitmap, row, col);
+            bool const is_background =
+                bg_spec && PPM_EQUAL(color, bg_color);
+
+            if (notify_progress)
+                notify_progress((float)(row * bitmap.width + col) /
+                                ((float) max_progress * (float)3.0),
+                                progress_data);
+
+            /* A valid edge can be TOP for an outside outline.
+               Outside outlines are traced counterclockwise.
+            */
+
+            if (!is_background &&
+                is_unmarked_outline_edge(row, col, TOP,
+                                         bitmap, marked, color, exp)) {
+                pixel_outline_type outline;
+                
+                CHECK_FATAL();   /* FREE(DONE) outline_list */
+                
+                LOG1("#%u: (counterclockwise)", O_LIST_LENGTH(outline_list));
+                
+                outline = find_one_outline(bitmap, TOP, row, col, &marked,
+                                           false, false, exp);
+                CHECK_FATAL();    /* FREE(DONE) outline_list */
+                
+                O_CLOCKWISE(outline) = false;
+                append_pixel_outline(&outline_list, outline);
+                
+                LOG1(" [%u].\n", O_LENGTH (outline));
+            } else
+                CHECK_FATAL ();	/* FREE(DONE) outline_list */
+
+            /* A valid edge can be BOTTOM for an inside outline.
+               Inside outlines are traced clockwise.
+            */
+            if (row > 0) {
+                pixel const colorAbove = getBitmapColor(bitmap, row-1, col);
+                if (!(bg_spec && PPM_EQUAL(colorAbove, bg_color)) &&
+                    is_unmarked_outline_edge(row-1, col, BOTTOM,
+                                             bitmap, marked, colorAbove,exp)) {
+                    CHECK_FATAL(); /* FREE(DONE) outline_list */
+                    
+                    /* This lines are for debugging only:*/
+                    if (is_background) {
+                        pixel_outline_type outline;
+                    
+                        LOG1("#%u: (clockwise)", O_LIST_LENGTH(outline_list));
+                        
+                        outline = find_one_outline(bitmap, BOTTOM, row-1, col,
+                                                   &marked, true, false, exp);
+                        CHECK_FATAL(); /* FREE(DONE) outline_list */
+                        
+                        O_CLOCKWISE(outline) = true;
+                        append_pixel_outline(&outline_list, outline);
+                        
+                        LOG1(" [%u].\n", O_LENGTH(outline));
+                    } else {
+                        find_one_outline(bitmap, BOTTOM, row-1, col,
+                                         &marked, true, true, exp);
+                        CHECK_FATAL(); /* FREE(DONE) outline_list */
+                    }
+                } else
+                    CHECK_FATAL();	/* FREE(DONE) outline_list */
+            }
+            if (test_cancel && test_cancel(testcancel_data)) {
+                free_pixel_outline_list(&outline_list);
+                goto cleanup;
+            }
+        }
+    }
+ cleanup:
+    free_bitmap(&marked);
+    flush_log_output();
+    if (at_exception_got_fatal(exp))
+        free_pixel_outline_list(&outline_list);
+
+    return outline_list;
+}
+
diff --git a/converter/other/pamtosvg/pxl-outline.h b/converter/other/pamtosvg/pxl-outline.h
new file mode 100644
index 00000000..e37ccaf6
--- /dev/null
+++ b/converter/other/pamtosvg/pxl-outline.h
@@ -0,0 +1,79 @@
+/* pxl-outline.h: find a list of outlines which make up one character. */
+
+#ifndef PXL_OUTLINE_H
+#define PXL_OUTLINE_H
+
+#include "ppm.h"
+
+#include "autotrace.h"
+#include "exception.h"
+#include "bitmap.h"
+
+/* This is a list of contiguous points on the bitmap.  */
+typedef struct
+{
+  pm_pixelcoord * data;
+  unsigned length;
+  bool clockwise;
+  pixel color;
+  bool open;
+} pixel_outline_type;
+
+
+/* The Nth coordinate in the list.  */
+#define O_COORDINATE(p_o, n) ((p_o).data[n])
+
+
+/* The length of the list.  */
+#define O_LENGTH(p_o) ((p_o).length)
+
+/* Whether the outline moves clockwise or counterclockwise.  */
+#define O_CLOCKWISE(p_o) ((p_o).clockwise)
+
+/* Since a pixel outline is cyclic, the index of the next coordinate
+   after the last is the first, and the previous coordinate before the
+   first is the last.  */
+#define O_NEXT(p_o, n) (((n) + 1) % O_LENGTH (p_o))
+#define O_PREV(p_o, n) ((n) == 0				\
+                         ? O_LENGTH (p_o) - 1			\
+                         : (n) - 1)
+
+/* And the character turns into a list of such lists.  */
+typedef struct
+{
+  pixel_outline_type *data;
+  unsigned length;
+} pixel_outline_list_type;
+
+/* The Nth list in the list of lists.  */
+#define O_LIST_OUTLINE(p_o_l, n) ((p_o_l).data[n])
+
+/* The length of the list of lists.  */
+#define O_LIST_LENGTH(p_o_l) ((p_o_l).length)
+
+/* Find all pixels on the outline in the character C.  */
+pixel_outline_list_type
+find_outline_pixels (bitmap_type         const type,
+                     bool                const bg_spec,
+                     pixel               const bg_color, 
+                     at_progress_func          notify_progress,
+                     void *              const progress_data,
+                     at_testcancel_func        test_cancel,
+                     void *              const testcancel_data,
+                     at_exception_type * const exp);
+
+/* Find all pixels on the center line of the character C.  */
+pixel_outline_list_type
+find_centerline_pixels (bitmap_type         const type,
+                        pixel               const bg_color, 
+                        at_progress_func          notify_progress,
+                        void *              const progress_data,
+                        at_testcancel_func        test_cancel,
+                        void *              const testcancel_data,
+                        at_exception_type * const exp);
+
+/* Free the memory in the list.  */
+extern void
+free_pixel_outline_list (pixel_outline_list_type *);
+
+#endif /* not PXL_OUTLINE_H */
diff --git a/converter/other/pamtosvg/spline.c b/converter/other/pamtosvg/spline.c
new file mode 100644
index 00000000..5bdf0c0e
--- /dev/null
+++ b/converter/other/pamtosvg/spline.c
@@ -0,0 +1,193 @@
+/* spline.c: spline and spline list (represented as arrays) manipulation. */
+
+#include <assert.h>
+
+#include "mallocvar.h"
+
+#include "message.h"
+#include "point.h"
+#include "spline.h"
+#include "vector.h"
+
+/* Print a spline in human-readable form.  */
+
+void
+print_spline (FILE *f, spline_type s)
+{
+  assert(SPLINE_DEGREE (s) == LINEARTYPE || SPLINE_DEGREE (s) == CUBICTYPE);
+
+  if (SPLINE_DEGREE (s) == LINEARTYPE)
+    fprintf (f, "(%.3f,%.3f)--(%.3f,%.3f).\n",
+                START_POINT (s).x, START_POINT (s).y,
+                END_POINT (s).x, END_POINT (s).y);
+
+  else if (SPLINE_DEGREE (s) == CUBICTYPE)
+    fprintf (f, "(%.3f,%.3f)..ctrls(%.3f,%.3f)&(%.3f,%.3f)..(%.3f,%.3f).\n",
+                START_POINT (s).x, START_POINT (s).y,
+                CONTROL1 (s).x, CONTROL1 (s).y,
+                CONTROL2 (s).x, CONTROL2 (s).y,
+                END_POINT (s).x, END_POINT (s).y);
+}
+
+
+/* Evaluate the spline S at a given T value.  This is an implementation
+   of de Casteljau's algorithm.  See Schneider's thesis, p.37.
+   The variable names are taken from there.  */
+
+float_coord
+evaluate_spline (spline_type s, float t)
+{
+  spline_type V[4];    /* We need degree+1 splines, but assert degree <= 3.  */
+  signed i, j;
+  float one_minus_t = (float) 1.0 - t;
+  polynomial_degree degree = SPLINE_DEGREE (s);
+
+  for (i = 0; i <= degree; i++)
+    {
+      V[0].v[i].x = s.v[i].x;
+      V[0].v[i].y = s.v[i].y;
+      V[0].v[i].z = s.v[i].z;
+    }
+
+  for (j = 1; j <= degree; j++)
+    for (i = 0; i <= degree - j; i++)
+      {
+        float_coord t1 = Pmult_scalar (V[j - 1].v[i], one_minus_t);
+        float_coord t2 = Pmult_scalar (V[j - 1].v[i + 1], t);
+        float_coord temp = Padd (t1, t2);
+        V[j].v[i].x = temp.x;
+        V[j].v[i].y = temp.y;
+        V[j].v[i].z = temp.z;
+      }
+
+  return V[degree].v[0];
+}
+
+
+/* Return a new, empty, spline list.  */
+
+spline_list_type *
+new_spline_list (void)
+{
+  spline_list_type *answer;
+
+  MALLOCVAR(answer);
+  *answer = empty_spline_list();
+  return answer;
+}
+
+spline_list_type 
+empty_spline_list (void)
+{
+  spline_list_type answer;
+  SPLINE_LIST_DATA (answer) = NULL;
+  SPLINE_LIST_LENGTH (answer) = 0;
+  return answer;
+}
+
+/* Return a new spline list with SPLINE as the first element.  */
+
+spline_list_type *
+new_spline_list_with_spline (spline_type spline)
+{
+  spline_list_type *answer;
+
+  answer = new_spline_list();
+  MALLOCVAR(SPLINE_LIST_DATA(*answer));
+  SPLINE_LIST_ELT (*answer, 0) = spline;
+  SPLINE_LIST_LENGTH (*answer) = 1;
+
+  return answer;
+}
+
+
+/* Free the storage in a spline list.  We don't have to free the
+   elements, since they are arrays in automatic storage.  And we don't
+   want to free the list if it was empty.  */
+
+void
+free_spline_list (spline_list_type spline_list)
+{
+  if (SPLINE_LIST_DATA (spline_list) != NULL)
+    free (SPLINE_LIST_DATA (spline_list));
+}
+
+
+/* Append the spline S to the list SPLINE_LIST.  */
+
+void
+append_spline (spline_list_type *l, spline_type s)
+{
+  assert (l != NULL);
+
+  SPLINE_LIST_LENGTH (*l)++;
+  REALLOCARRAY(SPLINE_LIST_DATA(*l), SPLINE_LIST_LENGTH(*l));
+  LAST_SPLINE_LIST_ELT (*l) = s;
+}
+
+
+/* Tack the elements in the list S2 onto the end of S1.
+   S2 is not changed.  */
+
+void
+concat_spline_lists (spline_list_type *s1, spline_list_type s2)
+{
+  unsigned this_spline;
+  unsigned new_length;
+
+  assert (s1 != NULL);
+
+  new_length = SPLINE_LIST_LENGTH (*s1) + SPLINE_LIST_LENGTH (s2);
+
+  REALLOCARRAY_NOFAIL(SPLINE_LIST_DATA(*s1), new_length);
+
+  for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (s2); this_spline++)
+    SPLINE_LIST_ELT (*s1, SPLINE_LIST_LENGTH (*s1)++)
+      = SPLINE_LIST_ELT (s2, this_spline);
+}
+
+
+/* Return a new, empty, spline list array.  */
+
+spline_list_array_type
+new_spline_list_array (void)
+{
+  spline_list_array_type answer;
+
+  SPLINE_LIST_ARRAY_DATA (answer) = NULL;
+  SPLINE_LIST_ARRAY_LENGTH (answer) = 0;
+
+  return answer;
+}
+
+
+/* Free the storage in a spline list array.  We don't
+   want to free the list if it is empty.  */
+void
+free_spline_list_array (spline_list_array_type *spline_list_array)
+{
+  unsigned this_list;
+
+  for (this_list = 0;
+       this_list < SPLINE_LIST_ARRAY_LENGTH (*spline_list_array);
+       this_list++)
+    free_spline_list (SPLINE_LIST_ARRAY_ELT (*spline_list_array, this_list));
+
+  if (SPLINE_LIST_ARRAY_DATA (*spline_list_array) != NULL)
+    free (SPLINE_LIST_ARRAY_DATA (*spline_list_array));
+
+  flush_log_output ();
+}
+
+
+/* Append the spline S to the list SPLINE_LIST_ARRAY.  */
+
+void
+append_spline_list (spline_list_array_type *l, spline_list_type s)
+{
+  SPLINE_LIST_ARRAY_LENGTH (*l)++;
+  REALLOCARRAY_NOFAIL(SPLINE_LIST_ARRAY_DATA(*l),
+                      SPLINE_LIST_ARRAY_LENGTH(*l));
+  LAST_SPLINE_LIST_ARRAY_ELT (*l) = s;
+}
+
diff --git a/converter/other/pamtosvg/spline.h b/converter/other/pamtosvg/spline.h
new file mode 100644
index 00000000..05a56e23
--- /dev/null
+++ b/converter/other/pamtosvg/spline.h
@@ -0,0 +1,90 @@
+/* spline.h: manipulate the spline representation.  */
+
+#ifndef SPLINE_H
+#define SPLINE_H
+
+#include <stdio.h>
+
+#include "point.h"
+#include "autotrace.h"
+
+typedef at_polynomial_degree polynomial_degree;
+typedef at_spline_type spline_type;
+
+#define LINEARTYPE          AT_LINEARTYPE
+#define QUADRATICTYPE       AT_QUADRATICTYPE
+#define CUBICTYPE           AT_CUBICTYPE
+#define PARALLELELLIPSETYPE AT_PARALLELELLIPSETYPE
+#define ELLIPSETYPE         AT_ELLIPSETYPE
+#define CIRCLETYPE          AT_CIRCLETYPE
+
+#define START_POINT(spl)        ((spl).v[0])
+#define CONTROL1(spl)           ((spl).v[1])
+#define CONTROL2(spl)           ((spl).v[2])
+#define END_POINT(spl)          ((spl).v[3])
+#define SPLINE_DEGREE(spl)      ((spl).degree)
+#define SPLINE_LINEARITY(spl)   ((spl).linearity)
+
+#ifndef _IMPORTING
+/* Print a spline on the given file.  */
+extern void print_spline (FILE *, spline_type);
+
+/* Evaluate SPLINE at the given T value.  */
+extern float_coord evaluate_spline (spline_type spline, float t);
+#endif
+
+/* Each outline in a character is typically represented by many
+   splines.  So, here is a list structure for that:  */
+typedef at_spline_list_type spline_list_type;
+
+
+/* An empty list will have length zero (and null data).  */
+#define SPLINE_LIST_LENGTH(spll)  ((spll).length)
+
+/* The address of the beginning of the array of data.  */
+#define SPLINE_LIST_DATA(spll)    ((spll).data)
+
+/* The element with index 'index' in S_L.  */
+#define SPLINE_LIST_ELT(spll, index) ((spll).data[index])
+
+/* The last element in S_L.  */
+#define LAST_SPLINE_LIST_ELT(s_l) \
+  (SPLINE_LIST_DATA (s_l)[SPLINE_LIST_LENGTH (s_l) - 1])
+
+/* The previous and next elements to INDEX in S_L.  */
+#define NEXT_SPLINE_LIST_ELT(s_l, index)                \
+  SPLINE_LIST_ELT (s_l, ((index) + 1) % SPLINE_LIST_LENGTH (s_l))
+#define PREV_SPLINE_LIST_ELT(s_l, index)                \
+  SPLINE_LIST_ELT (s_l, index == 0                  \
+                        ? SPLINE_LIST_LENGTH (s_l) - 1          \
+                        : index - 1)
+
+#ifndef _IMPORTING
+/* Construct and destroy new `spline_list_type' objects.  */
+extern spline_list_type *new_spline_list (void); /* Allocate new memory */
+extern spline_list_type empty_spline_list (void); /* No allocation */
+extern spline_list_type *new_spline_list_with_spline (spline_type);
+extern void free_spline_list (spline_list_type);
+
+/* Append the spline S to the list S_LIST.  */
+extern void append_spline (spline_list_type *s_list, spline_type s);
+
+/* Append the elements in list S2 to S1, changing S1.  */
+extern void concat_spline_lists (spline_list_type *s1, spline_list_type s2);
+#endif
+
+typedef at_spline_list_array_type spline_list_array_type;
+
+/* Turns out we can use the same definitions for lists of lists as for
+   just lists.  But we define the usual names, just in case.  */
+#define SPLINE_LIST_ARRAY_LENGTH(spll) ((spll).length)
+#define SPLINE_LIST_ARRAY_DATA     SPLINE_LIST_DATA
+#define SPLINE_LIST_ARRAY_ELT(spll, index) ((spll).data[index])
+#define LAST_SPLINE_LIST_ARRAY_ELT LAST_SPLINE_LIST_ELT
+
+extern spline_list_array_type new_spline_list_array (void);
+extern void append_spline_list (spline_list_array_type *, spline_list_type);
+extern void free_spline_list_array (spline_list_array_type *);
+
+#endif /* not SPLINE_H */
+
diff --git a/converter/other/pamtosvg/testgrid.svg b/converter/other/pamtosvg/testgrid.svg
new file mode 100644
index 00000000..e82c5551
--- /dev/null
+++ b/converter/other/pamtosvg/testgrid.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" standalone="yes"?>
+<svg width="14" height="16">
+<path style="fill:#000000; stroke:none;" d="M0 0L0 16L14 16L14 1L13 0L0 0z"/>
+<path style="fill:#ffffff; stroke:none;" d="M1 0L2 1L1 0M3 0L4 1L3 0M5 0L6 1L5 0M7 0L8 1L7 0M9 0L10 1L9 0M11 0L12 1L11 0M13 0L14 1L13 0M1 2L2 3L1 2M3 2L4 3L3 2M5 2L6 3L5 2M7 2L8 3L7 2M9 2L10 3L9 2M11 2L12 3L11 2M13 2L14 3L13 2M1 4L2 5L1 4M3 4L4 5L3 4M5 4L6 5L5 4M7 4L8 5L7 4M9 4L10 5L9 4M11 4L12 5L11 4M13 4L14 5L13 4M1 6L2 7L1 6M3 6L4 7L3 6M5 6L6 7L5 6M7 6L8 7L7 6M9 6L10 7L9 6M11 6L12 7L11 6M13 6L14 7L13 6M1 8L2 9L1 8M3 8L4 9L3 8M5 8L6 9L5 8M7 8L8 9L7 8M9 8L10 9L9 8M11 8L12 9L11 8M13 8L14 9L13 8M1 10L2 11L1 10M3 10L4 11L3 10M5 10L6 11L5 10M7 10L8 11L7 10M9 10L10 11L9 10M11 10L12 11L11 10M13 10L14 11L13 10M1 12L2 13L1 12M3 12L4 13L3 12M5 12L6 13L5 12M7 12L8 13L7 12M9 12L10 13L9 12M11 12L12 13L11 12M13 12L14 13L13 12M1 14L2 15L1 14M3 14L4 15L3 14M5 14L6 15L5 14M7 14L8 15L7 14M9 14L10 15L9 14M11 14L12 15L11 14M13 14L14 15L13 14z"/>
+</svg>
diff --git a/converter/other/pamtosvg/testline.svg b/converter/other/pamtosvg/testline.svg
new file mode 100644
index 00000000..e704ce74
--- /dev/null
+++ b/converter/other/pamtosvg/testline.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" standalone="yes"?>
+<svg width="20" height="20">
+<path style="fill:#000000; stroke:none;" d="M0 0L0 20L20 20L20 0L0 0z"/>
+<path style="fill:#ffffff; stroke:none;" d="M5 2L15 18L16 18L5 2z"/>
+</svg>
diff --git a/converter/other/pamtosvg/thin-image.c b/converter/other/pamtosvg/thin-image.c
new file mode 100644
index 00000000..40ced794
--- /dev/null
+++ b/converter/other/pamtosvg/thin-image.c
@@ -0,0 +1,373 @@
+/* thin-image.c: thin binary image
+
+   Copyright (C) 2001, 2002 Martin Weber
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser 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. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mallocvar.h"
+
+#include "thin-image.h"
+#include "logreport.h"
+#include "message.h"
+#include "bitmap.h"
+ 
+#define PIXEL_SET(p, new)  ((void)memcpy((p), (new), sizeof(Pixel)))
+#define PIXEL_EQUAL(p1, p2) \
+    ((p1)[0] == (p2)[0] && (p1)[1] == (p2)[1] && (p1)[2] == (p2)[2])
+
+ 
+typedef unsigned char Pixel[3];  /* RGB pixel data type */ 
+
+ 
+void thin3(bitmap_type *image, Pixel colour); 
+void thin1(bitmap_type *image, unsigned char colour); 
+ 
+ 
+/* -------------------------------- ThinImage - Thin binary image. --------------------------- * 
+ *                                                            
+ *    Description:                                                    
+ *        Thins the supplied binary image using Rosenfeld's parallel   
+ *        thinning algorithm.                                         
+ *                                                                     
+ *    On Entry:                                                        
+ *        image = Image to thin.                                       
+ *                                                                     
+ * -------------------------------------------------------------------------------------------- */ 
+ 
+ 
+/* Direction masks:                  */ 
+/*   N     S     W        E            */ 
+static        unsigned int     masks[]         = { 0200, 0002, 0040, 0010 }; 
+ 
+/*    True if pixel neighbor map indicates the pixel is 8-simple and  */ 
+/*    not an end point and thus can be deleted.  The neighborhood     */ 
+/*    map is defined as an integer of bits abcdefghi with a non-zero  */ 
+/*    bit representing a non-zero pixel.  The bit assignment for the  */ 
+/*    neighborhood is:                                                */ 
+/*                                                                    */ 
+/*                            a b c                                   */ 
+/*                            d e f                                   */ 
+/*                            g h i                                   */ 
+ 
+static        unsigned char   todelete[512] = { 
+              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, 1, 1, 1, 0, 0, 1, 1, 
+              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+              0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 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, 1, 1, 1, 1, 0, 0, 1, 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, 1, 1, 0, 0, 1, 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, 1, 1, 1, 1, 0, 0, 1, 1, 
+              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+              1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+              1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 
+              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+              1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+              1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 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, 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, 1, 0, 0, 1, 1, 
+              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+              1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 
+              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+              1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+              1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 
+              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+              1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 
+
+static pixel background;
+
+
+void
+thin_image(bitmap_type *image, bool bgSpec, pixel bg,
+           at_exception_type * exp)
+{ 
+    /* This is nasty as we need to call thin once for each  
+     * colour in the image the way I do this is to keep a second  
+     * copy of the bitmap and to use this to keep 
+     * track of which colours have not yet been processed, 
+     * trades time for pathological case memory.....*/ 
+    long m, n, num_pixels;
+    bitmap_type bm; 
+    unsigned int const spp = image->np;
+	unsigned int const width = image->width;
+	unsigned int const height = image->height;
+
+    if (bgSpec)
+        background = bg;
+    else 
+        PPM_ASSIGN(background, 255, 255, 255);
+
+    /* Clone the image */
+    bm.height = image->height;
+    bm.width = image->width;
+    bm.np = image->np;
+    MALLOCARRAY(bm.bitmap, height * width * spp); 
+    if (bm.bitmap == NULL)
+        pm_error("Unable to get memory for thin image bitmap clone");
+    memcpy(bm.bitmap, image->bitmap, height * width * spp); 
+
+    num_pixels = height * width;
+    switch (spp)
+    {
+	case 3:
+	{
+	    Pixel *ptr = (Pixel*)bm.bitmap;
+	    Pixel bg_color;
+	    bg_color[0] = PPM_GETR(background);
+	    bg_color[1] = PPM_GETG(background);
+	    bg_color[2] = PPM_GETB(background);
+
+	    for (n = num_pixels - 1; n >= 0L; --n)
+	    {
+		Pixel p;
+
+		PIXEL_SET(p, ptr[n]);
+		if (!PIXEL_EQUAL(p, bg_color))
+		{ 
+		    /* we have a new colour in the image */ 
+		    LOG3("Thinning colour (%x, %x, %x)\n", p[0], p[1], p[2]);
+		    for (m = n - 1; m >= 0L; --m)
+		    {
+			if (PIXEL_EQUAL(ptr[m], p))
+			    PIXEL_SET(ptr[m], bg_color);
+		    }
+		    thin3(image, p); 
+		} 
+	    } 
+	    break;
+	} 
+
+	case 1:
+	{
+	    unsigned char * const ptr = bm.bitmap;
+	    unsigned char bg_color;
+
+	    if (PPM_ISGRAY(background))
+            bg_color = PPM_GETR(background);
+	    else
+            bg_color = PPM_LUMIN(background);
+
+	    for (n = num_pixels - 1; n >= 0L; --n)
+	    {
+		unsigned char c = ptr[n];
+		if (c != bg_color)
+		{ 
+		    LOG1 ("Thinning colour %x\n", c);
+		    for (m = n - 1; m >= 0L; --m)
+			if (ptr[m] == c) ptr[m] = bg_color;
+		    thin1(image, c); 
+		} 
+	    } 
+	    break;
+	} 
+
+	default:
+	{
+	  LOG1 ("thin_image: %u-plane images are not supported", spp);
+	  at_exception_fatal(exp, "thin_image: wrong plane images are passed");
+	  goto cleanup;
+	}
+    }
+ cleanup:
+    free (bm.bitmap); 
+} 
+
+ 
+void thin3(bitmap_type *image, Pixel colour) 
+{ 
+      Pixel *ptr, *y_ptr, *y1_ptr;
+      Pixel bg_color;
+      unsigned int    xsize, ysize;   /* Image resolution             */ 
+      unsigned int    x, y;           /* Pixel location               */ 
+      unsigned int    i;              /* Pass index           */ 
+      unsigned int    pc      = 0;    /* Pass count           */ 
+      unsigned int    count   = 1;    /* Deleted pixel count          */ 
+      unsigned int    p, q;           /* Neighborhood maps of adjacent*/ 
+                                      /* cells                        */ 
+      unsigned char   *qb;            /* Neighborhood maps of previous*/ 
+                                      /* scanline                     */ 
+      unsigned int    m;              /* Deletion direction mask      */ 
+ 
+      bg_color[0] = PPM_GETR(background);
+      bg_color[1] = PPM_GETG(background);
+      bg_color[2] = PPM_GETB(background);
+
+      LOG (" Thinning image.....\n "); 
+      xsize = image->width;
+      ysize = image->height;
+      MALLOCARRAY_NOFAIL(qb, xsize); 
+      qb[xsize-1] = 0;                /* Used for lower-right pixel   */ 
+      ptr = (Pixel*)image->bitmap;
+ 
+      while ( count ) {               /* Scan image while deletions   */ 
+          pc++; 
+          count = 0; 
+ 
+          for ( i = 0 ; i < 4 ; i++ ) { 
+ 
+              m = masks[i]; 
+ 
+              /* Build initial previous scan buffer.                  */ 
+              p = PIXEL_EQUAL(ptr[0], colour); 
+              for ( x = 0 ; x < xsize-1 ; x++ ) 
+                  qb[x] = (unsigned char) (p = ((p<<1)&0006) | (unsigned int) PIXEL_EQUAL(ptr[x+1],
+				   colour)); 
+ 
+              /* Scan image for pixel deletion candidates.            */ 
+	      y_ptr = ptr; y1_ptr = ptr + xsize; 
+              for (y = 0; y < ysize - 1; y++, y_ptr += xsize, y1_ptr += xsize)
+	      { 
+                  q = qb[0]; 
+                  p = ((q<<2)&0330) | (unsigned int) PIXEL_EQUAL(y1_ptr[0], colour); 
+ 
+                  for ( x = 0 ; x < xsize-1 ; x++ ) { 
+                      q = qb[x]; 
+                      p = ((p<<1)&0666) | ((q<<3)&0110) | 
+			  (unsigned int) PIXEL_EQUAL(y1_ptr[x+1], colour);
+                      qb[x] = (unsigned char) p; 
+                      if ((i != 2 || x != 0) && ((p&m) == 0) && todelete[p] ) { 
+                          count++;  /* delete the pixel */ 
+			  PIXEL_SET(y_ptr[x], bg_color);
+                      } 
+                  } 
+ 
+                  /* Process right edge pixel.                        */ 
+                  p = (p<<1)&0666; 
+                  if  (i != 3 && (p&m) == 0 && todelete[p] ) { 
+                      count++; 
+		      PIXEL_SET(y_ptr[xsize-1], bg_color);
+                  } 
+              } 
+ 
+	      if (i != 1)
+	      {
+            /* Process bottom scan line.                            */ 
+            q = qb[0]; 
+            p = ((q<<2)&0330); 
+
+            y_ptr = ptr + xsize * (ysize - 1);
+            for ( x = 0 ; x < xsize ; x++ ) { 
+              q = qb[x]; 
+              p = ((p<<1)&0666) | ((q<<3)&0110); 
+              if ((i != 2 || x != 0) && (p&m) == 0 && todelete[p]) { 
+                count++; 
+                PIXEL_SET(y_ptr[x], bg_color);
+		      } 
+            } 
+           }
+          } 
+          LOG2 ("ThinImage: pass %d, %d pixels deleted\n", pc, count); 
+      } 
+      free (qb); 
+} 
+
+ 
+void thin1(bitmap_type *image, unsigned char colour) 
+{ 
+      unsigned char *ptr, *y_ptr, *y1_ptr;
+      unsigned char bg_color;
+      unsigned int    xsize, ysize;   /* Image resolution             */ 
+      unsigned int    x, y;           /* Pixel location               */ 
+      unsigned int    i;              /* Pass index           */ 
+      unsigned int    pc      = 0;    /* Pass count           */ 
+      unsigned int    count   = 1;    /* Deleted pixel count          */ 
+      unsigned int    p, q;           /* Neighborhood maps of adjacent*/ 
+                                      /* cells                        */ 
+      unsigned char   *qb;            /* Neighborhood maps of previous*/ 
+                                      /* scanline                     */ 
+      unsigned int    m;              /* Deletion direction mask      */ 
+
+      if (PPM_ISGRAY(background))
+          bg_color = PPM_GETR(background);
+      else
+          bg_color = PPM_LUMIN(background);
+
+      LOG (" Thinning image.....\n "); 
+      xsize = image->width;
+      ysize = image->height;
+      MALLOCARRAY_NOFAIL(qb, xsize); 
+      qb[xsize-1] = 0;                /* Used for lower-right pixel   */ 
+      ptr = image->bitmap;
+ 
+      while ( count ) {               /* Scan image while deletions   */ 
+          pc++; 
+          count = 0; 
+ 
+          for ( i = 0 ; i < 4 ; i++ ) { 
+ 
+              m = masks[i]; 
+ 
+              /* Build initial previous scan buffer.                  */ 
+              p = (ptr[0] == colour); 
+              for ( x = 0 ; x < xsize-1 ; x++ ) 
+                  qb[x] = (unsigned char) (p = ((p<<1)&0006) | (unsigned int)(ptr[x+1] == colour)); 
+ 
+              /* Scan image for pixel deletion candidates.            */ 
+	      y_ptr = ptr; y1_ptr = ptr + xsize; 
+              for (y = 0; y < ysize - 1; y++, y_ptr += xsize, y1_ptr += xsize)
+	      { 
+                  q = qb[0]; 
+                  p = ((q<<2)&0330) | (y1_ptr[0] == colour); 
+ 
+                  for ( x = 0 ; x < xsize-1 ; x++ ) { 
+                      q = qb[x]; 
+                      p = ((p<<1)&0666) | ((q<<3)&0110) | (unsigned int) (y1_ptr[x+1]==colour); 
+                      qb[x] = (unsigned char) p; 
+                      if  ( ((p&m) == 0) && todelete[p] ) { 
+                          count++; 
+			  y_ptr[x] = bg_color;  /* delete the pixel */ 
+                      } 
+                  } 
+ 
+                  /* Process right edge pixel.                        */ 
+                  p = (p<<1)&0666; 
+                  if  ( (p&m) == 0 && todelete[p] ) { 
+                      count++; 
+                      y_ptr[xsize-1] = bg_color;
+                  } 
+              } 
+ 
+              /* Process bottom scan line.                            */ 
+	      q = qb[0]; 
+	      p = ((q<<2)&0330); 
+ 
+	      y_ptr = ptr + xsize * (ysize - 1);
+              for ( x = 0 ; x < xsize ; x++ ) { 
+                  q = qb[x]; 
+                  p = ((p<<1)&0666) | ((q<<3)&0110); 
+                  if  ( (p&m) == 0 && todelete[p] ) { 
+                      count++; 
+                      y_ptr[x] = bg_color;
+                  } 
+              } 
+          } 
+          LOG2("thin1: pass %d, %d pixels deleted\n", pc, count); 
+      } 
+      free (qb); 
+} 
diff --git a/converter/other/pamtosvg/thin-image.h b/converter/other/pamtosvg/thin-image.h
new file mode 100644
index 00000000..4e0a77ee
--- /dev/null
+++ b/converter/other/pamtosvg/thin-image.h
@@ -0,0 +1,37 @@
+/* thin-image.h: thin binary image
+
+   Copyright (C) 2001, 2002 Martin Weber
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser 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. */
+
+#ifndef THIN_IMAGE_H
+#define THIN_IMAGE_H
+
+/*
+ * C code from the article
+ * "Efficient Binary Image Thinning using Neighborhood Maps"
+ * by Joseph M. Cychosz, 3ksnn64@ecn.purdue.edu
+ * in "Graphics Gems IV", Academic Press, 1994
+ */
+
+#include "bitmap.h"
+#include "exception.h"
+
+void
+thin_image(bitmap_type *image, bool bg_spec, pixel bg_color,
+           at_exception_type * exp);
+
+#endif /* not THIN_IMAGE_H */
diff --git a/converter/other/pamtosvg/vector.c b/converter/other/pamtosvg/vector.c
new file mode 100644
index 00000000..559163fc
--- /dev/null
+++ b/converter/other/pamtosvg/vector.c
@@ -0,0 +1,254 @@
+/* vector.c: vector/point operations. */
+
+#include <math.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+
+#include "pm_c_util.h"
+
+#include "vector.h"
+#include "message.h"
+#include "epsilon-equal.h"
+
+static float acos_d (float, at_exception_type * excep);
+
+
+/* Given the point COORD, return the corresponding vector.  */
+
+vector_type
+make_vector (const float_coord c)
+{
+  vector_type v;
+
+  v.dx = c.x;
+  v.dy = c.y;
+  v.dz = c.z;
+
+  return v;
+}
+
+
+/* And the converse: given a vector, return the corresponding point.  */
+
+float_coord
+vector_to_point (const vector_type v)
+{
+  float_coord coord;
+
+  coord.x = v.dx;
+  coord.y = v.dy;
+
+  return coord;
+}
+
+
+float
+magnitude (const vector_type v)
+{
+  return (float) sqrt (v.dx * v.dx + v.dy * v.dy + v.dz * v.dz);
+}
+
+
+vector_type
+normalize (const vector_type v)
+{
+  vector_type new_v;
+  float m = magnitude (v);
+
+  /* assert (m > 0.0); */
+
+  if (m > 0.0)
+  {
+    new_v.dx = v.dx / m;
+    new_v.dy = v.dy / m;
+    new_v.dz = v.dz / m;
+  }
+  else
+  {
+	new_v.dx = v.dx;
+    new_v.dy = v.dy;
+    new_v.dz = v.dz;
+  }
+
+  return new_v;
+}
+
+
+vector_type
+Vadd (const vector_type v1, const vector_type v2)
+{
+  vector_type new_v;
+
+  new_v.dx = v1.dx + v2.dx;
+  new_v.dy = v1.dy + v2.dy;
+  new_v.dz = v1.dz + v2.dz;
+
+  return new_v;
+}
+
+
+float
+Vdot (const vector_type v1, const vector_type v2)
+{
+  return v1.dx * v2.dx + v1.dy * v2.dy + v1.dz * v2.dz;
+}
+
+
+vector_type
+Vmult_scalar (const vector_type v, const float r)
+{
+  vector_type new_v;
+
+  new_v.dx = v.dx * r;
+  new_v.dy = v.dy * r;
+  new_v.dz = v.dz * r;
+
+  return new_v;
+}
+
+
+/* Given the IN_VECTOR and OUT_VECTOR, return the angle between them in
+   degrees, in the range zero to 180.  */
+
+float
+Vangle (const vector_type in_vector, 
+	const vector_type out_vector,
+	at_exception_type * exp)
+{
+  vector_type v1 = normalize (in_vector);
+  vector_type v2 = normalize (out_vector);
+
+  return acos_d (Vdot (v2, v1), exp);
+}
+
+
+float_coord
+Vadd_point (const float_coord c, const vector_type v)
+{
+  float_coord new_c;
+
+  new_c.x = c.x + v.dx;
+  new_c.y = c.y + v.dy;
+  new_c.z = c.z + v.dz;
+  return new_c;
+}
+
+
+float_coord
+Vsubtract_point (const float_coord c, const vector_type v)
+{
+  float_coord new_c;
+
+  new_c.x = c.x - v.dx;
+  new_c.y = c.y - v.dy;
+  new_c.z = c.z - v.dz;
+  return new_c;
+}
+
+
+pm_pixelcoord
+Vadd_int_point(pm_pixelcoord const c,
+               vector_type   const v) {
+
+    pm_pixelcoord a;
+
+    a.col = ROUND ((float) c.col + v.dx);
+    a.row = ROUND ((float) c.row + v.dy);
+    
+    return a;
+}
+
+
+vector_type
+Vabs (const vector_type v)
+{
+  vector_type new_v;
+
+  new_v.dx = (float) fabs (v.dx);
+  new_v.dy = (float) fabs (v.dy);
+  new_v.dz = (float) fabs (v.dz);
+  return new_v;
+}
+
+
+/* Operations on points.  */
+
+float_coord
+Padd (const float_coord coord1, const float_coord coord2)
+{
+  float_coord sum;
+
+  sum.x = coord1.x + coord2.x;
+  sum.y = coord1.y + coord2.y;
+  sum.z = coord1.z + coord2.z;
+
+  return sum;
+}
+
+
+float_coord
+Pmult_scalar (const float_coord coord, const float r)
+{
+  float_coord answer;
+
+  answer.x = coord.x * r;
+  answer.y = coord.y * r;
+  answer.z = coord.z * r;
+
+  return answer;
+}
+
+
+vector_type
+Psubtract (const float_coord c1, const float_coord c2)
+{
+  vector_type v;
+
+  v.dx = c1.x - c2.x;
+  v.dy = c1.y - c2.y;
+  v.dz = c1.z - c2.z;
+
+  return v;
+}
+
+
+
+/* Operations on integer points.  */
+
+vector_type
+IPsubtract(pm_pixelcoord const coord1,
+           pm_pixelcoord const coord2) {
+
+    vector_type v;
+
+    v.dx = (int) (coord1.col - coord2.col);
+    v.dy = (int) (coord1.row - coord2.row);
+    v.dz = 0.0;
+    
+    return v;
+}
+
+
+
+static float
+acos_d (float v, at_exception_type * excep)
+{
+  float a;
+
+  if (epsilon_equal (v, 1.0))
+    v = 1.0;
+  else if (epsilon_equal (v, -1.0))
+    v = -1.0;
+
+  errno = 0;
+  a = (float) acos (v);
+  if (errno == ERANGE || errno == EDOM)
+    {
+      at_exception_fatal(excep, strerror(errno));
+      return 0.0;
+    }
+  
+  
+  return a * (float) 180.0 / (float) M_PI;
+}
diff --git a/converter/other/pamtosvg/vector.h b/converter/other/pamtosvg/vector.h
new file mode 100644
index 00000000..74fb2fd2
--- /dev/null
+++ b/converter/other/pamtosvg/vector.h
@@ -0,0 +1,71 @@
+/* vector.h: operations on vectors and points. */
+
+#ifndef VECTOR_H
+#define VECTOR_H
+
+#include "point.h"
+#include "exception.h"
+
+/* Our vectors are represented as displacements along the x and y axes.  */
+
+typedef struct
+{
+  float dx, dy, dz;
+} vector_type;
+
+
+/* Consider a point as a vector from the origin.  */
+extern vector_type make_vector (const float_coord);
+
+/* And a vector as a point, i.e., a displacement from the origin.  */
+extern float_coord vector_to_point (const vector_type);
+
+
+/* Definitions for these common operations can be found in any decent
+   linear algebra book, and most calculus books.  */
+
+extern float magnitude (const vector_type);
+extern vector_type normalize (const vector_type);
+
+extern vector_type Vadd (const vector_type, const vector_type);
+extern float Vdot (const vector_type, const vector_type);
+extern vector_type Vmult_scalar (const vector_type, const float);
+extern float Vangle (const vector_type in, const vector_type out, at_exception_type * exp);
+
+/* These operations could have been named `P..._vector' just as well as
+   V..._point, so we may as well allow both names.  */
+#define Padd_vector Vadd_point
+extern float_coord Vadd_point
+  (const float_coord, const vector_type);
+
+#define Psubtract_vector Vsubtract_point
+extern float_coord Vsubtract_point
+  (const float_coord, const vector_type);
+
+/* This returns the rounded sum.  */
+#define IPadd_vector Vadd_int_point
+
+pm_pixelcoord
+Vadd_int_point(pm_pixelcoord const c,
+               vector_type   const v);
+
+/* Take the absolute value of both components.  */
+extern vector_type Vabs (const vector_type);
+
+/* Operations on points with real coordinates.  It is not orthogonal,
+   but more convenient, to have the subtraction operator return a
+   vector, and the addition operator return a point.  */
+extern vector_type Psubtract
+  (const float_coord, const float_coord);
+
+vector_type
+IPsubtract(pm_pixelcoord const coord1,
+           pm_pixelcoord const coord2);
+
+/* These are heavily used in spline fitting.  */
+extern float_coord Padd (const float_coord,
+                                  const float_coord);
+extern float_coord Pmult_scalar (const float_coord, const float);
+
+#endif
+
diff --git a/converter/other/pamtotga.c b/converter/other/pamtotga.c
new file mode 100644
index 00000000..1e0808ed
--- /dev/null
+++ b/converter/other/pamtotga.c
@@ -0,0 +1,572 @@
+/* pamtotga.c - read a portable pixmap and produce a TrueVision Targa file
+**
+** Copyright (C) 1989, 1991 by Mark Shand and 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.
+*/
+
+#define _BSD_SOURCE  /* Make sure string.h contains strdup() */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include <string.h>
+
+#include "pam.h"
+#include "pammap.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "tga.h"
+
+/* Max number of colors allowed for colormapped output. */
+#define MAXCOLORS 256
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char *inputFilespec;  /* Filespec of input file */
+    char *outName;
+    enum TGAbaseImageType imgType;
+    bool defaultFormat;
+    unsigned int norle;
+};
+
+
+
+static void
+parseCommandLine(int argc, char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Parse the program arguments (given by argc and argv) into a form
+   the program can deal with more easily -- a cmdline_info structure.
+   If the syntax is invalid, issue a message and exit the program via
+   pm_error().
+
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optStruct3 opt;  /* set by OPTENT3 */
+    optEntry *option_def = malloc(100*sizeof(optEntry));
+    unsigned int option_def_index;
+
+    unsigned int outNameSpec;
+    unsigned int cmap, mono, rgb;
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0,   "name",       OPT_STRING, 
+            &cmdlineP->outName, &outNameSpec, 0);
+    OPTENT3(0,   "cmap",       OPT_FLAG, 
+            NULL, &cmap, 0);
+    OPTENT3(0,   "mono",       OPT_FLAG, 
+            NULL, &mono, 0);
+    OPTENT3(0,   "rgb",        OPT_FLAG, 
+            NULL, &rgb, 0);
+    OPTENT3(0,   "norle",      OPT_FLAG, 
+            NULL, &cmdlineP->norle, 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);
+        /* Uses and sets argc, argv, and some of *cmdline_p and others. */
+
+    if (cmap + mono + rgb > 1)
+        pm_error("You may specify only one of -cmap, -mono, and -rgb.");
+
+    if (cmap + mono + rgb == 0)
+        cmdlineP->defaultFormat = TRUE;
+    else {
+        cmdlineP->defaultFormat = FALSE;
+    
+        if (cmap)
+            cmdlineP->imgType = TGA_MAP_TYPE;
+        else if (mono)
+            cmdlineP->imgType = TGA_MONO_TYPE;
+        else if (rgb)
+            cmdlineP->imgType = TGA_RGB_TYPE;
+    }
+
+    if (!outNameSpec)
+        cmdlineP->outName = NULL;
+    
+    if (argc-1 == 0) 
+        cmdlineP->inputFilespec = "-";
+    else if (argc-1 != 1)
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
+    else
+        cmdlineP->inputFilespec = argv[1];
+
+}
+
+
+static void
+writeTgaHeader(struct ImageHeader const tgaHeader) {
+
+    unsigned char flags;
+
+    putchar(tgaHeader.IdLength);
+    putchar(tgaHeader.CoMapType);
+    putchar(tgaHeader.ImgType);
+    putchar(tgaHeader.Index_lo);
+    putchar(tgaHeader.Index_hi);
+    putchar(tgaHeader.Length_lo);
+    putchar(tgaHeader.Length_hi);
+    putchar(tgaHeader.CoSize);
+    putchar(tgaHeader.X_org_lo);
+    putchar(tgaHeader.X_org_hi);
+    putchar(tgaHeader.Y_org_lo);
+    putchar(tgaHeader.Y_org_hi);
+    putchar(tgaHeader.Width_lo);
+    putchar(tgaHeader.Width_hi);
+    putchar(tgaHeader.Height_lo);
+    putchar(tgaHeader.Height_hi);
+    putchar(tgaHeader.PixelSize);
+    flags = (tgaHeader.AttBits & 0xf) | 
+        ((tgaHeader.Rsrvd & 0x1) << 4) |
+        ((tgaHeader.OrgBit & 0x1) << 5) | 
+        ((tgaHeader.OrgBit & 0x3) << 6);
+    putchar(flags);
+
+    if (tgaHeader.IdLength > 0)
+        fwrite(tgaHeader.Id, 1, (int) tgaHeader.IdLength, stdout);
+}
+    
+
+
+static void
+putPixel(struct pam *          const pamP,
+         tuple                 const tuple, 
+         enum TGAbaseImageType const imgType, 
+         bool                  const withAlpha,
+         tuplehash             const cht) {
+/*----------------------------------------------------------------------------
+   Write a single pixel of the TGA raster to Standard Output.  The
+   pixel is to have color 'tuple'.  The raster has format 'imgType'.
+   The color palette from which the specified color is to be drawn, if
+   'imgType' indicates use of a color palette, is 'cht'.
+-----------------------------------------------------------------------------*/
+    if (imgType == TGA_MAP_TYPE) {
+        int retval;
+        int found;
+
+        pnm_lookuptuple(pamP, cht, tuple, &found, &retval);
+        if (!found)
+            pm_error("Internal error: color not found in map that was "
+                     "generated from all the colors in the image");
+        putchar(retval);
+    } else {
+        if (imgType == TGA_RGB_TYPE && pamP->depth < 3) {
+            /* Make RGB pixel out of a single input plane */
+            unsigned int plane;
+            
+            for (plane = 0; plane < 3; ++plane) 
+                putchar(pnm_scalesample(tuple[0], 
+                                        pamP->maxval, TGA_MAXVAL));
+        } else if (imgType == TGA_MONO_TYPE)
+            putchar(pnm_scalesample(tuple[0], 
+                                    pamP->maxval, TGA_MAXVAL));
+        else {
+            putchar(pnm_scalesample(tuple[PAM_BLU_PLANE], 
+                                    pamP->maxval, TGA_MAXVAL));
+            putchar(pnm_scalesample(tuple[PAM_GRN_PLANE], 
+                                    pamP->maxval, TGA_MAXVAL));
+            putchar(pnm_scalesample(tuple[PAM_RED_PLANE], 
+                                    pamP->maxval, TGA_MAXVAL));
+            if (withAlpha)
+                putchar(pnm_scalesample(tuple[PAM_TRN_PLANE], 
+                                        pamP->maxval, TGA_MAXVAL));
+        }
+    }
+}
+
+
+
+static void
+putMapEntry(struct pam * const pamP, 
+            tuple        const value, 
+            int          const size) {
+
+    if (size == 15 || size == 16) {
+        /* 5 bits each of red, green, and blue.  Watch for byte order */
+
+        tuple const tuple31 = pnm_allocpamtuple(pamP);
+
+        pnm_scaletuple(pamP, tuple31, value, 31);
+        {
+            int const mapentry = 
+                tuple31[PAM_BLU_PLANE] << 0 |
+                tuple31[PAM_GRN_PLANE] << 5 |
+                tuple31[PAM_RED_PLANE] << 10;
+            
+            putchar(mapentry % 256);
+            putchar(mapentry / 256);
+        }
+        pnm_freepamtuple(tuple31);
+    } else if (size == 8)
+        putchar(pnm_scalesample(value[0], 
+                                pamP->maxval, TGA_MAXVAL));
+    else {
+        /* Must be 24 or 32 */
+        putchar(pnm_scalesample(value[PAM_BLU_PLANE], 
+                                pamP->maxval, TGA_MAXVAL));
+        putchar(pnm_scalesample(value[PAM_GRN_PLANE], 
+                                pamP->maxval, TGA_MAXVAL));
+        putchar(pnm_scalesample(value[PAM_RED_PLANE], 
+                                    pamP->maxval, TGA_MAXVAL));
+        if (size == 32)
+            putchar(pnm_scalesample(value[PAM_TRN_PLANE], 
+                                    pamP->maxval, TGA_MAXVAL));
+    }
+}
+
+
+
+static void
+computeRunlengths(struct pam * const pamP, 
+                   tuple *      const tuplerow, 
+                   int *        const runlength) {
+
+    int col, start;
+
+    /* Initialize all run lengths to 0.  (This is just an error check.) */
+    for (col = 0; col < pamP->width; ++col)
+        runlength[col] = 0;
+    
+    /* Find runs of identical pixels. */
+    for ( col = 0; col < pamP->width; ) {
+        start = col;
+        do {
+            ++col;
+        } while ( col < pamP->width &&
+                  col - start < 128 &&
+                  pnm_tupleequal(pamP, tuplerow[col], tuplerow[start]));
+        runlength[start] = col - start;
+    }
+    
+    /* Now look for runs of length-1 runs, and turn them into negative runs. */
+    for (col = 0; col < pamP->width; ) {
+        if (runlength[col] == 1) {
+            start = col;
+            while (col < pamP->width &&
+                   col - start < 128 &&
+                   runlength[col] == 1 ) {
+                runlength[col] = 0;
+                ++col;
+            }
+            runlength[start] = - ( col - start );
+        } else
+            col += runlength[col];
+    }
+}
+
+
+
+static void
+computeOutName(struct cmdlineInfo const cmdline, 
+               const char ** const outNameP) {
+    
+    char * workarea;
+
+    if (cmdline.outName)
+        workarea = strdup(cmdline.outName);
+    else if (streq(cmdline.inputFilespec, "-"))
+        workarea = NULL;
+    else {
+        char * cp;
+        workarea = strdup(cmdline.inputFilespec);
+        cp = strchr(workarea, '.');
+        if (cp != NULL)
+        	*cp = '\0';	/* remove extension */
+    }
+    
+    if (workarea == NULL)
+        *outNameP = NULL;
+    else {
+        /* Truncate the name to fit TGA specs */
+        if (strlen(workarea) > IMAGEIDFIELDMAXSIZE)
+            workarea[IMAGEIDFIELDMAXSIZE] = '\0';
+        *outNameP = workarea;
+    }
+}
+
+
+
+static void
+validateTupleType(struct pam * const pamP) {
+
+    if (streq(pamP->tuple_type, "RGB_ALPHA")) {
+        if (pamP->depth < 4)
+            pm_error("Invalid depth for tuple type RGB_ALPHA.  "
+                     "Should have at least 4 planes, but has %d.", 
+                     pamP->depth);
+    } else if (streq(pamP->tuple_type, "RGB")) {
+        if (pamP->depth < 3)
+            pm_error("Invalid depth for tuple type RGB.  "
+                     "Should have at least 3 planes, but has %d.", 
+                     pamP->depth);
+    } else if (streq(pamP->tuple_type, "GRAYSCALE")) {
+    } else if (streq(pamP->tuple_type, "BLACKANDWHITE")) {
+    } else 
+        pm_error("Invalid type of input.  PAM tuple type is '%s'.  "
+                 "This programs understands only RGB_ALPHA, RGB, GRAYSCALE, "
+                 "and BLACKANDWHITE.", pamP->tuple_type);
+}
+
+
+
+static void
+computeImageType_cht(struct pam *            const pamP,
+                     struct cmdlineInfo      const cmdline, 
+                     tuple **                const tuples,
+                     enum TGAbaseImageType * const baseImgTypeP,
+                     bool *                  const withAlphaP,
+                     tupletable *            const chvP,
+                     tuplehash *             const chtP, 
+                     int *                   const ncolorsP) {
+
+    unsigned int ncolors;
+    enum TGAbaseImageType baseImgType;
+    bool withAlpha;
+
+    validateTupleType(pamP);
+
+    withAlpha = (streq(pamP->tuple_type, "RGB_ALPHA"));
+
+    if (cmdline.defaultFormat) {
+        /* default the image type */
+        if (withAlpha) {
+            baseImgType = TGA_RGB_TYPE;
+            *chvP = NULL;
+        } else if (pamP->depth > 1) {
+            pm_message("computing colormap...");
+            *chvP = 
+                pnm_computetuplefreqtable(pamP, tuples, MAXCOLORS, &ncolors);
+            if (*chvP == NULL) {
+                pm_message("Too many colors for colormapped TGA.  Doing RGB.");
+                baseImgType = TGA_RGB_TYPE;
+            } else 
+                baseImgType = TGA_MAP_TYPE;
+        } else {
+            baseImgType = TGA_MONO_TYPE;
+            *chvP = NULL;
+        }
+    } else {
+        baseImgType = cmdline.imgType;
+
+        if (baseImgType == TGA_MAP_TYPE) {
+            if (withAlpha)
+                pm_error("Can't do a colormap because image has transparency "
+                         "information");
+            pm_message("computing colormap...");
+            *chvP = 
+                pnm_computetuplefreqtable(pamP, tuples, MAXCOLORS, &ncolors);
+            if (*chvP == NULL) 
+                pm_error("Too many colors for colormapped TGA.  "
+                         "Use 'pnmquant %d' to reduce the number of colors.", 
+                         MAXCOLORS);
+        } else
+            *chvP = NULL;
+        if (baseImgType == TGA_MONO_TYPE && pamP->depth > 1)
+            pm_error("For Mono TGA output, input must be "
+                     "GRAYSCALE or BLACKANDWHITE PAM or PBM or PGM");
+    }
+    
+    if (baseImgType == TGA_MAP_TYPE) {
+        pm_message("%d colors found.", ncolors);
+        /* Make a hash table for fast color lookup. */
+        *chtP = pnm_computetupletablehash(pamP, *chvP, ncolors);
+    } else
+        *chtP = NULL;
+
+    *baseImgTypeP = baseImgType;
+    *withAlphaP   = withAlpha;
+    *ncolorsP     = ncolors;
+}
+
+
+
+static void
+computeTgaHeader(struct pam *          const pamP,
+                 enum TGAbaseImageType const baseImgType,
+                 bool                  const withAlpha,
+                 bool                  const rle, 
+                 int                   const ncolors,
+                 unsigned char         const orgBit,
+                 const char *          const id,
+                 struct ImageHeader *  const tgaHeaderP) {
+
+    if (rle) {
+        switch (baseImgType ) {
+        case TGA_MONO_TYPE: tgaHeaderP->ImgType = TGA_RLEMono;          break;
+        case TGA_MAP_TYPE:  tgaHeaderP->ImgType = TGA_RLEMap;           break;
+        case TGA_RGB_TYPE:  tgaHeaderP->ImgType = TGA_RLERGB;           break;
+        }
+    } else {
+        switch(baseImgType) {
+        case TGA_MONO_TYPE: tgaHeaderP->ImgType = TGA_Mono;          break;
+        case TGA_MAP_TYPE:  tgaHeaderP->ImgType = TGA_Map;           break;
+        case TGA_RGB_TYPE:  tgaHeaderP->ImgType = TGA_RGB;           break;
+        }
+    }
+    
+    if (id) {
+        tgaHeaderP->IdLength = strlen(id);
+        tgaHeaderP->Id = strdup(id);
+    } else
+        tgaHeaderP->IdLength = 0;
+    tgaHeaderP->Index_lo = 0;
+    tgaHeaderP->Index_hi = 0;
+    if (baseImgType == TGA_MAP_TYPE) {
+        tgaHeaderP->CoMapType = 1;
+        tgaHeaderP->Length_lo = ncolors % 256;
+        tgaHeaderP->Length_hi = ncolors / 256;
+        tgaHeaderP->CoSize = 8 * pamP->depth;
+    } else {
+        tgaHeaderP->CoMapType = 0;
+        tgaHeaderP->Length_lo = 0;
+        tgaHeaderP->Length_hi = 0;
+        tgaHeaderP->CoSize = 0;
+    }
+    switch (baseImgType) {
+    case TGA_MAP_TYPE:
+        tgaHeaderP->PixelSize = 8;
+        break;
+    case TGA_RGB_TYPE:
+        tgaHeaderP->PixelSize = 8 * MAX((withAlpha ? 4: 3), pamP->depth);
+        break;
+    case TGA_MONO_TYPE:
+        tgaHeaderP->PixelSize = 8;
+    }
+    tgaHeaderP->X_org_lo = tgaHeaderP->X_org_hi = 0;
+    tgaHeaderP->Y_org_lo = tgaHeaderP->Y_org_hi = 0;
+    tgaHeaderP->Width_lo = pamP->width % 256;
+    tgaHeaderP->Width_hi = pamP->width / 256;
+    tgaHeaderP->Height_lo = pamP->height % 256;
+    tgaHeaderP->Height_hi = pamP->height / 256;
+    tgaHeaderP->AttBits = 0;
+    tgaHeaderP->Rsrvd = 0;
+    tgaHeaderP->IntrLve = 0;
+    tgaHeaderP->OrgBit = orgBit;
+}
+
+
+
+static void
+releaseTgaHeader(struct ImageHeader const tgaHeader) {
+
+    strfree(tgaHeader.Id);
+}
+
+
+
+static void 
+writeTgaRaster(struct pam *          const pamP,
+               tuple **              const tuples, 
+               tuplehash             const cht,
+               enum TGAbaseImageType const imgType,
+               bool                  const withAlpha,
+               bool                  const rle,
+               unsigned char         const orgBit) {
+
+    int* runlength;  /* malloc'ed */
+    int row;
+
+    if (rle)
+        MALLOCARRAY(runlength, pamP->width);
+
+    for (row = 0; row < pamP->height; ++row) {
+        int realrow;
+        realrow = (orgBit != 0) ? row : pamP->height - row - 1;
+        if (rle) {
+            int col;
+            computeRunlengths(pamP, tuples[realrow], runlength);
+            for (col = 0; col < pamP->width; ) {
+                if (runlength[col] > 0) {
+                    putchar(0x80 + runlength[col] - 1);
+                    putPixel(pamP, tuples[realrow][col], imgType, withAlpha,
+                             cht);
+                    col += runlength[col];
+                } else if (runlength[col] < 0) {
+                    int i;
+                    putchar(-runlength[col] - 1);
+                    for (i = 0; i < -runlength[col]; ++i)
+                        putPixel(pamP, tuples[realrow][col+i], 
+                                 imgType, withAlpha, cht);
+                    col += -runlength[col];
+                } else
+                    pm_error("Internal error: zero run length");
+            }
+        } else {
+            int col;
+            for (col = 0; col < pamP->width; ++col)
+                putPixel(pamP, tuples[realrow][col], imgType, withAlpha, cht);
+        }
+    }
+    if (rle)
+        free(runlength);
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    tuple ** tuples;
+    struct pam pam;
+    int ncolors;
+    tupletable chv;
+    tuplehash cht;
+    struct ImageHeader tgaHeader;
+    enum TGAbaseImageType baseImgType;
+    bool withAlpha;
+    const char *outName;
+
+    pnm_init( &argc, argv );
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    computeOutName(cmdline, &outName);
+
+    tuples = pnm_readpam(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+    pm_close(ifP);
+
+    computeImageType_cht(&pam, cmdline, tuples, 
+                         &baseImgType, &withAlpha, &chv, &cht, &ncolors);
+
+    /* Do the Targa header */
+    computeTgaHeader(&pam, baseImgType, withAlpha, !cmdline.norle,
+                     ncolors, 0, outName, &tgaHeader);
+    writeTgaHeader(tgaHeader);
+    
+    if (baseImgType == TGA_MAP_TYPE) {
+        /* Write out the Targa colormap. */
+        int i;
+        for (i = 0; i < ncolors; ++i)
+            putMapEntry(&pam, chv[i]->tuple, tgaHeader.CoSize);
+    }
+
+    writeTgaRaster(&pam, tuples, cht, baseImgType, withAlpha, 
+                   !cmdline.norle, 0);
+
+    if (cht)
+        pnm_destroytuplehash(cht);
+    if (chv)
+        pnm_freetupletable(&pam, chv);
+
+    releaseTgaHeader(tgaHeader);
+    strfree(outName);
+    pnm_freepamarray(tuples, &pam);
+
+    return 0;
+}
diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c
new file mode 100644
index 00000000..4174a431
--- /dev/null
+++ b/converter/other/pamtotiff.c
@@ -0,0 +1,1110 @@
+/*
+** pnmtotiff.c - converts a PNM image to a TIFF (Tagged Image File) image
+**
+** Derived by Jef Poskanzer from ras2tif.c, which is:
+**
+** Copyright (c) 1990 by Sun Microsystems, Inc.
+**
+** Author: Patrick J. Naughton
+** naughton@wind.sun.com
+**
+** 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 file is provided AS IS with no warranties of any kind.  The author
+** shall have no liability with respect to the infringement of copyrights,
+** trade secrets or any patents by this file or any part thereof.  In no
+** event will the author be liable for any lost revenue or profits or
+** other special, indirect and consequential damages.
+*/
+
+#define _XOPEN_SOURCE    /* Make sure stdio.h contains fileno() */
+#define _BSD_SOURCE      /* Make sure string.h contains strcasecmp() */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#ifdef VMS
+#ifdef SYSV
+#undef SYSV
+#endif
+#include <tiffioP.h>
+#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
+   AIX, <inttypes.h> defines it in some cases.  One case in which <inttypes.h>
+   does _not_ define int32 is where _XOPEN_SOURCE is declared.  So we always
+   do that when including tiffio.h.  06.01.05
+*/
+#include <tiffio.h>
+
+#include <string.h>
+
+#include "pm_c_util.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "pam.h"
+#include "pammap.h"
+#include "pm_tiff.h"
+
+#define MAXCOLORS 256
+
+/* 2001.09.03: Old tiff.h doesn't contain these values: */
+#ifndef COMPRESSION_ADOBE_DEFLATE
+#define COMPRESSION_ADOBE_DEFLATE 8
+#endif
+
+struct sizeset {
+    bool b1, b2, b4, b8;
+};
+
+
+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 compression;
+        /* COMPRESSION Tiff tag value, that corresponds to the compression
+           option the user specified, or -1 if he didn't specify any.
+           The -tag option doesn't count.
+        */
+    int fillorder;     /* FILLORDER Tiff tag value */
+    int g3options;     /* G3OPTIONS Tiff tag value or 0 for none */
+    int predictor;     /* PREDICTOR Tiff tag value or -1 for none */
+    int rowsperstrip;  /* -1 = unspecified */
+    unsigned int minisblack;   /* logical: User wants MINISBLACK photometric */
+    unsigned int miniswhite;   /* logical: User wants MINISWHITE photometric */
+    unsigned int truecolor;    /* logical: User wants truecolor, not cmap */
+    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;
+    /* Which bit widths are allowable in a raster of palette indices */
+    unsigned int verbose;
+    unsigned int append;
+    float resolution;  /* X and Y resolution */
+    struct optNameValue * taglist;
+};
+
+
+
+static void
+validateTagList(struct optNameValue const taglist[]) {
+
+    unsigned int i;
+    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 {
+            /* We don't allow the user to set directly any tag that we
+               control explicitly.  These are normally tags that have to be
+               consistent with other stuff we put in the image.  But in some
+               cases, they're just tags we had special options for before
+               -tag existed.  The latter should probably be converted
+               eventually to prefer -tag.
+            */
+            switch (tagDefP->tagnum) {
+            case TIFFTAG_IMAGEWIDTH:
+            case TIFFTAG_IMAGELENGTH:
+            case TIFFTAG_BITSPERSAMPLE:
+            case TIFFTAG_COMPRESSION:
+            case TIFFTAG_GROUP3OPTIONS:
+            case TIFFTAG_PREDICTOR:
+            case TIFFTAG_PHOTOMETRIC:
+            case TIFFTAG_FILLORDER:
+            case TIFFTAG_SAMPLESPERPIXEL:
+            case TIFFTAG_ROWSPERSTRIP:
+            case TIFFTAG_PLANARCONFIG:
+            case TIFFTAG_COLORMAP:
+            case TIFFTAG_RESOLUTIONUNIT:
+            case TIFFTAG_XRESOLUTION:
+            case TIFFTAG_YRESOLUTION:
+                pm_error("You cannot specify a '%s' tag with -tag.  "
+                         "Pamtotiff controls that internally or via other "
+                         "options.", tagName);
+            }
+        }
+    }
+}
+
+
+
+static void
+parseCommandLine(int                        argc,
+                 char **              const 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;
+
+    optStruct3 opt;
+
+    unsigned int none, packbits, lzw, g3, g4, msb2lsb, lsb2msb, opt_2d, fill;
+    unsigned int flate, adobeflate;
+    char * indexbits;
+    char * resolutionUnit;
+
+    unsigned int predictorSpec, rowsperstripSpec, xresolutionSpec,
+        yresolutionSpec, indexbitsSpec, resolutionUnitSpec, tagSpec;
+
+    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);
+    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);
+    OPTENT3(0, "g3",           OPT_FLAG,   NULL, &g3,                      0);
+    OPTENT3(0, "g4",           OPT_FLAG,   NULL, &g4,                      0);
+    OPTENT3(0, "flate",        OPT_FLAG,   NULL, &flate,                   0);
+    OPTENT3(0, "adobeflate",   OPT_FLAG,   NULL, &adobeflate,              0);
+    OPTENT3(0, "msb2lsb",      OPT_FLAG,   NULL, &msb2lsb,                 0);
+    OPTENT3(0, "lsb2msb",      OPT_FLAG,   NULL, &lsb2msb,                 0);
+    OPTENT3(0, "2d",           OPT_FLAG,   NULL, &opt_2d,                  0);
+    OPTENT3(0, "fill",         OPT_FLAG,   NULL, &fill,                    0);
+    OPTENT3(0, "minisblack",   OPT_FLAG,   NULL, &cmdlineP->minisblack,    0);
+    OPTENT3(0, "mb",           OPT_FLAG,   NULL, &cmdlineP->minisblack,    0);
+    OPTENT3(0, "miniswhite",   OPT_FLAG,   NULL, &cmdlineP->miniswhite,    0);
+    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,    
+            &predictorSpec,    0);
+    OPTENT3(0, "rowsperstrip", OPT_UINT,   &cmdlineP->rowsperstrip, 
+            &rowsperstripSpec, 0);
+    OPTENT3(0, "xresolution",  OPT_FLOAT,  &cmdlineP->xresolution,  
+            &xresolutionSpec,  0);
+    OPTENT3(0, "yresolution",  OPT_FLOAT,  &cmdlineP->yresolution,  
+            &yresolutionSpec,  0);
+    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);
+
+    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);
+    /* 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)
+        cmdlineP->compression = COMPRESSION_PACKBITS;
+    else if (lzw)
+        cmdlineP->compression = COMPRESSION_LZW;
+    else if (g3)
+        cmdlineP->compression = COMPRESSION_CCITTFAX3;
+    else if (g4)
+        cmdlineP->compression = COMPRESSION_CCITTFAX4;
+    else if (adobeflate)
+        cmdlineP->compression = COMPRESSION_ADOBE_DEFLATE;
+    else if (flate)
+        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.");
+
+    if (msb2lsb)
+        cmdlineP->fillorder = FILLORDER_MSB2LSB;
+    else if (lsb2msb)
+        cmdlineP->fillorder = FILLORDER_LSB2MSB;
+    else 
+        cmdlineP->fillorder = FILLORDER_MSB2LSB;
+    
+
+    if (cmdlineP->miniswhite && cmdlineP->minisblack)
+        pm_error("You cannot specify both -miniswhite and -minisblack");
+
+    cmdlineP->g3options = 0;  /* initial value */
+    if (opt_2d)
+        cmdlineP->g3options |= GROUP3OPT_2DENCODING;
+    if (fill)
+        cmdlineP->g3options |= GROUP3OPT_FILLBITS;
+
+    if (predictorSpec) {
+        if (cmdlineP->predictor != 1 && cmdlineP->predictor != 2)
+            pm_error("-predictor may be only 1 or 2.  You specified %d.", 
+                     cmdlineP->predictor);
+    } else
+        cmdlineP->predictor = -1;
+
+    if (rowsperstripSpec) {
+        if (cmdlineP->rowsperstrip < 1)
+            pm_error("-rowsperstrip must be positive.  You specified %d.",
+                     cmdlineP->rowsperstrip);
+    } else
+        cmdlineP->rowsperstrip = -1;
+
+    if (xresolutionSpec) {
+        if (cmdlineP->xresolution < 1)
+            pm_error("-xresolution must be positive.  You specified %f.",
+                     cmdlineP->xresolution);
+    } else
+        cmdlineP->xresolution = -1;
+
+    if (yresolutionSpec) {
+        if (cmdlineP->yresolution < 1)
+            pm_error("-yresolution must be positive.  You specified %f.",
+                     cmdlineP->yresolution);
+    } 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;
+        else
+            pm_error("The only acceptable values for -resolutionunit are "
+                     "inch, centimeter, none, in, cm, and no.  "
+                     "You specified '%s'.", resolutionUnit);
+    } else
+        cmdlineP->resolutionUnit = RESUNIT_INCH;
+
+    if (indexbitsSpec) {
+        if (strstr(indexbits, "1"))
+            cmdlineP->indexsizeAllowed.b1 = TRUE;
+        else
+            cmdlineP->indexsizeAllowed.b1 = FALSE;
+        if (strstr(indexbits, "2"))
+            cmdlineP->indexsizeAllowed.b2 = TRUE;
+        else
+            cmdlineP->indexsizeAllowed.b2 = FALSE;
+        if (strstr(indexbits, "4"))
+            cmdlineP->indexsizeAllowed.b4 = TRUE;
+        else
+            cmdlineP->indexsizeAllowed.b4 = FALSE;
+        if (strstr(indexbits, "8"))
+            cmdlineP->indexsizeAllowed.b8 = TRUE;
+        else
+            cmdlineP->indexsizeAllowed.b8 = FALSE;
+    } else {
+        cmdlineP->indexsizeAllowed.b1 = FALSE;
+        cmdlineP->indexsizeAllowed.b2 = FALSE;
+        cmdlineP->indexsizeAllowed.b4 = FALSE;
+        cmdlineP->indexsizeAllowed.b8 = TRUE;
+    }
+
+    if (tagSpec)
+        validateTagList(cmdlineP->taglist);
+    else {
+        MALLOCARRAY_NOFAIL(cmdlineP->taglist, 1);
+        cmdlineP->taglist[0].name = NULL;
+        cmdlineP->taglist[0].value = NULL;
+    }
+
+    if (argc-1 == 0) 
+        cmdlineP->input_filespec = "-";
+    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];
+}
+
+
+
+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)) = s;
+        (*tPP) += sizeof(short);
+    } else
+        *(*tPP)++ = s & 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,
+                       unsigned char * const buf,
+                       unsigned short  const tiff_maxval,
+                       unsigned short  const photometric,
+                       int             const fillorder,
+                       int             const bitspersample,
+                       tuplehash       const cht) {
+/*----------------------------------------------------------------------------
+  This subroutine deals with cases where multiple pixels are packed into
+  a single byte of the Tiff output image, i.e. bits per pixel < 8.
+-----------------------------------------------------------------------------*/
+    int col;
+    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.  
+        */
+    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).
+        */
+    sample s;
+        /* The value of the current sample */
+    unsigned char* tP;
+        /* The address of the byte in the output buffer in which
+           the current pixel goes.
+        */
+    unsigned char byte;
+        /* 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) {
+        if (cht == NULL) {
+            /* It's grayscale */
+            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 {
+            /* It's a colormapped raster */
+            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!.  "
+                         "col=%d  r=%lu g=%lu b=%lu",
+                         col, tuplerow[col][0], tuplerow[col][1],
+                         tuplerow[col][2]);
+            s = (unsigned char) si;
+        }
+        byte |= s << bitshift;
+        if (fillorder == FILLORDER_MSB2LSB)
+            bitshift -= bitspersample;  /* normal case */
+        else
+            bitshift += bitspersample;
+        if (bitshift < 0 || bitshift > 7) {
+            *tP++ = byte;
+            bitshift = firstbitshift;
+            byte = 0;
+        }
+    }
+    if (bitshift != firstbitshift)
+        *tP++ = byte;
+}
+
+
+
+static void
+fillRowOfWholeBytePixels(struct pam *    const pamP,
+                         tuple *         const tuplerow,
+                         unsigned char * const buf,
+                         unsigned short  const photometric,
+                         unsigned short  const tiffMaxval,
+                         unsigned int    const bitsPerSample) {
+
+    unsigned int col;
+    unsigned char * tP;
+    unsigned int planes;
+    
+    if (photometric == PHOTOMETRIC_RGB)
+        planes = pamP->depth;
+    else
+        /* Write only the first plane from the PAM, even if there
+           are more.
+        */
+        planes = 1;
+
+    for (col = 0, tP = buf; col < pamP->width; ++col) {
+        unsigned int plane;
+        for (plane = 0; plane < planes; ++plane) {
+            putSample(tuplerow[col][plane], pamP->maxval,
+                      tiffMaxval, bitsPerSample, &tP);
+            /* Advances tP */
+        }
+    }
+} 
+
+
+
+static void
+writeScanLines(struct pam *   const pamP,
+               TIFF *         const tif, 
+               tuplehash      const cht,
+               unsigned short const tiffMaxval,
+               unsigned short const bitspersample, 
+               unsigned short const photometric,
+               int            const bytesperrow, 
+               int            const fillorder) {
+/*----------------------------------------------------------------------------
+   Write out the raster for the input image described by 'pamP', whose
+   file is positioned to the raster of the image.
+-----------------------------------------------------------------------------*/
+    tuple * tuplerow;  /* malloc'ed */
+    unsigned char * buf; /* malloc'ed */
+    int row;
+
+    /* The man page for TIFFWriteScanLine doesn't tell the format of
+       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
+       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.
+
+       In all cases, the array elements are in order left to right going
+       from low array indices to high array indices.
+    */
+    MALLOCARRAY(buf, bytesperrow);
+
+    if (buf == NULL)
+        pm_error("can't allocate memory for row buffer");
+
+    tuplerow = pnm_allocpamrow(pamP);
+    
+    for (row = 0; row < pamP->height; ++row) {
+        int col;
+
+        pnm_readpamrow(pamP, tuplerow);
+
+        if (cht == NULL) {
+            /* It's a direct, non-colormapped raster */
+
+            if (bitspersample == 8 || bitspersample == 16)
+                fillRowOfWholeBytePixels(pamP, tuplerow, buf, photometric,
+                                         tiffMaxval, bitspersample);
+            else
+                fillRowOfSubBytePixels(pamP, tuplerow, buf,
+                                       tiffMaxval, photometric,
+                                       fillorder, bitspersample, NULL);
+        } else {
+            /* It's a colormapped raster */
+            if (bitspersample == 8) {
+                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!  "
+                                 "col=%d  r=%lu g=%lu b=%lu",
+                                 col, tuplerow[col][0], tuplerow[col][1],
+                                 tuplerow[col][2]);
+                    buf[col] = (unsigned char) si;
+                }
+            } else {
+                fillRowOfSubBytePixels(pamP, tuplerow, buf, 0, 0, fillorder,
+                                       bitspersample, cht);
+            }
+        }
+        if (TIFFWriteScanline(tif, buf, row, 0) < 0)
+            pm_error("failed a scanline write on row %d", row);
+    }
+    pnm_freepamrow(tuplerow);
+    free(buf);
+}
+
+
+
+static void
+analyzeColorsInRgbInput(struct pam *        const pamP,
+                        struct 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.
+-----------------------------------------------------------------------------*/
+    if (cmdline.color && cmdline.truecolor) {
+        *chvP = NULL;
+        *grayscaleP = FALSE;
+    } else {
+        tupletable chv;
+        bool grayscale;
+
+        pm_message("computing colormap...");
+        chv = pnm_computetuplefreqtable2(pamP, NULL, maxcolors,
+                                         pamP->maxval,
+                                         colorsP);
+        if (chv == NULL) {
+            grayscale = FALSE;
+        } else {
+            unsigned int i;
+            pm_message("%u color%s found", 
+                       *colorsP, *colorsP == 1 ? "" : "s");
+            grayscale = TRUE;  /* initial assumption */
+            for (i = 0; i < *colorsP && grayscale; ++i) {
+                if (!pnm_rgbtupleisgray(chv[i]->tuple))
+                    grayscale = FALSE;
+            }
+        }
+        *grayscaleP = grayscale;
+
+        if (grayscale || cmdline.truecolor) {
+            *chvP = NULL;
+            if (chv)
+                pnm_freetupletable(pamP, chv);
+        } else {
+            /* He wants a colormap.  But can we give it to him? */
+            if (chv)
+                *chvP = chv;
+            else {
+                pm_message("Too many colors - "
+                           "proceeding to write a 24-bit RGB file.");
+                pm_message("If you want an 8-bit palette file, "
+                           "try doing a 'pnmquant %d'.",
+                           maxcolors);
+                *chvP = NULL;
+            }
+        }
+    }
+}
+
+
+
+static void
+analyzeColors(struct pam *        const pamP,
+              struct 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. 
+
+   If the colors, combined with command line options 'cmdline', indicate
+   a colormapped TIFF should be generated, return as *chvP the address
+   of a color map (in newly malloc'ed space).  If a colormapped TIFF is
+   not indicated, return *chvP == NULL.
+
+   Return *grayscaleP == true iff the image should be stored as a grayscale
+   image (which means the image is monochromatic and the user doesn't
+   insist on color format).
+
+   Leave the file position undefined.
+-----------------------------------------------------------------------------*/
+    if (pamP->depth >= 3)
+        /* Assume it's a color-capable input image
+           (tuple type RGB or RGB_ALPHA)
+        */
+        analyzeColorsInRgbInput(pamP, cmdline, maxcolors,
+                                chvP, colorsP, grayscaleP);
+    else {
+        *chvP = NULL;
+        *grayscaleP = TRUE;
+    }
+}
+
+
+
+static void
+computeRasterParm(struct pam *     const pamP,
+                  tupletable       const chv, 
+                  int              const colors, 
+                  bool             const grayscale,
+                  int              const compression,
+                  bool             const minisblack,
+                  bool             const miniswhite,
+                  struct sizeset   const indexsizeAllowed,
+                  unsigned short * const samplesperpixelP,
+                  unsigned short * const bitspersampleP,
+                  unsigned short * const photometricP,
+                  int            * const bytesperrowP) {
+/*----------------------------------------------------------------------------
+   Compute the parameters of the raster portion of the TIFF image.
+
+   'minisblack' and 'miniswhite' mean the user requests the corresponding
+   photometric.  Both FALSE means user has no explicit requirement.
+-----------------------------------------------------------------------------*/
+    unsigned short defaultPhotometric;
+    /* The photometric we use if the user specified no preference */
+
+    /* We determine the bits per sample by the maxval, except that if
+       it would be more than 8, we just use 16.  I don't know if bits
+       per sample between 8 and 16 are legal, but they aren't very
+       nice in any case.  If users want them, we should provide an
+       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.  
+    */
+
+    if (pamP->depth == 1 && pamP->maxval == 1) {
+        *samplesperpixelP = 1;
+        *bitspersampleP = 1;
+        if ((compression == COMPRESSION_CCITTFAX3) ||
+            (compression == COMPRESSION_CCITTFAX4))
+            defaultPhotometric = PHOTOMETRIC_MINISWHITE;
+        else
+            defaultPhotometric = PHOTOMETRIC_MINISBLACK;
+    } else {
+        if (chv) {
+            *samplesperpixelP = 1;  /* Pixel is just the one index value */
+            *bitspersampleP = 
+                colors <=   2 && indexsizeAllowed.b1 ? 1 :
+                colors <=   4 && indexsizeAllowed.b2 ? 2 :
+                colors <=  16 && indexsizeAllowed.b4 ? 4 :
+                colors <= 256 && indexsizeAllowed.b8 ? 8 :
+                0;
+            if (*bitspersampleP == 0)
+                pm_error("Your -indexbits option is insufficient for the "
+                         "%d colors in this image.", colors);
+
+            defaultPhotometric = PHOTOMETRIC_PALETTE;
+        } else {
+            if (grayscale) {
+                /* We'll write just the first plane regardless of how many are
+                   in the input PAM.
+                */
+                *samplesperpixelP = 1;
+                *bitspersampleP =
+                    pamP->maxval > 255 ? 16 : pm_maxvaltobits(pamP->maxval);
+                defaultPhotometric = PHOTOMETRIC_MINISBLACK;
+            } else {
+                *samplesperpixelP = pamP->depth;
+                *bitspersampleP = pamP->maxval > 255 ? 16 : 8;
+                defaultPhotometric = PHOTOMETRIC_RGB;
+            }
+        }
+    }
+
+    if (miniswhite)
+        *photometricP = PHOTOMETRIC_MINISWHITE;
+    else if (minisblack)
+        *photometricP = PHOTOMETRIC_MINISBLACK;
+    else
+        *photometricP = defaultPhotometric;
+
+    {
+        unsigned int const samplesPerRow = pamP->width * *samplesperpixelP;
+
+        if (*bitspersampleP < 8) {
+            int samplesperbyte;
+            samplesperbyte = 8 / *bitspersampleP;
+            *bytesperrowP =
+                (samplesPerRow + samplesperbyte-1) / samplesperbyte;
+        } else {
+            if (UINT_MAX / *bitspersampleP < samplesPerRow)
+                pm_error("Too many bytes per row to compute");
+            *bytesperrowP = (samplesPerRow * *bitspersampleP) / 8;
+        }
+    }
+}
+
+
+
+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.
+
+   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.
+-----------------------------------------------------------------------------*/
+    int rc;
+
+    /* We'd like to get the current position and leave the file positioned
+       where we found it.  But that entails the mess with some systems
+       having 32 bit file offsets and some having 64 bit file offsets.
+    */
+
+    /* Some files can seek ahead, but not back.  So we test for the
+       more difficult backward seek.
+    */
+    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));
+}
+
+
+
+static void
+createTiffGenerator(int          const ofd, 
+                    const char * const outFileName,
+                    bool         const append,
+                    TIFF **      const tifPP) {
+
+    const char * option;
+
+    /* Before 10.12 (November 2002), we set O_NONBLOCK here:
+
+       fcntl( 1, F_SETFL, O_NONBLOCK ) ; 
+   
+       I have no idea why.  The comment attached said, 
+
+         acooke dec99 - otherwise blocks on read inside 
+         next line (Linux i386) 
+    */
+
+    validateSeekableOutputFile(ofd, outFileName);
+
+    if (append)
+        option = "a";
+    else
+        option = "w";
+
+    *tifPP = TIFFFdOpen(ofd, outFileName, option);
+    if (*tifPP == NULL)
+        pm_error("error opening standard output as TIFF file.  "
+                 "TIFFFdOpen() failed.");
+}
+
+
+
+static void
+destroyTiffGenerator(TIFF * const tifP) {
+
+    TIFFFlushData(tifP);
+    TIFFClose(tifP);
+}
+
+
+
+static void
+createTiffColorMap(struct pam *       const pamP,
+                   unsigned int       const bitspersample,
+                   tupletable         const chv,
+                   unsigned int       const colors,
+                   unsigned short *** const tiffColorMapP) {
+
+    unsigned int const colorMapSize = 1 << bitspersample;
+    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) {
+            if (i < colors)
+                tiffColorMap[plane][i] =
+                    chv[i]->tuple[plane] * 65535L / pamP->maxval;
+            else
+                tiffColorMap[plane][i] = 0;
+        }
+    }
+    *tiffColorMapP = tiffColorMap;
+}
+        
+
+
+static void
+destroyTiffColorMap(struct pam *      const pamP,
+                    unsigned short ** const tiffColorMap) {
+
+    unsigned int plane;
+
+    for (plane = 0; plane < pamP->depth; ++plane)
+        free(tiffColorMap[plane]);
+
+    free(tiffColorMap);
+}
+
+
+
+static void
+setTagListFields(const struct optNameValue * const taglist,
+                 TIFF *                      const tifP) {
+
+    unsigned int i;
+
+    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);
+    }
+}
+
+
+
+static void
+setTiffFields(TIFF *              const tifP,
+              struct cmdlineInfo  const cmdline,
+              struct pam *        const pamP,
+              unsigned short      const bitspersample,
+              unsigned short      const photometric,
+              unsigned short      const samplesperpixel,
+              unsigned short **   const tiffColorMap,
+              const char *        const inputFileDescription,
+              struct optNameValue const taglist[]) {
+
+    /* TODO: It would be cleaner to set all tags in a tag list and
+       then call setTagListFields() on that list.  That way,
+       TIFFSetField() is in only one place and all tags get set the
+       same way and we don't have this icky setting of default and
+       then resetting with user choice (e.g. DOCUMENTNAME).
+    */
+
+    /* Set TIFF parameters. */
+    TIFFSetField(tifP, TIFFTAG_IMAGEWIDTH,    pamP->width);
+    TIFFSetField(tifP, TIFFTAG_IMAGELENGTH,   pamP->height);
+    TIFFSetField(tifP, TIFFTAG_BITSPERSAMPLE, bitspersample);
+    if (cmdline.compression != -1)
+        TIFFSetField(tifP, TIFFTAG_COMPRESSION, cmdline.compression);
+    if (cmdline.compression == COMPRESSION_CCITTFAX3 && cmdline.g3options != 0)
+        TIFFSetField( tifP, TIFFTAG_GROUP3OPTIONS, cmdline.g3options);
+    if (cmdline.compression == COMPRESSION_LZW && cmdline.predictor != -1)
+        TIFFSetField( tifP, TIFFTAG_PREDICTOR, cmdline.predictor);
+    TIFFSetField(tifP, TIFFTAG_PHOTOMETRIC, photometric);
+    if (cmdline.fillorder != -1)
+        TIFFSetField(tifP, TIFFTAG_FILLORDER, cmdline.fillorder);
+    TIFFSetField(tifP, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
+    if (cmdline.rowsperstrip != -1)
+        TIFFSetField(tifP, TIFFTAG_ROWSPERSTRIP, cmdline.rowsperstrip);
+    else
+        TIFFSetField(tifP, TIFFTAG_ROWSPERSTRIP,
+                     TIFFDefaultStripSize(tifP, 0));
+    if (cmdline.xresolution != -1 ||
+        cmdline.yresolution != -1 ||
+        cmdline.resolutionUnit != -1) {
+        TIFFSetField(tifP, TIFFTAG_RESOLUTIONUNIT,
+                     cmdline.resolutionUnit != -1 ?
+                     cmdline.resolutionUnit : RESUNIT_NONE);
+    }
+    if (cmdline.xresolution > 0)
+        TIFFSetField(tifP, TIFFTAG_XRESOLUTION, cmdline.xresolution);
+    if ( cmdline.yresolution > 0)
+        TIFFSetField(tifP, TIFFTAG_YRESOLUTION, cmdline.yresolution);
+    TIFFSetField(tifP, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+
+    if (tiffColorMap)
+        TIFFSetField(tifP, TIFFTAG_COLORMAP,
+                     tiffColorMap[PAM_RED_PLANE],
+                     tiffColorMap[PAM_GRN_PLANE],
+                     tiffColorMap[PAM_BLU_PLANE]);
+
+
+    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.
+    */
+    setTagListFields(taglist, tifP);
+}
+
+
+
+static void
+convertImage(FILE *             const ifP,
+             TIFF *             const tifP,
+             const char *       const inputFileDescription,
+             struct cmdlineInfo const cmdline) {
+
+    tupletable chv;
+    tuplehash cht;
+    unsigned short ** tiffColorMap;  /* malloc'ed */
+    struct pam pam;
+    unsigned int colors;
+    bool grayscale;
+    unsigned short photometric;
+    unsigned short samplesperpixel;
+    unsigned short bitspersample;
+    unsigned short tiff_maxval;
+    /* This is the maxval of the samples in the tiff file.  It is 
+       determined solely by the bits per sample ('bitspersample').
+       */
+    int bytesperrow;
+    pm_filepos rasterPos;
+
+    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+
+    pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
+
+    analyzeColors(&pam, cmdline, MAXCOLORS, &chv, &colors, &grayscale);
+
+    /* Go back to beginning of raster */
+    pm_seek2(ifP, &rasterPos, sizeof(rasterPos));  
+
+    /* Figure out TIFF parameters. */
+
+    computeRasterParm(&pam, chv, colors, grayscale, 
+                      cmdline.compression,
+                      cmdline.minisblack, cmdline.miniswhite,
+                      cmdline.indexsizeAllowed,
+                      &samplesperpixel, &bitspersample, &photometric,
+                      &bytesperrow);
+
+    tiff_maxval = pm_bitstomaxval(bitspersample);
+
+    if (!chv) {
+        cht = NULL;
+        tiffColorMap = NULL;
+    } else {
+        createTiffColorMap(&pam, bitspersample, chv, colors, &tiffColorMap);
+
+        /* Convert color vector to color hash table, for fast lookup. */
+        cht = pnm_computetupletablehash(&pam, chv, colors);
+        pnm_freetupletable(&pam, chv);
+    }
+
+    setTiffFields(tifP, cmdline, &pam, bitspersample, photometric,
+                  samplesperpixel, tiffColorMap, inputFileDescription,
+                  cmdline.taglist);
+
+    writeScanLines(&pam, tifP, cht,
+                   tiff_maxval, bitspersample, photometric, bytesperrow, 
+                   cmdline.fillorder);
+
+    if (tiffColorMap)
+        destroyTiffColorMap(&pam, tiffColorMap);
+}
+
+
+
+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.
+-----------------------------------------------------------------------------*/
+    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.");
+    }
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+    struct cmdlineInfo cmdline;
+    const char * inputFileDescription;
+    FILE* ifP;
+    TIFF* tifP;
+    bool eof;
+    unsigned int imageSeq;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+    
+    ifP = pm_openr_seekable(cmdline.input_filespec);
+
+    if (streq(cmdline.input_filespec, "-"))
+        inputFileDescription = "Standard Input";
+    else 
+        inputFileDescription = cmdline.input_filespec;
+
+    if (cmdline.append)
+        validateReadableStdout();
+
+    createTiffGenerator(STDOUT_FILENO, "Standard Output", cmdline.append,
+                        &tifP);
+
+    eof = FALSE;  /* initial assumption */
+    imageSeq = 0;
+
+    while (!eof) {
+        bool success;
+
+        if (cmdline.verbose)
+            pm_message("Converting Image %u", imageSeq);
+
+        pnm_nextimage(ifP, &eof);
+
+        if (!eof) {
+            if (imageSeq > 0)
+                validateReadableStdout();
+
+            convertImage(ifP, tifP, inputFileDescription, cmdline);
+            
+            success = TIFFWriteDirectory(tifP);
+            if (!success)
+                pm_error("Unable to write TIFF image %u to file.  "
+                         "tifWriteDirectory() failed.", imageSeq);
+            ++imageSeq;
+        }
+    }
+
+    destroyTiffGenerator(tifP);
+    pm_close(ifP);
+
+    return 0;
+}
diff --git a/converter/other/pamtouil.c b/converter/other/pamtouil.c
new file mode 100644
index 00000000..b9ddc749
--- /dev/null
+++ b/converter/other/pamtouil.c
@@ -0,0 +1,438 @@
+/* pamtouil.c - convert PBM, PGM, PPM, or PPM+alpha to Motif UIL icon file
+**
+** Bryan Henderson converted ppmtouil to pamtouil on 2002.05.04.
+**
+** Jef Poskanzer derived pamtouil from ppmtoxpm, which is
+** Copyright (C) 1990 by Mark W. Snitily.
+**
+** 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.
+*/
+
+#define _BSD_SOURCE  /* Make sure string.h contains strdup() */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+#include <ctype.h>
+#include <string.h>
+#include "pam.h"
+#include "pammap.h"
+#include "colorname.h"
+#include "shhopt.h"
+#include "nstring.h"
+
+/* Max number of colors allowed in ppm input. */
+#define MAXCOLORS 256
+
+/* Lower bound and upper bound of character-pixels printed in UIL output. */
+#define LOW_CHAR '`'
+#define HIGH_CHAR '~'
+
+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 */
+    char *outname;         /* output filename, less "_icon" */
+    unsigned int verbose;
+};
+
+
+
+typedef struct {    /* character-pixel mapping */
+    const char* cixel;    /* character string printed for pixel */
+    const char* rgbname;  /* ascii rgb color, either mnemonic or #rgb value */
+    const char* uilname;  /* same, with spaces replaced by underbars */
+    bool        transparent;
+} cixel_map;
+
+
+
+static void
+parseCommandLine(int argc, 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.  The outname array is in newly
+   malloc'ed storage.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def = malloc( 100*sizeof( optEntry ) );
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    unsigned int outnameSpec;
+    const char *outnameOpt;
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "name",       OPT_STRING, &outnameOpt, 
+            &outnameSpec,       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 may have parms that are negative numbers */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc-1 == 0)
+        cmdlineP->inputFilespec = "-";  /* stdin */
+    else if (argc-1 == 1)
+        cmdlineP->inputFilespec = argv[1];
+    else 
+        pm_error("Too many arguments (%d).  "
+                 "Only need one: the input filespec", argc-1);
+
+    if (outnameSpec) {
+        char * barPos;
+
+        cmdlineP->outname = strdup(outnameOpt);
+
+        /* Remove trailing "_icon" */
+        barPos = strrchr(cmdlineP->outname, '_');
+        if (STREQ(barPos, "_icon")) 
+            *barPos = '\0';
+    } else {
+        if (STREQ(cmdlineP->inputFilespec, "-"))
+            cmdlineP->outname = strdup("noname");
+        else {
+            char * dotPos;
+
+            cmdlineP->outname = strdup(cmdlineP->inputFilespec);
+
+            /* remove extension */
+            dotPos = strrchr(cmdlineP->outname, '.');
+            if (dotPos)
+                *dotPos = '\0';
+        }
+    }
+}
+
+
+
+
+static char*
+genNumstr(int  const number, 
+          int  const base, 
+          char const low_char, 
+          int  const digits ) {
+/*----------------------------------------------------------------------------
+  Generate a string 'digits' characters long in newly malloc'ed
+  storage that is the number 'number' displayed in base 'base'.  Fill it on
+  the left with zero digits and truncate on the left if it doesn't fit.
+
+  Use the characters 'low_char' to 'low_char' + 'base' to represent the
+  digits 0 to 'base'. 
+-----------------------------------------------------------------------------*/
+    char* str;
+    char* p;
+    int d;
+    int i;
+
+    /* Allocate memory for printed number.  Abort if error. */
+    str = (char*) malloc(digits + 1);
+    if (str == NULL)
+        pm_error("out of memory allocating number string");
+
+    /* Generate characters starting with least significant digit. */
+    i = number;
+    p = str + digits;
+    *p-- = '\0';    /* nul terminate string */
+    while (p >= str) {
+        d = i % base;
+        i /= base;
+        *p-- = low_char + d;
+    }
+    return str;
+}
+
+
+
+static const char * 
+uilName(const char * const rgbname, bool const transparent) {
+/*----------------------------------------------------------------------------
+   Return a string in newly malloc'ed storage which is an appropriate 
+   color name for the UIL palette.  It is the same as the rgb name,
+   except that blanks are replaced by underscores, and if 'transparent'
+   is true, it is "background color".  The latter is a strange name of
+   a color, but it works pretty much the same in the UIL colortable() value.
+-----------------------------------------------------------------------------*/
+    char * output;
+
+    if (transparent)
+        output = strdup("background color");
+    else {
+        int i;
+
+        output = malloc(strlen(rgbname) + 5 + 1);
+        if (output == NULL)
+            pm_error( "out of memory allocating color name" );
+        
+        for (i = 0; i < strlen(rgbname); ++i) {
+            if (rgbname[i] == ' ')
+                output[i] = '_';
+            else
+                output[i] = rgbname[i];
+        }
+        output[strlen(rgbname)] = '\0';
+    }
+
+    return output;
+}
+
+
+
+static void
+genCmap(struct pam *   const pamP,
+        tupletable     const chv, 
+        unsigned int   const ncolors, 
+        cixel_map            cmap[MAXCOLORS], 
+        unsigned int * const charsppP,
+        bool           const verbose) {
+
+    unsigned int const base = (int) HIGH_CHAR - (int) LOW_CHAR + 1;
+    char* colorname;
+    unsigned int colorIndex;
+    {
+        /* Figure out how many characters per pixel we'll be using.
+        ** Don't want to be forced to link with libm.a, so using a
+        ** division loop rather than a log function.  
+        */
+        unsigned int i;
+        for (*charsppP = 0, i = ncolors; i > 0; ++(*charsppP))
+            i /= base;
+    }
+
+    /* Generate the character-pixel string and the rgb name for each colormap
+    ** entry.
+    */
+    for (colorIndex = 0; colorIndex < ncolors; ++colorIndex) {
+        bool nameAlreadyInCmap;
+        unsigned int indexOfName;
+        bool transparent;
+        int j;
+        
+        if (pamP->depth-1 < PAM_TRN_PLANE)
+            transparent = FALSE;
+        else 
+            transparent = 
+                chv[colorIndex]->tuple[PAM_TRN_PLANE] < pamP->maxval/2;
+
+        /* Generate color name string. */
+        colorname = pam_colorname(pamP, chv[colorIndex]->tuple, 
+                                  PAM_COLORNAME_ENGLISH);
+
+        /* We may have already assigned a character code to this color
+           name/transparency because the same color name can apply to
+           two different colors because we said we wanted the closest
+           matching color that has an English name, and we recognize
+           only one transparent color.  If that's the case, we just
+           make a cross-reference.  
+        */
+        nameAlreadyInCmap = FALSE;   /* initial assumption */
+        for (j = 0; j < colorIndex; ++j) {
+            if (cmap[j].rgbname != NULL && 
+                STREQ(colorname, cmap[j].rgbname) &&
+                cmap[j].transparent == transparent) {
+                nameAlreadyInCmap = TRUE;
+                indexOfName = j;
+            }
+        }
+        if (nameAlreadyInCmap) {
+            /* Make the entry a cross-reference to the earlier entry */
+            cmap[colorIndex].uilname = NULL;
+            cmap[colorIndex].rgbname = NULL;
+            cmap[colorIndex].cixel = cmap[indexOfName].cixel;
+        } else {
+            cmap[colorIndex].uilname = uilName(colorname, transparent);
+            cmap[colorIndex].rgbname = strdup(colorname);
+            if (cmap[colorIndex].rgbname == NULL)
+                pm_error( "out of memory allocating color name" );
+            
+            cmap[colorIndex].transparent = transparent;
+            
+            /* Generate color value characters. */
+            cmap[colorIndex].cixel = 
+                genNumstr(colorIndex, base, LOW_CHAR, *charsppP);
+            if (verbose)
+                pm_message("Adding color '%s' %s = '%s' to UIL colormap",
+                           cmap[colorIndex].rgbname, 
+                           cmap[colorIndex].transparent ? "TRANS" : "OPAQUE",
+                           cmap[colorIndex].cixel);
+        }
+    }
+}
+
+
+
+static void
+writeUilHeader(const char * const outname) {
+    /* Write out the UIL header. */
+    printf( "module %s\n", outname );
+    printf( "version = 'V1.0'\n" );
+    printf( "names = case_sensitive\n" );
+    printf( "include file 'XmAppl.uil';\n" );
+}
+
+
+
+static void
+writeColormap(const char * const outname, 
+              cixel_map          cmap[MAXCOLORS], 
+              unsigned int const ncolors) {
+
+    {
+        int i;
+
+        /* Write out the colors. */
+        printf("\n");
+        printf("value\n");
+        for (i = 0; i < ncolors; ++i)
+            if (cmap[i].uilname != NULL && !cmap[i].transparent) 
+                printf("    %s : color( '%s' );\n", 
+                       cmap[i].uilname, cmap[i].rgbname );
+    }
+    {
+        /* Write out the ascii colormap. */
+
+        int i;
+        bool printedOne;
+
+        printf("\n");
+        printf("value\n");
+        printf("  %s_rgb : color_table (\n", outname);
+        printedOne = FALSE; 
+        for (i = 0; i < ncolors; ++i)
+            if (cmap[i].uilname != NULL) {
+                if (printedOne)
+                    printf(",\n");
+                printf("    %s = '%s'", cmap[i].uilname, cmap[i].cixel);
+                printedOne = TRUE;
+            }     
+        printf("\n");
+        printf("    );\n");
+    }
+}
+
+
+
+static void
+writeRaster(struct pam *  const pamP, 
+            tuple **      const tuples,
+            const char *  const outname,
+            cixel_map           cmap[MAXCOLORS], 
+            unsigned int  const ncolors,
+            tuplehash     const cht, 
+            unsigned int  const charspp) {
+    
+    int row;
+    /* Write out the ascii character-pixel image. */
+
+    printf("\n");
+    printf("%s_icon : exported icon( color_table = %s_rgb,\n",
+           outname, outname);
+    for (row = 0; row < pamP->height; ++row) {
+        int col;
+
+        printf("    '");
+        for (col = 0; col < pamP->width; ++col) {
+            int colorIndex;
+            int found;
+            if ((col * charspp) % 70 == 0 && col > 0)
+                printf( "\\\n" );       /* line continuation */
+            pnm_lookuptuple(pamP, cht, tuples[row][col], &found, &colorIndex);
+            if (!found)
+                pm_error("INTERNAL ERROR: color not found in colormap");
+            printf("%s", cmap[colorIndex].cixel);
+        }
+        if (row != pamP->height - 1)
+            printf("',\n");
+        else
+            printf("'\n"); 
+    }
+    printf(");\n");
+    printf("\n");
+}
+
+
+static void
+freeString(const char * const s) {
+/*----------------------------------------------------------------------------
+   This is just free(), but with type checking for const char *.
+-----------------------------------------------------------------------------*/
+    free((void *)s);
+}
+
+
+
+static void
+freeCmap(cixel_map cmap[], unsigned int const ncolors) {
+
+    int i;
+
+    for (i = 0; i < ncolors; ++i) {
+        cixel_map const cmapEntry = cmap[i];
+        if (cmapEntry.uilname)
+            freeString(cmapEntry.uilname);
+        if (cmapEntry.rgbname)
+            freeString(cmapEntry.uilname);
+    }
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    struct pam pam;   /* Input PAM image */
+    FILE* ifP;
+    tuple** tuples;
+    unsigned int ncolors;
+    tuplehash cht;
+    tupletable chv;
+    cixel_map cmap[MAXCOLORS];
+    unsigned int charspp;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+    tuples = pnm_readpam(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+    pm_close(ifP);
+
+    pm_message("computing colormap...");
+
+    chv = pnm_computetuplefreqtable(&pam, tuples, MAXCOLORS, &ncolors);
+    if (chv == NULL)
+        pm_error("too many colors - try doing a 'pnmquant %u'", MAXCOLORS);
+    if (cmdline.verbose)
+        pm_message("%u colors found", ncolors);
+
+    /* Make a hash table for fast color lookup. */
+    cht = pnm_computetupletablehash(&pam, chv, ncolors);
+
+    /* Now generate the character-pixel colormap table. */
+    pm_message("looking up color names, assigning character codes...");
+    genCmap(&pam, chv, ncolors, cmap, &charspp, cmdline.verbose);
+
+    pm_message("generating UIL...");
+    writeUilHeader(cmdline.outname);
+
+    writeColormap(cmdline.outname, cmap, ncolors);
+
+    writeRaster(&pam, tuples, cmdline.outname, cmap, ncolors, cht, charspp);
+
+    printf("end module;\n");
+
+    free(cmdline.outname);
+    freeCmap(cmap, ncolors);
+
+    return 0;
+}
diff --git a/converter/other/pamtoxvmini.c b/converter/other/pamtoxvmini.c
new file mode 100644
index 00000000..dc56e912
--- /dev/null
+++ b/converter/other/pamtoxvmini.c
@@ -0,0 +1,250 @@
+/*=============================================================================
+                                    pamtoxvmini
+===============================================================================
+   Convert Netpbm image to XV mini thumbnail.
+
+   Written by Bryan Henderson in April 2006 and contributed to the public
+   domain.
+=============================================================================*/
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include "pm_c_util.h"
+#include "nstring.h"
+#include "pam.h"
+#include "pammap.h"
+
+typedef struct xvPalette {
+    unsigned int red[256];
+    unsigned int grn[256];
+    unsigned int blu[256];
+} xvPalette;
+
+
+struct cmdlineInfo {
+    const char * inputFileName;
+};
+
+
+
+static void
+parseCommandLine(int const argc,
+                 char *    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: %u.  Only argument is optional "
+                     "input file name.", argc-1);
+    }
+}
+
+
+
+static void
+makeXvPalette(xvPalette * const xvPaletteP) {
+
+    unsigned int paletteIndex;
+    unsigned int r;
+
+    paletteIndex = 0;
+
+    for (r = 0; r < 8; ++r) {
+        unsigned int g;
+        for (g = 0; g < 8; ++g) {
+            unsigned int b;
+            for (b = 0; b < 4; ++b) {
+                xvPaletteP->red[paletteIndex] = (r*255)/7;
+                xvPaletteP->grn[paletteIndex] = (g*255)/7;
+                xvPaletteP->blu[paletteIndex] = (b*255)/3;
+                ++paletteIndex;
+            }
+        }
+    }
+
+}
+
+
+
+static void
+writeXvHeader(FILE *       const ofP,
+              unsigned int const cols,
+              unsigned int const rows,
+              unsigned int const maxval) {
+           
+    fprintf(ofP, "P7 332\n");
+
+    fprintf(ofP, "# Created by Pamtoxvmini\n");
+    fprintf(ofP, "#END_OF_COMMENTS\n");
+
+    fprintf(ofP, "%u %u %u\n", cols, rows, maxval);
+}
+
+
+
+static void
+findClosestColor(struct pam *      const pamP,
+                 tuple             const tuple, 
+                 const xvPalette * const xvPaletteP,
+                 unsigned int *    const paletteIndexP) {
+/*----------------------------------------------------------------------------
+   Find the color in the palette *xvPaletteP that is closest to the color
+   'tuple' and return its index in the palette.
+-----------------------------------------------------------------------------*/
+    unsigned int paletteIndex;
+    unsigned int bestPaletteIndex;
+    unsigned int bestDistanceSoFar;
+
+    /* An entry condition is that the tuple have the same form as the
+       colors in the XV palette:
+    */
+    assert(pamP->depth >= 3);
+    assert(pamP->maxval = 255);
+
+    bestPaletteIndex = 0;
+    bestDistanceSoFar = UINT_MAX;
+
+    for (paletteIndex = 0; paletteIndex < 256; ++paletteIndex) {
+        unsigned int const tupleRed = tuple[PAM_RED_PLANE];
+        unsigned int const tupleGrn = tuple[PAM_GRN_PLANE];
+        unsigned int const tupleBlu = tuple[PAM_BLU_PLANE];
+        
+        unsigned int const paletteRed = xvPaletteP->red[paletteIndex];
+        unsigned int const paletteGrn = xvPaletteP->grn[paletteIndex];
+        unsigned int const paletteBlu = xvPaletteP->blu[paletteIndex];
+
+        unsigned int const distance = 
+            SQR((int)tupleRed - (int)paletteRed) +
+            SQR((int)tupleGrn - (int)paletteGrn) +
+            SQR((int)tupleBlu - (int)paletteBlu);
+
+        if (distance < bestDistanceSoFar) {
+            bestDistanceSoFar = distance;
+            bestPaletteIndex = paletteIndex;
+        }
+    }
+    *paletteIndexP = bestPaletteIndex;
+}
+
+
+
+static void
+getPaletteIndexThroughCache(struct pam *      const pamP,
+                            tuple             const tuple,
+                            const xvPalette * const xvPaletteP,
+                            tuplehash         const paletteHash,
+                            unsigned int *    const paletteIndexP) {
+/*----------------------------------------------------------------------------
+   Return as *paletteIndexP the index into the palette *xvPaletteP of
+   the color that most closely resembles the color 'tuple'.
+
+   Use the hash table *paletteIndexP as a cache to speed up the search.
+   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 paletteIndex;
+
+    pnm_lookuptuple(pamP, paletteHash, tuple, &found, &paletteIndex);
+    if (found)
+        *paletteIndexP = paletteIndex;
+    else {
+        bool fits;
+        findClosestColor(pamP, tuple, xvPaletteP, paletteIndexP);
+        
+        pnm_addtotuplehash(pamP, paletteHash, tuple, *paletteIndexP, &fits);
+        
+        if (!fits)
+            pm_error("Can't get memory for palette hash.");
+    }
+}
+
+    
+
+static void
+writeXvRaster(struct pam * const pamP,
+              xvPalette *  const xvPaletteP,
+              FILE *       const ofP) {
+/*----------------------------------------------------------------------------
+   Write out the XV image, from the Netpbm input file ifP, which is
+   positioned to the raster.
+
+   The XV raster contains palette indices into the palette *xvPaletteP.
+
+   If there is any color in the image which is not in the palette, we
+   fail the program.  We really should use the closest color in the palette
+   instead.
+-----------------------------------------------------------------------------*/
+    tuplehash paletteHash;
+    tuple * tuplerow;
+    unsigned int row;
+    unsigned char * xvrow;
+
+    paletteHash = pnm_createtuplehash();
+
+    tuplerow = pnm_allocpamrow(pamP);
+    xvrow = (unsigned char*)pm_allocrow(pamP->width, 1);
+
+    for (row = 0; row < pamP->height; ++row) {
+        unsigned int col;
+
+        pnm_readpamrow(pamP, tuplerow);
+        pnm_scaletuplerow(pamP, tuplerow, tuplerow, 255);
+        pnm_makerowrgb(pamP, tuplerow);
+
+        for (col = 0; col < pamP->width; ++col) {
+            unsigned int paletteIndex;
+
+            getPaletteIndexThroughCache(pamP, tuplerow[col], xvPaletteP,
+                                        paletteHash, &paletteIndex);
+
+            assert(paletteIndex < 256);
+
+            xvrow[col] = paletteIndex;
+        }
+        fwrite(xvrow, 1, pamP->width, ofP);
+    }
+
+    pm_freerow((char*)xvrow);
+    pnm_freepamrow(pamP);
+
+    pnm_destroytuplehash(paletteHash);
+}
+
+
+
+int 
+main(int    argc,
+     char * argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    struct pam pam;
+    xvPalette xvPalette;
+ 
+    ppm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    makeXvPalette(&xvPalette);
+
+    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(allocation_depth));
+
+    pnm_setminallocationdepth(&pam, 3);
+
+    writeXvHeader(stdout, pam.width, pam.height, pam.maxval);
+    
+    writeXvRaster(&pam, &xvPalette, stdout);
+
+    pm_close(ifP);
+
+    return 0;
+}
diff --git a/converter/other/pbmtopgm.c b/converter/other/pbmtopgm.c
new file mode 100644
index 00000000..69b20fb2
--- /dev/null
+++ b/converter/other/pbmtopgm.c
@@ -0,0 +1,80 @@
+/* pbmtopgm.c - convert PBM to PGM by totalling pixels over sample area
+ * AJCD 12/12/90
+ */
+
+#include <stdio.h>
+
+#include "pm_c_util.h"
+#include "pgm.h"
+
+int
+main(int argc, char *argv[]) {
+
+    gray *outrow, maxval;
+    int right, left, down, up;
+    bit **inbits;
+    int rows, cols;
+    FILE *ifd;
+    int row;
+    int width, height;
+    const char * const usage = "<w> <h> [pbmfile]";
+   
+
+    pgm_init( &argc, argv );
+
+    if (argc > 4 || argc < 3)
+        pm_usage(usage);
+
+    width = atoi(argv[1]);
+    height = atoi(argv[2]);
+    if (width < 1 || height < 1)
+        pm_error("width and height must be > 0");
+    left=width/2; right=width-left;
+    up=width/2; down=height-up;
+
+    if (argc == 4)
+        ifd = pm_openr(argv[3]);
+    else
+        ifd = stdin ;
+
+    inbits = pbm_readpbm(ifd, &cols, &rows) ;
+    
+    if (width > cols)
+        pm_error("You specified a sample width (%u columns) which is greater "
+                 "than the image width (%u columns)", height, rows);
+    if (height > rows)
+        pm_error("You specified a sample height (%u rows) which is greater "
+                 "than the image height (%u rows)", height, rows);
+
+    outrow = pgm_allocrow(cols) ;
+    maxval = MIN(PGM_OVERALLMAXVAL, width*height);
+    pgm_writepgminit(stdout, cols, rows, maxval, 0) ;
+
+    for (row = 0; row < rows; row++) {
+        int const t = (row > up) ? (row-up) : 0;
+        int const b = (row+down < rows) ? (row+down) : rows;
+        int const onv = height - (t-row+up) - (row+down-b);
+        unsigned int col;
+        for (col = 0; col < cols; col++) {
+            int const l = (col > left) ? (col-left) : 0;
+            int const r = (col+right < cols) ? (col+right) : cols;
+            int const onh = width - (l-col+left) - (col+right-r);
+            int value;
+            int x;
+
+            value = 0;  /* initial value */
+
+            for (x = l; x < r; ++x) {
+                int y;
+                for (y = t; y < b; ++y)
+                    if (inbits[y][x] == PBM_WHITE) 
+                        ++value;
+            }
+            outrow[col] = maxval*value/(onh*onv);
+        }
+        pgm_writepgmrow(stdout, outrow, cols, maxval, 0) ;
+    }
+    pm_close(ifd);
+
+    return 0;
+}
diff --git a/converter/other/pclxl.h b/converter/other/pclxl.h
new file mode 100644
index 00000000..b1d1c043
--- /dev/null
+++ b/converter/other/pclxl.h
@@ -0,0 +1,390 @@
+#ifndef PCLXL_H_INCLUDED
+#define PCLXL_H_INCLUDED
+
+/* This file defines elements of Hewlett Packard's PCL-XL printer
+   control language (fka PCL-6)
+*/
+
+enum ArcDirection {
+    eClockWise = 0,
+    eCounterClockWise = 1
+};
+
+enum CharSubModeArray {
+    eNoSubstitution = 0,
+    eVerticalSubstitution = 1
+};
+
+enum ClipRegion {
+    eInterior = 0,
+    eExterior = 1
+};
+
+enum ColorDepth {
+    e1Bit = 0,
+    e4Bit = 1,
+    e8Bit = 2
+};
+
+enum ColrMapping {
+    eDirectPixel = 0,
+    eIndexedPixel = 1
+};
+
+enum Colorspace {
+    eGray = 1,
+    eRGB = 2
+};
+
+enum Compression {
+    eNoCompression = 0,
+    eRLECompression = 1,
+    eJPEGCompression = 2
+};
+
+enum DataOrg {
+    eBinaryHighByteFirst = 0,
+    eBinaryLowByteFirst = 1
+};
+
+enum DataSource {
+    eDefault = 0
+};
+
+enum DataType {
+    eUByte = 0,
+    eSByte = 1,
+    eUint16 = 2,
+    eSint16 = 3
+};
+
+enum DitherMatrix {  
+    eDeviceBest = 0
+}; 
+
+
+enum DuplexPageMode {
+    eDuplexHorizontalBinding = 0,
+    eDuplexVerticalBinding = 1
+};
+
+enum DuplexPageSide {
+    eFrontMediaSide = 0,
+    eBackMediaSide = 1
+};
+
+enum ErrorReport {
+    eNoReporting = 0,
+    eBackChannel = 1,
+    eErrorPage = 2,
+    eBackChAndErrPage = 3,
+    eNWBackChannel = 4 ,
+    eNWErrorPage = 5,
+    eNWBackChAndErrPage = 6
+};
+
+enum FillMode {
+    eNonZeroWinding = 0,
+    eEvenOdd = 1
+};
+
+enum LineCap {
+    eButtCap = 0,
+    eRoundCap = 1,
+    eSquareCap = 2,
+    eTriangleCap = 3
+};
+
+enum LineJoin {
+    eMiterJoin = 0,
+    eRoundJoin = 1,
+    eBevelJoin = 2,
+    eNoJoin = 3
+};
+
+enum Measure {
+    eInch = 0,
+    eMillimeter = 1,
+    eTenthsOfAMillimeter = 2
+};
+
+enum MediaSource {
+    eDefaultSource = 0,
+    eAutoSelect = 1,
+    eManualFeed = 2,
+    eMultiPurposeTray = 3,
+    eUpperCassette = 4,
+    eLowerCassette = 5,
+    eEnvelopeTray = 6,
+    eThirdCassette = 7
+};
+
+enum MediaDestination {
+    eDefaultDestination = 0,
+    eFaceDownBin = 1,
+    eFaceUpBin = 2,
+    eJobOffsetBin = 3
+};
+
+enum Orientation {
+    ePortraitOrientation = 0,
+    eLandscapeOrientation = 1,
+    eReversePortrait = 2,
+    eReverseLandscape = 3
+};
+
+enum PatternPersistence {
+    eTempPattern = 0,
+    ePagePattern = 1,
+    eSessionPattern = 2
+};
+
+enum SimplexPageMode {
+    eSimplexFrontSide = 0
+};
+
+enum TxMode {
+    eOpaque = 0,
+    eTransparent = 1
+};
+
+enum WritingMode{
+    eHorizontal = 0,
+    eVertical = 1
+};
+
+enum Attribute {
+    aPaletteDepth        =   2,
+    aColorSpace          =   3,
+    aNullBrush           =   4,
+    aNullPen             =   5,
+    aPaletteData         =   6,
+    aPatternSelectID     =   8,
+    aGrayLevel           =   9,
+    aRGBColor            =  11,
+    aPatternOrigin       =  12,
+    aNewDestinationSize  =  13,
+    aPrimaryArray        =  14,
+    aPrimaryDepth        =  15,
+    aDeviceMatrix        =  33,
+    aDitherMatrixDataType=  34,
+    aDitherOrigin        =  35,
+    aMediaDestination    =  36,
+    aMediaSize           =  37,
+    aMediaSource         =  38,
+    aMediaType           =  39,
+    aOrientation         =  40,
+    aPageAngle           =  41,
+    aPageOrigin          =  42,
+    aPageScale           =  43,
+    aROP3                =  44,
+    aTxMode              =  45,
+    aCustomMediaSize     =  47,
+    aCustomMediaUnits    =  48,
+    aPageCopies          =  49,
+    aDitherMatrixSize    =  50,
+    aDitherMatrixDepth   =  51,
+    aSimplexPageMode     =  52,
+    aDuplexPageMode      =  53,
+    aDuplexPageSide      =  54,
+    aArcDirection        =  65,
+    aBoundingBox         =  66,
+    aDashOffset          =  67,
+    aEllipseDimension    =  68,
+    aEndPoint            =  69,
+    aFillMode            =  70,
+    aLineCapStyle        =  71,
+    aLineJoinStyle       =  72,
+    aMiterLength         =  73,
+    aLineDashStyle       =  74,
+    aPenWidth            =  75,
+    aPoint               =  76,
+    aNumberOfPoints      =  77,
+    aSolidLine           =  78,
+    aStartPoint          =  79,
+    aPointType           =  80,
+    aControlPoint1       =  81,
+    aControlPoint2       =  82,
+    aClipRegion          =  83,
+    aClipMode            =  84,
+    aColorDepth          =  98,
+    aBlockHeight         =  99,
+    aColorMapping        = 100,
+    aCompressMode        = 101,
+    aDestinationBox      = 102,
+    aDestinationSize     = 103,
+    aPatternPersistence  = 104,
+    aPatternDefineID     = 105,
+    aSourceHeight        = 107,
+    aSourceWidth         = 108,
+    aStartLine           = 109,
+    aPadBytesMultiple    = 110,
+    aBlockByteLength     = 111,
+    aNumberOfScanLines   = 115,
+    aColorTreatment      = 120,
+    aCommentData         = 129,
+    aDataOrg             = 130,
+    aMeasure             = 134,
+    aSourceType          = 136,
+    aUnitsPerMeasure     = 137,
+    aStreamName          = 139,
+    aStreamDataLength    = 140,
+    aErrorReport         = 143,
+    aCharAngle           = 161,
+    aCharCode            = 162,
+    aCharDataSize        = 163,
+    aCharScale           = 164,
+    aCharShear           = 165,
+    aCharSize            = 166,
+    aFontHeaderLength    = 167,
+    aFontName            = 168,
+    aFontFormat          = 169,
+    aSymbolSet           = 170,
+    aTextData            = 171,
+    aCharSubModeArray    = 172,
+    aXSpacingData        = 175,
+    aYSpacingData        = 176,
+    aCharBoldValue       = 177
+};
+                                          
+enum Operator {
+    oBeginSession        = 0x41,
+    oEndSession          = 0x42,
+    oBeginPage           = 0x43,
+    oEndPage             = 0x44,
+    oComment             = 0x47,
+    oOpenDataSource      = 0x48,
+    oCloseDataSource     = 0x49,
+    oBeginFontHeader     = 0x4f,
+    oReadFontHeader      = 0x50,
+    oEndFontHeader       = 0x51,
+    oBeginChar           = 0x52,
+    oReadChar            = 0x53,
+    oEndChar             = 0x54,
+    oRemoveFont          = 0x55,
+    oSetCharAttributes   = 0x56,
+    oBeginStream         = 0x5b,
+    oReadStream          = 0x5c,
+    oEndStream           = 0x5d,
+    oExecStream          = 0x5e,
+    oRemoveStream        = 0x5f,
+    oPopGS               = 0x60,
+    oPushGS              = 0x61,
+    oSetClipReplace      = 0x62,
+    oSetBrushSource      = 0x63,
+    oSetCharAngle        = 0x64,
+    oSetCharScale        = 0x65,
+    oSetCharShear        = 0x66,
+    oSetClipIntersect    = 0x67,
+    oSetClipRectangle    = 0x68,
+    oSetClipToPage       = 0x69,
+    oSetColorSpace       = 0x6a,
+    oSetCursor           = 0x6b,
+    oSetCursorRel        = 0x6c,
+    oSetHalftoneMethod   = 0x6d,
+    oSetFillMode         = 0x6e,
+    oSetFont             = 0x6f,
+    oSetLineDash         = 0x70,
+    oSetLineCap          = 0x71,
+    oSetLineJoin         = 0x72,
+    oSetMiterLimit       = 0x73,
+    oSetPageDefaultCTM   = 0x74,
+    oSetPageOrigin       = 0x75,
+    oSetPageRotation     = 0x76,
+    oSetPageScale        = 0x77,
+    oSetPatternTxMode    = 0x78,
+    oSetPenSource        = 0x79,
+    oSetPenWidth         = 0x7a,
+    oSetROP              = 0x7b,
+    oSetSourceTxMode     = 0x7c,
+    oSetCharBoldValue    = 0x7d,
+    oSetClipMode         = 0x7f,
+    oSetPathToClip       = 0x80,
+    oSetCharSubMode      = 0x81,
+    oCloseSubPath        = 0x84,
+    oNewPath             = 0x85,
+    oPaintPath           = 0x86,
+    oArcPath             = 0x91,
+    oBezierPath          = 0x93,
+    oBezierRelPath       = 0x95,
+    oChord               = 0x96,
+    oChordPath           = 0x97,
+    oEllipse             = 0x98,
+    oEllipsePath         = 0x99,
+    oLinePath            = 0x9b,
+    oLineRelPath         = 0x9d,
+    oPie                 = 0x9e,
+    oPiePath             = 0x9f,
+    oRectangle           = 0xa0,
+    oRectanglePath       = 0xa1,
+    oRoundRectangle      = 0xa2,  
+    oRoundRectanglePath  = 0xa3,
+    oText                = 0xa8,
+    oTextPath            = 0xa9,
+    oBeginImage          = 0xb0,
+    oReadImage           = 0xb1,
+    oEndImage            = 0xb2,
+    oBeginRastPattern    = 0xb3,
+    oReadRastPattern     = 0xb4,
+    oEndRastPattern      = 0xb5,
+    oBeginScan           = 0xb6,
+    oEndScan             = 0xb8,
+    oScanLineRel         = 0xb9
+};
+
+enum MediaSize {
+    eLetterPaper,
+    eLegalPaper,
+    eA4Paper,
+    eExecPaper,
+    eLedgerPaper,
+    eA3Paper,
+    eCOM10Envelope,
+    eMonarchEnvelope,
+    eC5Envelope,
+    eDLEnvelope,
+    eJB4Paper,
+    eJB5Paper,
+    etralala,
+    eB5Envelope,
+    eJPostcard,
+    eJDoublePostcard,
+    eA5Paper,
+    eA6Paper,
+    eJB6Paper
+};
+
+struct sPaperFormat {
+    const char *name;
+    int xl_nr;
+    float width,height; /* inch */
+} xlPaperFormats[] = {
+    {"letter",eLetterPaper,8.5,11.0},
+    {"legal",eLegalPaper,8.5,14},
+    {"a4",eA4Paper,8.26389,11.6944},
+    {"exec",eExecPaper,190/2.54,254/2.54},
+    {"ledger",eLedgerPaper,279/2.54,432/2.54},
+    {"a3",eA3Paper,11.6944,16.5278},
+    {"com10envelope",eCOM10Envelope,105/2.54,241/2.54},
+    {"monarchenvelope",eMonarchEnvelope,98/2.54,191/2.54},
+    {"c5envelope",eC5Envelope,162/2.54,229/2.54},
+    {"dlenvelope",eDLEnvelope,110/2.54,220/2.54},
+    {"jb4",eJB4Paper,257/2.54,364/2.54},
+    {"jb5",eJB5Paper,182/2.54,257/2.54},
+    {"b5envelope",eB5Envelope,176/2.54,250/2.54},
+    {"",-1,0,0},
+    {"jpostcard",eJPostcard,148/2.54,200/2.54},
+    {"jdoublepostcard",eJDoublePostcard,100/2.54,148/2.54},
+    {"a5",eA5Paper, 5.84722,8.26389},
+    {"a6",eA6Paper,4.125,5.84722},
+    {"jb6",eJB6Paper,0,0},
+    {NULL,0,0,0}
+};
+
+enum {
+    eSTART,
+    eRLE,
+    eLIT 
+} RLEstates;
+
+#endif
diff --git a/converter/other/pfmtopam.c b/converter/other/pfmtopam.c
new file mode 100644
index 00000000..9430f5fa
--- /dev/null
+++ b/converter/other/pfmtopam.c
@@ -0,0 +1,395 @@
+/*****************************************************************************
+                                  pfmtopam
+******************************************************************************
+  This program converts a PFM (Portable Float Map) image to PAM.
+  
+  By Bryan Henderson, San Jose, CA April 2004.
+
+  Contributed to the public domain by its author.
+
+*****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pam.h"
+#include "pm_gamma.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+
+
+struct cmdlineInfo {
+    const char * inputFilespec;
+    unsigned int verbose;
+    sample maxval;
+};
+
+
+
+static void 
+parseCommandLine(int argc, 
+                 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 = malloc( 100*sizeof( optEntry ) );
+    /* Instructions to optParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+  
+    unsigned int option_def_index;
+    unsigned int maxvalSpec;
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "maxval",   OPT_UINT, &cmdlineP->maxval, &maxvalSpec,        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 */
+
+    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    /* Uses and sets argc, argv, and some of *cmdline_p and others. */
+
+    if (!maxvalSpec)
+        cmdlineP->maxval = PNM_MAXMAXVAL;
+
+    if (cmdlineP->maxval > PNM_OVERALLMAXVAL)
+        pm_error("Maximum allowed -maxval is %u.  You specified %u",
+                 PNM_OVERALLMAXVAL, (unsigned)cmdlineP->maxval);
+    else if (cmdlineP->maxval == 0)
+        pm_error("-maxval cannot be 0");
+
+    /* Get the program parameters */
+
+    if (argc-1 >= 1)
+        cmdlineP->inputFilespec = argv[1];
+    else
+        cmdlineP->inputFilespec = "-";
+    
+    if (argc-1 > 1)
+        pm_error("Program takes at most one argument:  the file name.  "
+                 "You specified %d", argc-1);
+}
+
+
+enum endian {ENDIAN_BIG, ENDIAN_LITTLE};
+
+
+static enum endian machineEndianness;
+
+
+
+static enum endian
+thisMachineEndianness(void) {
+/*----------------------------------------------------------------------------
+   Endianness is a component of the format in which a machine represents
+   a number in memory or a register.  It is the only component of the format
+   that varies among typical machines.
+
+   Big endianness is the natural format.  In this format, if an integer is
+   4 bytes, to be stored at memory address 100-103, the most significant 
+   byte goes at 100, the next most significant at 101, and the least
+   significant byte at 103.  This is natural because it matches the way
+   humans read and write numbers.  I.e. 258 is stored as 0x00000102.
+
+   Little endian is extremely common because it is used by IA32.  In the
+   example above, the least significant byte goes first, so 258 would be
+   stored as 0x02010000.
+
+   You can extend this concept to floating point numbers, even though the
+   bytes of a floating point number differ by more than significance.
+-----------------------------------------------------------------------------*/
+    short const testNumber = 0x0001;
+
+    unsigned char * const storedNumber = (unsigned char *)&testNumber;
+    enum endian endianness;
+    
+    if (storedNumber[0] == 0x01)
+        endianness = ENDIAN_LITTLE;
+    else
+        endianness = ENDIAN_BIG;
+
+    return endianness;
+}
+
+
+
+typedef union {
+    unsigned char bytes[4];      /* as read from the file */
+    float value;
+        /* This is valid only if the pfmSample has the same endianness
+           as the machine we're running on.
+        */
+} pfmSample;
+
+
+
+static float
+floatFromPfmSample(pfmSample   const sample, 
+                   enum endian const pfmEndianness) {
+/*----------------------------------------------------------------------------
+   Type converter
+-----------------------------------------------------------------------------*/
+    if (machineEndianness == pfmEndianness) {
+        return sample.value;
+    } else {
+        pfmSample rightEndianSample;
+        unsigned int i, j;
+        
+        for (i = 0, j = sizeof(sample.bytes)-1; 
+             i < sizeof(sample.bytes); 
+             ++i, --j)
+            
+            rightEndianSample.bytes[i] = sample.bytes[j];
+
+        return rightEndianSample.value;
+    }
+}
+
+
+
+struct pfmHeader {
+    unsigned int width;
+    unsigned int height;
+    bool color;
+    float scaleFactor;
+    enum endian endian;
+};
+
+
+static void
+readPfmHeader(FILE *             const ifP,
+              struct pfmHeader * const pfmHeaderP) {
+
+    int firstChar;
+    int secondChar;
+    float scaleFactorEndian;
+
+    firstChar = fgetc(ifP);
+    if (firstChar == EOF)
+        pm_error("Error reading first character of PFM file");
+    secondChar = fgetc(ifP);
+    if (secondChar == EOF)
+        pm_error("Error reading second character of PFM file");
+
+    if (firstChar != 'P' || (secondChar != 'F' && secondChar != 'f'))
+        pm_error("First two characters of input file are '%c%c', but "
+                 "for a valid PFM file, they must be 'PF' or 'Pf'.",
+                 firstChar, secondChar);
+
+    {
+        int whitespace;
+
+        whitespace = fgetc(ifP);
+        if (whitespace == EOF)
+            pm_error("Error reading third character of PFM file");
+
+        if (!isspace(whitespace))
+            pm_error("The 3rd character of the input file is not whitespace.");
+    }
+    {
+        int rc;
+        char whitespace;
+
+        rc = fscanf(ifP, "%u %u%c", 
+                    &pfmHeaderP->width, &pfmHeaderP->height, &whitespace);
+
+        if (rc == EOF)
+            pm_error("Error reading the width and height from input file.");
+        else if (rc != 3)
+            pm_error("Invalid input file format where width and height "
+                     "are supposed to be (should be two positive decimal "
+                     "integers separated by a space and followed by "
+                     "white space)");
+        
+        if (!isspace(whitespace))
+            pm_error("Invalid input file format -- '%c' instead of "
+                     "white space after height", whitespace);
+
+        if (pfmHeaderP->width == 0)
+            pm_error("Invalid input file: image width is zero");
+        if (pfmHeaderP->height == 0)
+            pm_error("Invalid input file: image height is zero");
+    }
+    {
+        int rc;
+        char whitespace;
+
+        rc = fscanf(ifP, "%f%c", &scaleFactorEndian, &whitespace);
+
+        if (rc == EOF)
+            pm_error("Error reading the scale factor from input file.");
+        else if (rc != 2)
+            pm_error("Invalid input file format where scale factor "
+                     "is supposed to be (should be a floating point decimal "
+                     "number followed by white space");
+        
+        if (!isspace(whitespace))
+            pm_error("Invalid input file format -- '%c' instead of "
+                     "white space after scale factor", whitespace);
+    }
+
+    pfmHeaderP->color = (secondChar == 'F');  
+        /* 'PF' = RGB, 'Pf' = monochrome */
+
+    if (scaleFactorEndian > 0.0) {
+        pfmHeaderP->endian = ENDIAN_BIG;
+        pfmHeaderP->scaleFactor = scaleFactorEndian;
+    } else if (scaleFactorEndian < 0.0) {
+        pfmHeaderP->endian = ENDIAN_LITTLE;
+        pfmHeaderP->scaleFactor = - scaleFactorEndian;
+    } else
+        pm_error("Scale factor/endianness in PFM header is 0");
+}
+
+
+static void
+dumpPfmHeader(struct pfmHeader const pfmHeader) {
+
+    pm_message("width: %u, height: %u", pfmHeader.width, pfmHeader.height);
+    pm_message("color: %s", pfmHeader.color ? "YES" : "NO");
+    pm_message("endian: %s", 
+               pfmHeader.endian == ENDIAN_BIG ? "BIG" : "LITTLE");
+    pm_message("scale factor: %f", pfmHeader.scaleFactor);
+}
+
+
+
+static void
+initPam(struct pam * const pamP, 
+        int          const width, 
+        int          const height, 
+        bool         const color,
+        sample       const maxval) {
+
+    pamP->size        = sizeof(*pamP);
+    pamP->len         = PAM_STRUCT_SIZE(tuple_type);
+    pamP->file        = stdout;
+    pamP->format      = PAM_FORMAT;
+    pamP->plainformat = FALSE;
+    pamP->width       = width;
+    pamP->height      = height;
+    pamP->maxval      = maxval;
+    if (color) {
+        pamP->depth = 3;
+        strcpy(pamP->tuple_type, "RGB");
+    } else {
+        pamP->depth = 1;
+        strcpy(pamP->tuple_type, "GRAYSCALE");
+    }
+}
+
+
+
+static void
+makePamRow(struct pam * const pamP,
+           FILE *       const ifP,
+           unsigned int const pfmRow,
+           unsigned int const pfmSamplesPerRow,
+           tuplen **    const tuplenArray,
+           enum endian  const endian,
+           float        const scaleFactor,
+           pfmSample *  const pfmRowBuffer) {
+/*----------------------------------------------------------------------------
+   Make a PAM (tuple) row of the form described by *pamP, from the next
+   row in the PFM file identified by 'ifP'.  Place it in the proper location
+   in the tuple array 'tuplenArray'.
+  
+   'endian' is the endianness of the samples in the PFM file.
+
+   'pfmRowNum' is the sequence number (starting at 0, which is the
+   bottommost row of the image) of the row we are converting in the
+   PFM file.
+
+   Use 'pfmRowBuffer' as a work space; Caller must ensure this array
+   has at least 'pfmSamplesPerRow' elements of space in it.
+-----------------------------------------------------------------------------*/
+    int      const row       = pamP->height - pfmRow - 1;
+    tuplen * const tuplenRow = tuplenArray[row];
+
+    int col;
+    int pfmCursor;
+    int rc;
+
+    rc = fread(pfmRowBuffer, sizeof(pfmSample), pfmSamplesPerRow, ifP);
+    if (rc != pfmSamplesPerRow)
+        pm_error("End of file in the middle of row %d", pfmRow);
+
+    pfmCursor = 0;
+
+    for (col = 0; col < pamP->width; ++col) {
+        /* The order of planes (R, G, B) is the same in PFM as in PAM. */
+        unsigned int plane;
+        for (plane = 0; plane < pamP->depth; ++plane) {
+            float const val = 
+                floatFromPfmSample(pfmRowBuffer[pfmCursor++], endian);
+            tuplenRow[col][plane] = val / scaleFactor;
+        }
+    }
+    assert(pfmCursor == pfmSamplesPerRow);
+}
+
+
+
+int
+main(int argc, char **argv ) {
+
+    struct cmdlineInfo cmdline;
+    FILE* ifP;
+    struct pam pam;
+    struct pfmHeader pfmHeader;
+    pfmSample * pfmRowBuffer;
+    unsigned int pfmSamplesPerRow;
+    unsigned pfmRow;
+    tuplen ** tuplenArray;
+
+    machineEndianness = thisMachineEndianness();
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    readPfmHeader(ifP, &pfmHeader);
+
+    if (cmdline.verbose)
+        dumpPfmHeader(pfmHeader);
+
+    initPam(&pam, 
+            pfmHeader.width, pfmHeader.height, pfmHeader.color,
+            cmdline.maxval);
+
+    tuplenArray = pnm_allocpamarrayn(&pam);
+
+    pfmSamplesPerRow = pam.width * pam.depth;
+    
+    MALLOCARRAY_NOFAIL(pfmRowBuffer, pfmSamplesPerRow);
+
+    /* PFMs are upside down like BMPs */
+    for (pfmRow = 0; pfmRow < pam.height; ++pfmRow)
+        makePamRow(&pam, ifP, pfmRow, pfmSamplesPerRow,
+                   tuplenArray, pfmHeader.endian, pfmHeader.scaleFactor,
+                   pfmRowBuffer);
+
+    pnm_writepamn(&pam, tuplenArray);
+
+    pnm_freepamarrayn(tuplenArray, &pam);
+    free(pfmRowBuffer);
+    
+    pm_close(ifP);
+    pm_close(pam.file);
+
+    return 0;
+}
diff --git a/converter/other/pgmtopbm.c b/converter/other/pgmtopbm.c
new file mode 100644
index 00000000..98bdc332
--- /dev/null
+++ b/converter/other/pgmtopbm.c
@@ -0,0 +1,723 @@
+/* pgmtopbm.c - read a portable graymap and write a portable bitmap
+**
+** Copyright (C) 1989 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 <assert.h>
+#include "pgm.h"
+#include "dithers.h"
+#include "mallocvar.h"
+#include "shhopt.h"
+
+enum halftone {QT_FS, QT_THRESH, QT_DITHER8, QT_CLUSTER, QT_HILBERT};
+
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char *  inputFilespec;
+    enum halftone halftone;
+    unsigned int  clumpSize;
+    unsigned int  clusterRadius;  
+        /* Defined only for halftone == QT_CLUSTER */
+    float         threshval;
+};
+
+
+
+
+static void
+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.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def;
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    unsigned int floydOpt, hilbertOpt, thresholdOpt, dither8Opt,
+        cluster3Opt, cluster4Opt, cluster8Opt;
+    unsigned int valueSpec, clumpSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "floyd",     OPT_FLAG,  NULL, &floydOpt,     0);
+    OPTENT3(0, "fs",        OPT_FLAG,  NULL, &floydOpt,     0);
+    OPTENT3(0, "threshold", OPT_FLAG,  NULL, &thresholdOpt, 0);
+    OPTENT3(0, "hilbert",   OPT_FLAG,  NULL, &hilbertOpt,   0);
+    OPTENT3(0, "dither8",   OPT_FLAG,  NULL, &dither8Opt,   0);
+    OPTENT3(0, "d8",        OPT_FLAG,  NULL, &dither8Opt,   0);
+    OPTENT3(0, "cluster3",  OPT_FLAG,  NULL, &cluster3Opt,  0);
+    OPTENT3(0, "c3",        OPT_FLAG,  NULL, &cluster3Opt,  0);
+    OPTENT3(0, "cluster4",  OPT_FLAG,  NULL, &cluster4Opt,  0);
+    OPTENT3(0, "c4",        OPT_FLAG,  NULL, &cluster4Opt,  0);
+    OPTENT3(0, "cluster8",  OPT_FLAG,  NULL, &cluster8Opt,  0);
+    OPTENT3(0, "c8",        OPT_FLAG,  NULL, &cluster8Opt,  0);
+    OPTENT3(0, "value",     OPT_FLOAT, &cmdlineP->threshval, 
+            &valueSpec, 0);
+    OPTENT3(0, "clump",     OPT_UINT,  &cmdlineP->clumpSize, 
+            &clumpSpec, 0);
+
+    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 */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (floydOpt + thresholdOpt + hilbertOpt + dither8Opt + 
+        cluster3Opt + cluster4Opt + cluster8Opt == 0)
+        cmdlineP->halftone = QT_FS;
+    else if (floydOpt + thresholdOpt + dither8Opt + 
+        cluster3Opt + cluster4Opt + cluster8Opt > 1)
+        pm_error("No cannot specify more than one halftoning type");
+    else {
+        if (floydOpt)
+            cmdlineP->halftone = QT_FS;
+        else if (thresholdOpt)
+            cmdlineP->halftone = QT_THRESH;
+        else if (hilbertOpt)
+            cmdlineP->halftone = QT_HILBERT;
+        else if (dither8Opt)
+            cmdlineP->halftone = QT_DITHER8;
+        else if (cluster3Opt) {
+            cmdlineP->halftone = QT_CLUSTER;
+            cmdlineP->clusterRadius = 3;
+        } else if (cluster4Opt) {
+            cmdlineP->halftone = QT_CLUSTER;
+            cmdlineP->clusterRadius = 4;
+        } else if (cluster8Opt) {
+            cmdlineP->halftone = QT_CLUSTER;
+            cmdlineP->clusterRadius = 8;
+        } else 
+            pm_error("INTERNAL ERROR.  No halftone option");
+    }
+
+    if (!valueSpec)
+        cmdlineP->threshval = 0.5;
+    else {
+        if (cmdlineP->threshval < 0.0)
+            pm_error("-value cannot be negative.  You specified %f",
+                     cmdlineP->threshval);
+        if (cmdlineP->threshval > 1.0)
+            pm_error("-value cannot be greater than one.  You specified %f",
+                     cmdlineP->threshval);
+    }
+            
+    if (!clumpSpec)
+        cmdlineP->clumpSize = 5;
+    else {
+        if (cmdlineP->clumpSize < 2)
+            pm_error("-clump must be at least 2.  You specified %u",
+                     cmdlineP->clumpSize);
+    }
+
+    if (argc-1 > 1)
+        pm_error("Too many arguments (%d).  There is at most one "
+                 "non-option argument:  the file name",
+                 argc-1);
+    else if (argc-1 == 1)
+        cmdlineP->inputFilespec = argv[1];
+    else
+        cmdlineP->inputFilespec = "-";
+}
+
+
+
+/* Hilbert curve tracer */
+
+#define MAXORD 18
+
+static int hil_order,hil_ord;
+static int hil_turn;
+static int hil_dx,hil_dy;
+static int hil_x,hil_y;
+static int hil_stage[MAXORD];
+static int hil_width,hil_height;
+
+static void 
+init_hilbert(int const w, 
+             int const h) {
+/*----------------------------------------------------------------------------
+  Initialize the Hilbert curve tracer 
+-----------------------------------------------------------------------------*/
+    int big,ber;
+    hil_width = w;
+    hil_height = h;
+    big = w > h ? w : h;
+    for (ber = 2, hil_order = 1; ber < big; ber <<= 1, hil_order++);
+    if (hil_order > MAXORD)
+        pm_error("Sorry, hilbert order is too large");
+    hil_ord = hil_order;
+    hil_order--;
+}
+
+
+
+static int 
+hilbert(int * const px, int * const py) {
+/*----------------------------------------------------------------------------
+  Return non-zero if got another point
+-----------------------------------------------------------------------------*/
+    int temp;
+    if (hil_ord > hil_order) {
+        /* have to do first point */
+
+        hil_ord--;
+        hil_stage[hil_ord] = 0;
+        hil_turn = -1;
+        hil_dy = 1;
+        hil_dx = hil_x = hil_y = 0;
+        *px = *py = 0;
+        return 1;
+    }
+
+    /* Operate the state machine */
+    for(;;)  {
+        switch (hil_stage[hil_ord]) {
+        case 0:
+            hil_turn = -hil_turn;
+            temp = hil_dy;
+            hil_dy = -hil_turn * hil_dx;
+            hil_dx = hil_turn * temp;
+            if (hil_ord > 0) {
+                hil_stage[hil_ord] = 1;
+                hil_ord--;
+                hil_stage[hil_ord]=0;
+                continue;
+            }
+        case 1:
+            hil_x += hil_dx;
+            hil_y += hil_dy;
+            if (hil_x < hil_width && hil_y < hil_height) {
+                hil_stage[hil_ord] = 2;
+                *px = hil_x;
+                *py = hil_y;
+                return 1;
+            }
+        case 2:
+            hil_turn = -hil_turn;
+            temp = hil_dy;
+            hil_dy = -hil_turn * hil_dx;
+            hil_dx = hil_turn * temp;
+            if (hil_ord > 0) { 
+                /* recurse */
+
+                hil_stage[hil_ord] = 3;
+                hil_ord--;
+                hil_stage[hil_ord]=0;
+                continue;
+            }
+        case 3:
+            hil_x += hil_dx;
+            hil_y += hil_dy;
+            if (hil_x < hil_width && hil_y < hil_height) {
+                hil_stage[hil_ord] = 4;
+                *px = hil_x;
+                *py = hil_y;
+                return 1;
+            }
+        case 4:
+            if (hil_ord > 0) {
+                /* recurse */
+                hil_stage[hil_ord] = 5;
+                hil_ord--;
+                hil_stage[hil_ord]=0;
+                continue;
+            }
+        case 5:
+            temp = hil_dy;
+            hil_dy = -hil_turn * hil_dx;
+            hil_dx = hil_turn * temp;
+            hil_turn = -hil_turn;
+            hil_x += hil_dx;
+            hil_y += hil_dy;
+            if (hil_x < hil_width && hil_y < hil_height) {
+                hil_stage[hil_ord] = 6;
+                *px = hil_x;
+                *py = hil_y;
+                return 1;
+            }
+        case 6:
+            if (hil_ord > 0) {
+                /* recurse */
+                hil_stage[hil_ord] = 7;
+                hil_ord--;
+                hil_stage[hil_ord]=0;
+                continue;
+            }
+        case 7:
+            temp = hil_dy;
+            hil_dy = -hil_turn * hil_dx;
+            hil_dx = hil_turn * temp;
+            hil_turn = -hil_turn;
+            /* Return from a recursion */
+            if (hil_ord < hil_order)
+                hil_ord++;
+            else
+                return 0;
+        }
+    }
+}
+
+
+
+static void doHilbert(FILE *       const ifP,
+                      unsigned int const clump_size) {
+/*----------------------------------------------------------------------------
+  Use hilbert space filling curve dithering
+-----------------------------------------------------------------------------*/
+    /*
+     * This is taken from the article "Digital Halftoning with
+     * Space Filling Curves" by Luiz Velho, proceedings of
+     * SIGRAPH '91, page 81.
+     *
+     * This is not a terribly efficient or quick version of
+     * this algorithm, but it seems to work. - Graeme Gill.
+     * graeme@labtam.labtam.OZ.AU
+     *
+     */
+
+    int cols, rows;
+    gray maxval;
+    gray **grays;
+    bit **bits;
+    int end;
+    int *x,*y;
+    int sum = 0;
+
+    grays = pgm_readpgm(ifP, &cols,&rows, &maxval);
+    bits = pbm_allocarray(cols,rows);
+
+    MALLOCARRAY(x, clump_size);
+    MALLOCARRAY(y, clump_size);
+    if (x == NULL  || y == NULL)
+        pm_error("out of memory");
+    init_hilbert(cols,rows);
+
+    end = clump_size;
+    while (end == clump_size) {
+        int i;
+        /* compute the next clust co-ordinates along hilbert path */
+        for (i = 0; i < end; i++) {
+            if (hilbert(&x[i],&y[i])==0)
+                end = i;    /* we reached the end */
+        }
+        /* sum levels */
+        for (i = 0; i < end; i++)
+            sum += grays[y[i]][x[i]];
+        /* dither half and half along path */
+        for (i = 0; i < end; i++) {
+            if (sum >= maxval) {
+                bits[y[i]][x[i]] = PBM_WHITE;
+                sum -= maxval;
+            } else
+                bits[y[i]][x[i]] = PBM_BLACK;
+        }
+    }
+    pbm_writepbm(stdout, bits, cols, rows, 0);
+}
+
+
+
+struct converter {
+    void (*convertRow)(struct converter * const converterP,
+                       unsigned int       const row,
+                       gray                     grayrow[], 
+                       bit                      bitrow[]);
+    void (*destroy)(struct converter * const converterP);
+    unsigned int cols;
+    gray maxval;
+    void * stateP;
+};
+
+
+
+unsigned int const fs_scale      = 1024;
+unsigned int const half_fs_scale = 512;
+
+struct fsState {
+    long* thiserr;
+    long* nexterr;
+    bool fs_forward;
+    long threshval;  /* Threshold gray value, scaled by FS_SCALE */
+};
+
+
+static void
+fsConvertRow(struct converter * const converterP,
+             unsigned int       const row,
+             gray                     grayrow[],
+             bit                      bitrow[]) {
+
+    struct fsState * const stateP = converterP->stateP;
+
+    long * const thiserr = stateP->thiserr;
+    long * const nexterr = stateP->nexterr;
+
+    bit* bP;
+    gray* gP;
+
+    unsigned int limitcol;
+    unsigned int col;
+    
+    for (col = 0; col < converterP->cols + 2; ++col)
+        nexterr[col] = 0;
+    if (stateP->fs_forward) {
+        col = 0;
+        limitcol = converterP->cols;
+        gP = grayrow;
+        bP = bitrow;
+    } else {
+        col = converterP->cols - 1;
+        limitcol = -1;
+        gP = &(grayrow[col]);
+        bP = &(bitrow[col]);
+    }
+    do {
+        long sum;
+        sum = ((long) *gP * fs_scale) / converterP->maxval + 
+            thiserr[col + 1];
+        if (sum >= stateP->threshval) {
+            *bP = PBM_WHITE;
+            sum = sum - stateP->threshval - half_fs_scale;
+        } else
+            *bP = PBM_BLACK;
+        
+        if (stateP->fs_forward) {
+            thiserr[col + 2] += (sum * 7) / 16;
+            nexterr[col    ] += (sum * 3) / 16;
+            nexterr[col + 1] += (sum * 5) / 16;
+            nexterr[col + 2] += (sum    ) / 16;
+            
+            ++col;
+            ++gP;
+            ++bP;
+        } else {
+            thiserr[col    ] += (sum * 7) / 16;
+            nexterr[col + 2] += (sum * 3) / 16;
+            nexterr[col + 1] += (sum * 5) / 16;
+            nexterr[col    ] += (sum    ) / 16;
+            
+            --col;
+            --gP;
+            --bP;
+        }
+    } while (col != limitcol);
+    
+    stateP->thiserr = nexterr;
+    stateP->nexterr = thiserr;
+    stateP->fs_forward = ! stateP->fs_forward;
+}
+
+
+
+static void
+fsDestroy(struct converter * const converterP) {
+    free(converterP->stateP);
+}
+
+
+
+static struct converter
+createFsConverter(unsigned int const cols, 
+                  gray         const maxval,
+                  float        const threshFraction) {
+
+    struct fsState * stateP;
+    struct converter converter;
+
+    MALLOCVAR_NOFAIL(stateP);
+
+    /* Initialize Floyd-Steinberg error vectors. */
+    MALLOCARRAY_NOFAIL(stateP->thiserr, cols + 2);
+    MALLOCARRAY_NOFAIL(stateP->nexterr, cols + 2);
+    srand((int)(time(NULL) ^ getpid()));
+
+    {
+        /* (random errors in [-fs_scale/8 .. fs_scale/8]) */
+        unsigned int col;
+        for (col = 0; col < cols + 2; ++col)
+            stateP->thiserr[col] = 
+                (long)(rand() % fs_scale - half_fs_scale) / 4;
+    }
+
+    stateP->fs_forward = TRUE;
+    stateP->threshval = threshFraction * fs_scale;
+    converter.stateP = stateP;
+    converter.cols = cols;
+    converter.maxval = maxval;
+    converter.convertRow = &fsConvertRow;
+    converter.destroy = &fsDestroy;
+
+    return converter;
+}
+
+
+
+struct threshState {
+    gray threshval;
+};
+
+
+static void
+threshConvertRow(struct converter * const converterP,
+                 unsigned int       const row,
+                 gray                     grayrow[],
+                 bit                      bitrow[]) {
+    
+    struct threshState * const stateP = converterP->stateP;
+
+    unsigned int col;
+    for (col = 0; col < converterP->cols; ++col)
+        if (grayrow[col] >= stateP->threshval)
+            bitrow[col] = PBM_WHITE;
+        else
+            bitrow[col] = PBM_BLACK;
+}
+
+
+
+static void
+threshDestroy(struct converter * const converterP) {
+    free(converterP->stateP);
+}
+
+
+
+static struct converter
+createThreshConverter(unsigned int const cols, 
+                      gray         const maxval,
+                      float        const threshFraction) {
+
+    struct threshState * stateP;
+    struct converter converter;
+
+    MALLOCVAR_NOFAIL(stateP);
+
+    converter.cols       = cols;
+    converter.maxval     = maxval;
+    converter.convertRow = &threshConvertRow;
+    converter.destroy    = &threshDestroy;
+
+    stateP->threshval    = ROUNDU(maxval * threshFraction);
+    converter.stateP     = stateP;
+
+    return converter;
+}
+
+
+
+static void
+dither8ConvertRow(struct converter * const converterP,
+                  unsigned int       const row,
+                  gray                     grayrow[],
+                  bit                      bitrow[]) {
+
+    unsigned int col;
+
+    for (col = 0; col < converterP->cols; ++col)
+        if (grayrow[col] > dither8[row % 16][col % 16])
+            bitrow[col] = PBM_WHITE;
+        else
+            bitrow[col] = PBM_BLACK;
+}
+
+
+
+static struct converter
+createDither8Converter(unsigned int const cols, 
+                       gray         const maxval) {
+
+    struct converter converter;
+
+    unsigned int row;
+
+    converter.cols = cols;
+    converter.convertRow = &dither8ConvertRow;
+    converter.destroy = NULL;
+
+    /* Scale dither matrix. */
+    for (row = 0; row < 16; ++row) {
+        unsigned int col;
+        for (col = 0; col < 16; ++col)
+            dither8[row][col] = dither8[row][col] * maxval / 256;
+    }
+    return converter;
+}
+
+
+
+struct clusterState {
+    unsigned int radius;
+    int ** clusterMatrix;
+};
+
+
+
+static void
+clusterConvertRow(struct converter * const converterP,
+                  unsigned int       const row,
+                  gray                     grayrow[],
+                  bit                      bitrow[]) {
+
+    struct clusterState * const stateP = converterP->stateP;
+    unsigned int const diameter = 2 * stateP->radius;
+
+    unsigned int col;
+
+    for (col = 0; col < converterP->cols; ++col)
+        if (grayrow[col] >
+            stateP->clusterMatrix[row % diameter][col % diameter])
+            bitrow[col] = PBM_WHITE;
+        else
+            bitrow[col] = PBM_BLACK;
+}
+
+
+
+static void
+clusterDestroy(struct converter * const converterP) {
+
+    struct clusterState * const stateP = converterP->stateP;
+    unsigned int const diameter = 2 * stateP->radius;
+
+    unsigned int row;
+
+    for (row = 0; row < diameter; ++row)
+        free(stateP->clusterMatrix[row]);
+
+    free(stateP->clusterMatrix);
+    
+    free(stateP);
+}
+
+
+
+static struct converter
+createClusterConverter(unsigned int const radius,
+                       unsigned int const cols, 
+                       gray         const maxval) {
+    
+    int const clusterNormalizer = radius * radius * 2;
+    unsigned int const diameter = 2 * radius;
+
+    struct converter converter;
+    struct clusterState * stateP;
+    unsigned int row;
+
+    converter.cols = cols;
+    converter.convertRow = &clusterConvertRow;
+    converter.destroy = &clusterDestroy;
+
+    MALLOCVAR_NOFAIL(stateP);
+
+    stateP->radius = radius;
+
+    MALLOCARRAY_NOFAIL(stateP->clusterMatrix, diameter);
+    for (row = 0; row < diameter; ++row) {
+        unsigned int col;
+
+        MALLOCARRAY_NOFAIL(stateP->clusterMatrix[row], diameter);
+        
+        for (col = 0; col < diameter; ++col) {
+            int val;
+            switch (radius) {
+            case 3: val = cluster3[row][col]; break;
+            case 4: val = cluster4[row][col]; break;
+            case 8: val = cluster8[row][col]; break;
+            default:
+                pm_error("INTERNAL ERROR: invalid radius");
+            }
+            stateP->clusterMatrix[row][col] = val * maxval / clusterNormalizer;
+        }
+    }            
+
+    converter.stateP = stateP;
+
+    return converter;
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE* ifP;
+    gray* grayrow;
+    bit* bitrow;
+
+    pgm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    if (cmdline.halftone == QT_HILBERT)
+        doHilbert(ifP, cmdline.clumpSize);
+    else {
+        struct converter converter;
+        int cols, rows;
+        gray maxval;
+        int format;
+        int row;
+
+        pgm_readpgminit(ifP, &cols, &rows, &maxval, &format);
+        
+        pbm_writepbminit(stdout, cols, rows, 0);
+
+        switch (cmdline.halftone) {
+        case QT_FS:
+            converter = createFsConverter(cols, maxval, cmdline.threshval);
+            break;
+        case QT_THRESH:
+            converter = createThreshConverter(cols, maxval, cmdline.threshval);
+            break;
+        case QT_DITHER8: 
+            converter = createDither8Converter(cols, maxval); 
+            break;
+        case QT_CLUSTER: 
+            converter = 
+                createClusterConverter(cmdline.clusterRadius, cols, maxval);
+            break;
+        case QT_HILBERT: 
+                pm_error("INTERNAL ERROR: halftone is QT_HILBERT where it "
+                         "shouldn't be.");
+                break;
+        }
+
+        grayrow = pgm_allocrow(cols);
+        bitrow  = pbm_allocrow(cols);
+
+        for (row = 0; row < rows; ++row) {
+            pgm_readpgmrow(ifP, grayrow, cols, maxval, format);
+
+            converter.convertRow(&converter, row, grayrow, bitrow);
+            
+            pbm_writepbmrow(stdout, bitrow, cols, 0);
+        }
+        pbm_freerow(bitrow);
+        pgm_freerow(grayrow);
+
+        if (converter.destroy)
+            converter.destroy(&converter);
+    }
+
+    pm_close(ifP);
+
+    return 0;
+}
diff --git a/converter/other/pgmtoppm.c b/converter/other/pgmtoppm.c
new file mode 100644
index 00000000..c695ddd5
--- /dev/null
+++ b/converter/other/pgmtoppm.c
@@ -0,0 +1,153 @@
+/* pgmtoppm.c - colorize a portable graymap into 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.
+*/
+
+#include <string.h>
+#include "ppm.h"
+
+int
+main( argc, argv )
+    int argc;
+    char* argv[];
+    {
+    FILE* ifp;
+    gray* grayrow;
+    register gray* gP;
+    pixel p;
+    pixel* pixelrow;
+    register pixel* pP;
+    pixel** mappixels;
+    int argn, rows, cols, format, maprows, mapcols, mapmaxcolor, row;
+    register int col;
+    gray maxval;
+    pixval mapmaxval;
+    char* color0;
+    char* color1;
+    pixval red0, grn0, blu0, red1, grn1, blu1;
+    const char* const usage = "<colorspec> [pgmfile]\n                 <colorspec1>,<colorspec2> [pgmfile]\n                 -map mapfile [pgmfile]";
+
+
+    ppm_init( &argc, argv );
+
+    argn = 1;
+    mappixels = (pixel**) 0;
+
+    if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
+	{
+	if ( pm_keymatch( argv[argn], "-map", 2 ) )
+	    {
+	    ++argn;
+	    if ( argn == argc )
+		pm_usage( usage );
+	    ifp = pm_openr( argv[argn] );
+	    mappixels = ppm_readppm( ifp, &mapcols, &maprows, &mapmaxval );
+	    pm_close( ifp );
+	    mapmaxcolor = maprows * mapcols - 1;
+	    }
+	else
+	    pm_usage( usage );
+	++argn;
+	}
+
+    if ( mappixels == (pixel**) 0 )
+	{
+	if ( argn == argc )
+	    pm_usage( usage );
+	color0 = argv[argn];
+	++argn;
+	}
+
+    if ( argn != argc )
+	{
+	ifp = pm_openr( argv[argn] );
+	++argn;
+	}
+    else
+	ifp = stdin;
+
+    if ( argn != argc )
+	pm_usage( usage );
+
+    pgm_readpgminit( ifp, &cols, &rows, &maxval, &format );
+    grayrow = pgm_allocrow( cols );
+    if ( mappixels == (pixel**) 0 )
+	ppm_writeppminit( stdout, cols, rows, (pixval) maxval, 0 );
+    else
+	ppm_writeppminit( stdout, cols, rows, mapmaxval, 0 );
+    pixelrow = ppm_allocrow( cols );
+
+    if ( mappixels == (pixel**) 0 )
+	{
+	color1 = strchr( color0, '-' );
+	if ( color1 == 0 )
+	    {
+	    color1 = color0;
+	    red0 = 0;
+	    grn0 = 0;
+	    blu0 = 0;
+	    }
+	else
+	    {
+	    *color1 = '\0';
+	    ++color1;
+	    p = ppm_parsecolor( color0, (pixval) maxval );
+	    red0 = PPM_GETR( p );
+	    grn0 = PPM_GETG( p );
+	    blu0 = PPM_GETB( p );
+	    }
+	p = ppm_parsecolor( color1, (pixval) maxval );
+	red1 = PPM_GETR( p );
+	grn1 = PPM_GETG( p );
+	blu1 = PPM_GETB( p );
+	}
+
+    for ( row = 0; row < rows; ++row )
+	{
+	pgm_readpgmrow( ifp, grayrow, cols, maxval, format );
+
+	if ( mappixels == (pixel**) 0 )
+	    {
+	    for ( col = 0, gP = grayrow, pP = pixelrow;
+		  col < cols;
+		  ++col, ++gP, ++pP )
+		PPM_ASSIGN(
+		    *pP,
+		    ( red0 * ( maxval - *gP ) + red1 * *gP ) / maxval,
+		    ( grn0 * ( maxval - *gP ) + grn1 * *gP ) / maxval,
+		    ( blu0 * ( maxval - *gP ) + blu1 * *gP ) / maxval );
+
+	    }
+	else
+	    {
+	    register int c;
+
+	    for ( col = 0, gP = grayrow, pP = pixelrow;
+		  col < cols;
+		  ++col, ++gP, ++pP )
+		{
+		if ( maxval == mapmaxcolor )
+		    c = *gP;
+		else
+		    c = *gP * mapmaxcolor / maxval;
+		*pP = mappixels[c / mapcols][c % mapcols];
+		}
+	    }
+
+	ppm_writeppmrow( stdout, pixelrow, cols, (pixval) maxval, 0 );
+	}
+
+    pm_close( ifp );
+
+    /* If the program failed, it previously aborted with nonzero completion
+       code, via various function calls.
+    */
+    return 0;
+    }
diff --git a/converter/other/pm_tiff.h b/converter/other/pm_tiff.h
new file mode 100644
index 00000000..f98110e3
--- /dev/null
+++ b/converter/other/pm_tiff.h
@@ -0,0 +1,41 @@
+#ifndef PM_TIFF_H_INCLUDED
+#define PM_TIFF_H_INCLUDED
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   This is an association between a tag value name and the integer that
+   represents the tag value in the TIFF.
+
+   E.g. for an ORIENTATION tag, the value named "TOPLEFT" is represented
+   by the integer 1.
+-----------------------------------------------------------------------------*/
+    const char *  name;
+    unsigned long value;
+} tagvalmap;
+
+typedef struct tagDefinition {
+/*----------------------------------------------------------------------------
+   This is the definition of a type of tag, e.g. ORIENTATION.
+-----------------------------------------------------------------------------*/
+    const char * name;
+        /* The name by which our user knows the tag type, e.g. 
+           "ORIENTATION"
+        */
+    unsigned int tagnum;
+        /* The integer by which libtiff knows the tag type, e.g.
+           TIFFTAG_ORIENTATION
+        */
+    void (*      put)(TIFF *, unsigned int, const char *, const tagvalmap *);
+    const tagvalmap * choices;
+        /* List of the possible values for the tag, if it is one with
+           enumerated values.  e.g. for ORIENTATION, it's TOPLEFT,
+           TOPRIGHT, etc.
+        */
+} tagDefinition;
+
+
+
+const tagDefinition *
+tagDefFind(const char * const name);
+
+#endif
diff --git a/converter/other/pngtopnm.c b/converter/other/pngtopnm.c
new file mode 100644
index 00000000..bb8afb8d
--- /dev/null
+++ b/converter/other/pngtopnm.c
@@ -0,0 +1,1096 @@
+/*
+** pngtopnm.c -
+** read a Portable Network Graphics file and produce a portable anymap
+**
+** Copyright (C) 1995,1998 by Alexander Lehmann <alex@hal.rhein-main.de>
+**                        and Willem van Schaik <willem@schaik.com>
+**
+** 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
+*/
+
+/* 
+   BJH 20000408:  rename PPM_MAXMAXVAL to PPM_OVERALLMAXVAL
+   BJH 20000303:  fix include statement so dependencies work out right.
+*/
+/* GRR 19991203:  moved VERSION to new version.h header file */
+
+/* GRR 19990713:  fixed redundant freeing of png_ptr and info_ptr in setjmp()
+ *  blocks and added "pm_close(ifp)" in each.  */
+
+/* GRR 19990317:  declared "clobberable" automatic variables in convertpng()
+ *  static to fix Solaris/gcc stack-corruption bug.  Also installed custom
+ *  error-handler to avoid jmp_buf size-related problems (i.e., jmp_buf
+ *  compiled with one size in libpng and another size here).  */
+
+#ifndef PNMTOPNG_WARNING_LEVEL
+#  define PNMTOPNG_WARNING_LEVEL 0   /* use 0 for backward compatibility, */
+#endif                               /*  2 for warnings (1 == error) */
+
+#include <math.h>
+#include <png.h>    /* includes zlib.h and setjmp.h */
+#define VERSION "2.37.4 (5 December 1999) +netpbm"
+
+#include "pnm.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+
+typedef struct _jmpbuf_wrapper {
+  jmp_buf jmpbuf;
+} jmpbuf_wrapper;
+
+/* GRR 19991205:  this is used as a test for pre-1999 versions of netpbm and
+ *   pbmplus vs. 1999 or later (in which pm_close was split into two)
+ */
+#ifdef PBMPLUS_RAWBITS
+#  define pm_closer pm_close
+#  define pm_closew pm_close
+#endif
+
+#ifndef TRUE
+#  define TRUE 1
+#endif
+#ifndef FALSE
+#  define FALSE 0
+#endif
+#ifndef NONE
+#  define NONE 0
+#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 pngcolor {
+/*----------------------------------------------------------------------------
+   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 int verbose = FALSE;
+static int mtime;
+static jmpbuf_wrapper pngtopnm_jmpbuf_struct;
+
+
+static void
+parseCommandLine(int                 argc, 
+                 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 = malloc(100*sizeof(optEntry));
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    unsigned int alphaSpec, mixSpec, backgroundSpec, gammaSpec, textSpec;
+
+    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, 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);
+}
+
+
+
+
+#define get_png_val(p) _get_png_val (&(p), info_ptr->bit_depth)
+
+static png_uint_16
+_get_png_val (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 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) (pow ((double) v / maxval, 
+                                   (1.0 / g)) * maxval + 0.5);
+    else
+        return v;
+}
+
+
+
+#ifdef __STDC__
+static int iscolor (png_color c)
+#else
+static int iscolor (c)
+png_color c;
+#endif
+{
+  return c.red != c.green || c.green != c.blue;
+}
+
+#ifdef __STDC__
+static void save_text (png_info *info_ptr, FILE *tfp)
+#else
+static void save_text (info_ptr, tfp)
+png_info *info_ptr;
+FILE *tfp;
+#endif
+{
+  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 */
+    
+    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);
+    }
+    putc ((int)'\n', tfp);
+  }
+}
+
+#ifdef __STDC__
+static void show_time (png_info *info_ptr)
+#else
+static void show_time (info_ptr)
+png_info *info_ptr;
+#endif
+{
+    static const char * const month[] = {
+        "", "January", "February", "March", "April", "May", "June",
+        "July", "August", "September", "October", "November", "December"
+    };
+
+  if (info_ptr->valid & PNG_INFO_tIME) {
+    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);
+  }
+}
+
+#ifdef __STDC__
+static void pngtopnm_error_handler (png_structp png_ptr, png_const_charp msg)
+#else
+static void pngtopnm_error_handler (png_ptr, msg)
+png_structp png_ptr;
+png_const_charp msg;
+#endif
+{
+  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. */
+
+  pm_message("fatal libpng error: %s", msg);
+
+  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.");
+  }
+
+  longjmp(jmpbuf_ptr->jmpbuf, 1);
+}
+
+
+
+static void
+dump_png_info(png_info *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 bool
+isTransparentColor(pngcolor   const color,
+                   png_info * const info_ptr,
+                   double     const totalgamma) {
+/*----------------------------------------------------------------------------
+   Return TRUE iff pixels of color 'color' are supposed to be transparent
+   everywhere they occur.  Assume it's an RGB image.
+-----------------------------------------------------------------------------*/
+    bool retval;
+
+    if (info_ptr->valid & PNG_INFO_tRNS) {
+        const png_color_16 * const transColorP = &info_ptr->trans_values;
+    
+
+        /* There seems to be a problem here: you can't compare real
+           numbers for equality.  Also, I'm not sure the gamma
+           corrected/uncorrected color spaces are right here.  
+        */
+
+        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;
+}
+
+
+
+#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");
+}
+
+
+
+static void
+setupGammaCorrection(png_struct * const png_ptr,
+                     png_info *   const info_ptr,
+                     float        const displaygamma,
+                     float *      const totalgammaP) {
+
+    if (displaygamma == -1.0)
+        *totalgammaP = -1.0;
+    else {
+        if (info_ptr->valid & PNG_INFO_gAMA) {
+            if (displaygamma != info_ptr->gamma) {
+                png_set_gamma(png_ptr, displaygamma, info_ptr->gamma);
+                *totalgammaP =
+                    (double) info_ptr->gamma * (double) displaygamma;
+                /* in case of gamma-corrections, sBIT's as in the
+                   PNG-file are not valid anymore 
+                */
+                info_ptr->valid &= ~PNG_INFO_sBIT;
+                if (verbose)
+                    pm_message("image gamma is %4.2f, "
+                               "converted for display gamma of %4.2f",
+                               info_ptr->gamma, displaygamma);
+            }
+        } else {
+            if (displaygamma != info_ptr->gamma) {
+                png_set_gamma (png_ptr, displaygamma, 1.0);
+                *totalgammaP = (double) displaygamma;
+                info_ptr->valid &= ~PNG_INFO_sBIT;
+                if (verbose)
+                    pm_message("image gamma assumed 1.0, "
+                               "converted for display gamma of %4.2f",
+                               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[i] != 0 &&
+                    info_ptr->trans[i] != maxval) {
+                    foundGray = TRUE;
+                }
+            }
+            retval = foundGray;
+        } else
+            retval = FALSE;
+    } else
+        retval = FALSE;
+
+    return retval;
+}
+
+
+
+static void
+setupSignificantBits(png_struct *        const png_ptr,
+                     png_info *          const info_ptr,
+                     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 'png_ptr' and 'info_ptr', with 'alpha' telling which
+  information in the PNG we care about (image or alpha mask).
+
+  Return the result as *maxvalP.
+-----------------------------------------------------------------------------*/
+    /* 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[i] != 0 && info_ptr->trans[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 (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 (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 (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(png_info * const info_ptr) {
+
+    bool retval;
+
+    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+        info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+
+        retval = FALSE;
+    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) {
+        bool foundColor;
+        unsigned int i;
+            
+        for (i = 0, foundColor = FALSE;
+             i < info_ptr->num_palette && !foundColor;
+             ++i) {
+            if (iscolor(info_ptr->palette[i]))
+                foundColor = TRUE;
+        }
+        retval = foundColor;
+    } else
+        retval = TRUE;
+
+    return retval;
+}
+
+
+
+static void
+determineOutputType(png_info *          const info_ptr,
+                    enum alpha_handling const alphaHandling,
+                    xelval              const maxval,
+                    int *               const pnmTypeP) {
+
+    if (alphaHandling != ALPHA_ONLY && imageHasColor(info_ptr))
+        *pnmTypeP = PPM_TYPE;
+    else {
+        if (maxval > 1)
+            *pnmTypeP = PGM_TYPE;
+        else
+            *pnmTypeP = PBM_TYPE;
+    }
+}
+
+
+
+static void
+getBackgroundColor(png_info *        const info_ptr,
+                   const char *      const requestedColor,
+                   float             const totalgamma,
+                   xelval            const maxval,
+                   struct 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);
+        switch (info_ptr->color_type) {
+        case PNG_COLOR_TYPE_GRAY:
+        case PNG_COLOR_TYPE_GRAY_ALPHA:
+            bgColorP->r = bgColorP->g = bgColorP->b = PNM_GET1(backcolor);
+            break;
+        case PNG_COLOR_TYPE_PALETTE:
+        case PNG_COLOR_TYPE_RGB:
+        case PNG_COLOR_TYPE_RGB_ALPHA:
+            bgColorP->r = PPM_GETR(backcolor);
+            bgColorP->g = PPM_GETG(backcolor);
+            bgColorP->b = PPM_GETB(backcolor);
+            break;
+        }
+    } else if (info_ptr->valid & 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) {
+        case PNG_COLOR_TYPE_GRAY:
+        case PNG_COLOR_TYPE_GRAY_ALPHA:
+            bgColorP->r = bgColorP->g = bgColorP->b = 
+                gamma_correct(info_ptr->background.gray, totalgamma);
+            break;
+        case PNG_COLOR_TYPE_PALETTE: {
+            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);
+        }
+        break;
+        case PNG_COLOR_TYPE_RGB:
+        case PNG_COLOR_TYPE_RGB_ALPHA: {
+            png_color_16 const rawBgcolor = 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
+writePnm(FILE *              const ofP,
+         xelval              const maxval,
+         int                 const pnm_type,
+         png_info *          const info_ptr,
+         png_byte **         const png_image,
+         pngcolor            const bgColor,
+         enum alpha_handling const alpha_handling,
+         double              const totalgamma) {
+/*----------------------------------------------------------------------------
+   Write a PNM of either the image or the alpha mask, according to
+   'alpha_handling' that is in the PNG image described by 'info_ptr' and
+   png_image.
+
+   'pnm_type' 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.
+-----------------------------------------------------------------------------*/
+    xel * xelrow;
+    unsigned int row;
+
+    if (verbose)
+        pm_message ("writing a %s file (maxval=%u)",
+                    pnm_type == PBM_TYPE ? "PBM" :
+                    pnm_type == PGM_TYPE ? "PGM" :
+                    pnm_type == PPM_TYPE ? "PPM" :
+                    "UNKNOWN!", 
+                    maxval);
+    
+    xelrow = pnm_allocrow(info_ptr->width);
+
+    pnm_writepnminit(stdout, info_ptr->width, info_ptr->height, maxval,
+                     pnm_type, FALSE);
+
+    for (row = 0; row < info_ptr->height; ++row) {
+        png_byte * png_pixelP;
+        int col;
+
+        png_pixelP = &png_image[row][0];  /* initial value */
+        for (col = 0; col < info_ptr->width; ++col) {
+            switch (info_ptr->color_type) {
+            case PNG_COLOR_TYPE_GRAY: {
+                pngcolor fgColor;
+                fgColor.r = fgColor.g = fgColor.b = get_png_val(png_pixelP);
+                setXel(&xelrow[col], fgColor, bgColor, alpha_handling,
+                       ((info_ptr->valid & PNG_INFO_tRNS) &&
+                        (fgColor.r == 
+                         gamma_correct(info_ptr->trans_values.gray,
+                                       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(png_pixelP);
+                alpha = get_png_val(png_pixelP);
+                setXel(&xelrow[col], fgColor, bgColor, alpha_handling, alpha);
+            }
+            break;
+
+            case PNG_COLOR_TYPE_PALETTE: {
+                png_uint_16 const index        = get_png_val(png_pixelP);
+                png_color   const paletteColor = info_ptr->palette[index];
+
+                pngcolor fgColor;
+
+                fgColor.r = paletteColor.red;
+                fgColor.g = paletteColor.green;
+                fgColor.b = paletteColor.blue;
+
+                setXel(&xelrow[col], fgColor, bgColor, alpha_handling,
+                       (info_ptr->valid & PNG_INFO_tRNS) &&
+                       index < info_ptr->num_trans ?
+                       info_ptr->trans[index] : maxval);
+            }
+            break;
+                
+            case PNG_COLOR_TYPE_RGB: {
+                pngcolor fgColor;
+
+                fgColor.r = get_png_val(png_pixelP);
+                fgColor.g = get_png_val(png_pixelP);
+                fgColor.b = get_png_val(png_pixelP);
+                setXel(&xelrow[col], fgColor, bgColor, alpha_handling,
+                       isTransparentColor(fgColor, info_ptr, totalgamma) ?
+                       0 : maxval);
+            }
+            break;
+
+            case PNG_COLOR_TYPE_RGB_ALPHA: {
+                pngcolor fgColor;
+                png_uint_16 alpha;
+
+                fgColor.r = get_png_val(png_pixelP);
+                fgColor.g = get_png_val(png_pixelP);
+                fgColor.b = get_png_val(png_pixelP);
+                alpha     = get_png_val(png_pixelP);
+                setXel(&xelrow[col], fgColor, bgColor, alpha_handling, alpha);
+            }
+            break;
+
+            default:
+                pm_error ("unknown PNG color type: %d", info_ptr->color_type);
+            }
+        }
+        pnm_writepnmrow(ofP, xelrow, info_ptr->width, maxval, pnm_type, FALSE);
+    }
+    pnm_freerow (xelrow);
+}
+
+
+
+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;
+    int x, y;
+    int linesize;
+    int pnm_type;
+    pngcolor bgColor;
+    float totalgamma;
+
+    *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))
+        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);
+
+    MALLOCARRAY(png_image, info_ptr->height);
+    if (png_image == NULL) {
+        png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
+        pm_closer (ifp);
+        pm_error ("couldn't allocate space for image");
+    }
+
+    if (info_ptr->bit_depth == 16)
+        linesize = 2 * info_ptr->width;
+    else
+        linesize = info_ptr->width;
+
+    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+        linesize *= 2;
+    else
+        if (info_ptr->color_type == PNG_COLOR_TYPE_RGB)
+            linesize *= 3;
+        else
+            if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+                linesize *= 4;
+
+    for (y = 0 ; y < info_ptr->height ; y++) {
+        png_image[y] = malloc (linesize);
+        if (png_image[y] == NULL) {
+            for (x = 0 ; x < y ; x++)
+                free (png_image[x]);
+            free (png_image);
+            png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
+            pm_closer (ifp);
+            pm_error ("couldn't allocate space for image");
+        }
+    }
+
+    if (info_ptr->bit_depth < 8)
+        png_set_packing (png_ptr);
+
+    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);
+
+    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);
+
+    if (mtime)
+        show_time (info_ptr);
+    if (tfp)
+        save_text (info_ptr, tfp);
+
+    if (info_ptr->valid & PNG_INFO_pHYs) {
+        float r;
+        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;
+        }
+    }
+
+    determineOutputType(info_ptr, cmdline.alpha, maxval, &pnm_type);
+
+    writePnm(stdout, maxval, pnm_type, info_ptr, png_image, bgColor, 
+             cmdline.alpha, totalgamma);
+
+    fflush(stdout);
+    for (y = 0 ; y < info_ptr->height ; y++)
+        free (png_image[y]);
+    free (png_image);
+    png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
+}
+
+
+
+int 
+main(int argc, char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE *ifp, *tfp;
+    int errorlevel;
+
+    pnm_init (&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+    mtime = cmdline.time;
+
+    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
new file mode 100644
index 00000000..bbbec099
--- /dev/null
+++ b/converter/other/pngtxt.c
@@ -0,0 +1,315 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <png.h>
+
+#include "nstring.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) {
+
+    /* Get the comment key */
+    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;
+    
+    if (textline[0] == '"') {
+        ++cursor;  /* skip past opening " */
+        while (textline[cursor] != '"') {
+            if (textline[cursor] == '\0') {
+                *cp = '\0';
+                pm_error("Invalid comment file format:  keyword contains "
+                         "a NUL character.  Text leading up to the NUL "
+                         "character is '%s'", *keyP);
+            }
+            *(cp++) = textline[cursor++];
+        }
+        ++cursor;  /* skip past closing " */
+    } else {
+        while (cursor < lineLength && 
+               textline[cursor] != ' '  && textline[cursor] != '\t' &&
+               textline[cursor] != '\0')
+            *(cp++) = textline[cursor++];
+    }
+    *cp++ = '\0';
+
+    *cursorP = cursor;
+}
+
+
+
+
+static void
+startComment(struct png_text_struct * const commentP, 
+             char                     const textline[],
+             unsigned int             const lineLength,
+             bool                     const compressed) {
+/*----------------------------------------------------------------------------
+   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.
+
+   'textline' is not NUL-terminated.  Its length is 'lineLength', and
+   it is at least one character long.  'textline' does not contain a
+   newline character.
+
+   'compressed' means the comment text is compressed.
+-----------------------------------------------------------------------------*/
+    unsigned int cursor;
+
+    /* 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;
+
+    cursor = 0;
+
+    readOffKey(textline, lineLength, &cursor, &commentP->key);
+
+    /* 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;
+    }
+}
+
+
+
+static void
+continueComment(struct png_text_struct * const commentP, 
+                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.
+
+   'textline' is not NUL-terminated.  Its length is 'lineLength', and
+   it is at least one character long.  'textline' does not contain a
+   newline character.
+-----------------------------------------------------------------------------*/
+    unsigned int cursor;  /* cursor into textline[] */
+
+    unsigned int const newTextLength =
+        commentP->text_length + lineLength + 1 + 1;
+
+    REALLOCARRAY(commentP->text, newTextLength);
+
+    if (commentP->text == NULL)
+        pm_error("Unable to allocate %u bytes of memory for comment chunk",
+                 newTextLength);
+
+    commentP->text[commentP->text_length++] = '\n';
+
+    /* Skip past leading delimiter characters in file line */
+    cursor = 0;
+    while (textline[cursor] == ' ' || textline[cursor] == '\t' ||
+           textline[cursor] == '\0')
+        ++cursor;
+
+    memcpy(commentP->text + commentP->text_length,
+           textline + cursor,
+           lineLength - cursor);
+
+    commentP->text_length += lineLength - cursor;
+
+    commentP->text[commentP->text_length] = '\0';  /* for safety */
+}
+
+
+
+static void
+getFileLine(FILE *         const fileP, 
+            const char **  const textP, 
+            unsigned int * const lengthP) {
+/*----------------------------------------------------------------------------
+   Read the next line (characters from current position through the first
+   newline character) and return it.  Put the text in newly malloc'ed 
+   storage.
+
+   Do not include the newline.
+
+   Add a terminating NUL for safety, but note that you can't rely on this
+   as the end of line marker because the line may contain a NUL.  *lengthP
+   does not include the NUL that we add.
+
+   If there are no more characters in the file, return NULL.
+-----------------------------------------------------------------------------*/
+    char * textline;  /* malloc'ed */
+    unsigned int cursor;  /* cursor into textline[] */
+    unsigned int allocated;
+        /* The number of characters of space that are allocated for
+           'textline' 
+        */
+    bool eol;
+    bool gotSomething;
+
+    allocated = 128;  /* initial value */
+
+    MALLOCARRAY(textline, allocated);
+    if (textline == NULL)
+        pm_error("Unable to allocate buffer to read a line of a file.");
+    
+    cursor = 0;
+    eol = FALSE;
+    gotSomething = FALSE;
+
+    while (!eol) {
+        int const c = getc(fileP);
+        
+        if (c != EOF)
+            gotSomething = TRUE;
+
+        if (c == '\n' || c == EOF)
+            eol = TRUE;
+        else {
+            if (cursor > allocated - 1 - 1) { /* leave space for safety NUL */
+                allocated *= 2;
+                REALLOCARRAY(textline, allocated);
+                if (textline == NULL)
+                    pm_error("Unable to allocate buffer to read a line of "
+                             "a file.");
+            }
+            textline[cursor++] = c;
+        }
+    }
+    textline[cursor] = '\0';  /* For safety; not part of line */
+
+    if (gotSomething) {
+        *textP = textline;
+        *lengthP = cursor;
+    } else {
+        free(textline);
+        *textP = NULL;
+    }
+}
+
+
+
+static void
+handleArrayAllocation(png_text **    const arrayP,
+                      unsigned int * const allocatedCommentsP,
+                      unsigned int   const commentIdx) {
+
+    if (commentIdx >= *allocatedCommentsP) {
+        *allocatedCommentsP *= 2;
+        REALLOCARRAY(*arrayP, *allocatedCommentsP);
+        if (*arrayP == NULL) 
+            pm_error("unable to allocate memory for comment array");
+    }
+}
+
+
+/******************************************************************************
+                            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;
+    bool eof;
+    unsigned int allocatedComments;
+        /* Number of entries currently allocated for the info_ptr->text
+           array 
+        */
+
+    allocatedComments = 256;  /* initial value */
+
+    MALLOCARRAY(info_ptr->text, allocatedComments);
+    if (info_ptr->text == NULL) 
+        pm_error("unable to allocate memory for comment array");
+
+    commentIdx = 0;
+    noCommentsYet = TRUE;
+   
+    eof = FALSE;
+    while (!eof) {
+        getFileLine(tfp, &textline, &lineLength);
+        if (textline == NULL)
+            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;
+
+                    startComment(&info_ptr->text[commentIdx], 
+                                 textline, lineLength, ztxt);
+                } else {
+                    /* Line starts with whitespace, which means it is
+                       a continuation of the current comment.
+                    */
+                    if (noCommentsYet)
+                        pm_error("Invalid comment file format: "
+                                 "first line is a continuation line! "
+                                 "(It starts with whitespace)");
+                    continueComment(&info_ptr->text[commentIdx], 
+                                    textline, lineLength);
+                }
+            }
+            strfree(textline);
+        }
+    } 
+    if (noCommentsYet)
+        info_ptr->num_text = 0;
+    else
+        info_ptr->num_text = commentIdx + 1;
+
+    if (verbose)
+        pm_message("%d comments placed in text chunk", info_ptr->num_text);
+}
+
+
+
diff --git a/converter/other/pngtxt.h b/converter/other/pngtxt.h
new file mode 100644
index 00000000..ae7fe2c4
--- /dev/null
+++ b/converter/other/pngtxt.h
@@ -0,0 +1,13 @@
+#ifndef PNGTXT_H_INCLUDED
+#define PNGTXT_H_INCLUDED
+
+#include "pm_c_util.h"
+#include <png.h>
+
+void 
+pnmpng_read_text (png_info * const info_ptr, 
+                  FILE *     const tfp, 
+                  bool const ztxt,
+                  bool const verbose);
+
+#endif
diff --git a/converter/other/pnmtoddif.c b/converter/other/pnmtoddif.c
new file mode 100644
index 00000000..65152865
--- /dev/null
+++ b/converter/other/pnmtoddif.c
@@ -0,0 +1,611 @@
+/*
+ * $Log: pnmtoddif.c,v $
+ * Revision 1.6  1993/01/25  08:14:06  neideck
+ * Placed into public use form.
+ *
+ * Revision 1.5  1992/12/02  08:15:18  neideck
+ *  Added RCS id.
+ *
+ */
+
+/*
+ * Author:      Burkhard Neidecker-Lutz
+ *              Digital CEC Karlsruhe
+ *      neideck@nestvx.enet.dec.com 
+
+ Copyright (c) Digital Equipment Corporation, 1992
+
+ 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, and that the name of Digital Equipment
+ Corporation not be used in advertising or publicity pertaining to
+ distribution of the software without specific, written prior
+ permission. Digital Equipment Corporation makes no representations
+ about the suitability of this software for any purpose. It is provided
+ "as is" without express or implied warranty.
+
+ Version: 1.0           30.07.92
+
+*/
+
+#include <string.h>
+#include "pnm.h"
+
+/* The structure we use to convey all sorts of "magic" data to the DDIF */
+/* header write procedure.                      */
+
+typedef struct {
+    int width;
+    int height;
+    int h_res;            /* Resolutions in dpi for bounding box */
+    int v_res;
+    int bits_per_pixel;
+    int bytes_per_line;
+    int spectral;         /* 2 == monochrome, 5 == rgb        */
+    int components;
+    int bits_per_component;
+    int polarity;         /* zeromin == 2 , zeromax == 1      */
+} imageparams;
+
+
+
+/* ASN.1 basic encoding rules magic number */
+#define UNIVERSAL 0
+#define APPLICATION 1
+#define CONTEXT 2
+#define PRIVATE 3
+
+#define PRIM 0
+#define CONS 1
+
+/* "tag": Emit an ASN tag of the specified class and tag number.    */
+/* This is used in conjuntion with the                  */
+/* wr_xxx routines that follow to construct the various ASN.1 entities. */
+/* Writing each entity is a two-step process, where first the tag is    */
+/* written and then the length and value.               */
+/* All of these routines take a pointer to a pointer into an output */
+/* buffer in the first argument and update it accordingly.      */
+
+static void tag(unsigned char ** buffer, int cl, int constructed,
+                unsigned int t)
+{
+    int tag_first;
+    unsigned int stack[10];
+    int sp;
+    unsigned char *p = *buffer;
+
+    tag_first = (cl << 6) | constructed << 5;
+    if (t < 31) {         /* Short tag form   */
+        *p++ = tag_first | t;
+    } else {          /* Long tag form */
+        *p++ = tag_first | 31;
+        sp = 0;
+        while (t > 0) {
+            stack[sp++] = t & 0x7f; 
+            t >>= 7;
+        }
+        while (--sp > 0) {  /* Tag values with continuation bits */
+            *p++ = stack[sp] | 0x80;
+        }
+        *p++ = stack[0];    /* Last tag portion without continuation bit */
+    }
+    *buffer = p;      /* Update buffer pointer */
+}
+
+
+
+/* Emit indefinite length encoding */
+static void 
+ind(unsigned char **buffer)
+{
+    unsigned char *p = *buffer;
+
+    *p++ = 0x80;
+    *buffer = p;
+}
+
+
+
+/* Emit ASN.1 NULL */
+static void 
+wr_null(unsigned char **buffer)
+{
+    unsigned char *p = *buffer;
+
+    *p++ = 0;
+    *buffer = p;
+}
+
+
+
+/* Emit ASN.1 length only into buffer, no data */
+static void 
+wr_length(unsigned char ** buffer, int amount)
+{
+    int length;
+    unsigned int mask;
+    unsigned char *p = *buffer;
+
+    length = 4;
+    mask = 0xff000000;
+
+    if (amount < 128) {
+        *p++ = amount;
+    } else {          /* > 127 */
+        while (!(amount & mask)) {  /* Search for first non-zero byte */
+            mask >>= 8;
+            --length;
+        }
+
+        *p++ = length | 0x80;       /* Number of length bytes */
+
+        while (--length >= 0) {     /* Put length bytes   */
+            *p++ =(amount >> (8*length)) & 0xff;
+        }
+
+    }
+    *buffer = p;
+}
+
+
+
+/* BER encode an integer and write it's length and value */
+static void 
+wr_int(unsigned char ** buffer, int val)
+{
+    int length;
+    int sign;
+    unsigned int mask;
+    unsigned char *p = *buffer;
+
+    if (val == 0) {
+        *p++ = 1;               /* length */
+        *p++ = 0;               /* value  */
+    } else {
+        sign = val < 0 ? 0xff : 0x00;   /* Sign bits */
+        length = 4;
+#ifdef __STDC__
+        mask  = 0xffu << 24;
+#else
+        mask  = 0xff << 24;
+#endif
+        while ((val & mask) == sign) {  /* Find the smallest representation */
+            length--;
+            mask >>= 8;
+        }
+        sign = (0x80 << ((length-1)*8)) & val; /* New sign bit */
+        if (((val < 0) && !sign) || ((val > 0) && sign)) { /* Sign error */
+            length++;
+        }
+        *p++ = length;          /* length */
+        while (--length >= 0) {
+            *p++ = (val >> (8*length)) & 0xff;
+        }
+    }
+    *buffer = p;
+}
+
+
+
+/* Emit and End Of Coding sequence  */
+static void 
+eoc(unsigned char ** buffer)
+{
+    unsigned char *p = *buffer;
+
+    *p++ = 0;
+    *p++ = 0;
+    *buffer = p;
+}
+
+
+
+/* Emit a simple string */
+static 
+void wr_string(unsigned char ** const buffer, const char * const val)
+{
+    int length;
+    unsigned char *p = *buffer;
+
+    length  = strlen(val);        
+    if (length > 127) {
+        fprintf(stderr,"Can't encode length > 127 yet (%d)\n",length);
+        exit(1);
+    }
+    *p++ = length;
+    {
+        const char * valCursor;
+        for (valCursor = val; *valCursor; ++valCursor)
+            *p++ = *valCursor;
+    }
+    *buffer = p;
+}
+
+
+
+/* Emit a ISOLATIN-1 string */
+static void 
+emit_isolatin1(unsigned char ** const buffer, const char * const val)
+{
+    int length;
+    unsigned char *p = *buffer;
+
+    length  = strlen(val) + 1;        /* One NULL byte and charset leader */
+    if (length > 127) {
+        fprintf(stderr,"Can't encode length > 127 yet (%d)\n",length);
+        exit(1);
+    }
+    *p++ = length;
+    *p++ = 1;             /* ISO LATIN-1 */
+    {
+        const char * valCursor;
+        for (valCursor = val; *valCursor; ++valCursor)
+            *p++ = *valCursor;
+    }
+    *buffer = p;
+}
+
+
+
+/* Write the DDIF grammar onto "file" up to the actual starting location */
+/* of the image data. The "ip" structure needs to be set to the right    */
+/* values. A lot of the values here are hardcoded to be just right for   */
+/* the bit grammars that the PBMPLUS formats want.           */
+
+static int 
+write_header(FILE *file, imageparams *ip)
+{
+    unsigned char buffer[300];            /* Be careful with the size ! */
+    unsigned char *p = buffer;
+    int headersize;
+    int bounding_x;
+    int bounding_y;
+    int i;
+
+    /* Calculate the bounding box from the resolutions    */
+    bounding_x = ((int) (1200 * ((double) (ip->width) / ip->h_res)));
+    bounding_y = ((int) (1200 * ((double) (ip->height) / ip->v_res)));
+
+    /* This is gross. The entire DDIF grammar is constructed by   */
+    /* hand. The indentation is meant to indicate DDIF document structure */
+
+    tag(&p,PRIVATE,CONS,16383); ind(&p);      /* DDIF Document */
+    tag(&p,CONTEXT,CONS, 0); ind(&p);        /* Document Descriptor */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1);  /* Major Version */
+    tag(&p,CONTEXT,PRIM, 1); wr_int(&p,3);  /* Minor Version */
+    tag(&p,CONTEXT,PRIM, 2); wr_string(&p,"PBM+"); /* Product Indentifier */
+    tag(&p,CONTEXT,CONS, 3); ind(&p);       /* Product Name */
+    tag(&p,PRIVATE,PRIM, 9); emit_isolatin1(&p,"PBMPLUS Writer V1.0");
+    eoc(&p);
+    eoc(&p);                 /* Document Descriptor */
+    tag(&p,CONTEXT,CONS, 1); ind(&p);        /* Document Header     */
+    tag(&p,CONTEXT,CONS, 3); ind(&p);       /* Version */
+    tag(&p,PRIVATE,PRIM, 9); emit_isolatin1(&p,"1.0");
+    eoc(&p);
+    eoc(&p);                 /* Document Header */
+    tag(&p,CONTEXT,CONS, 2); ind(&p);        /* Document Content    */
+    tag(&p,APPLICATION,CONS,2); ind(&p);    /* Segment Primitive    */
+    eoc(&p);
+    tag(&p,APPLICATION,CONS,2); ind(&p);    /* Segment  */
+    tag(&p,CONTEXT,CONS, 3); ind(&p);      /* Segment Specific Attributes */
+    tag(&p,CONTEXT,PRIM, 2); wr_string(&p,"$I");  /* Category */
+    tag(&p,CONTEXT,CONS,22); ind(&p);     /* Image Attributes */
+    tag(&p,CONTEXT,CONS, 0); ind(&p);    /* Image Presentation Attributes */
+    tag(&p,CONTEXT,PRIM, 1); wr_int(&p,0);  /* Pixel Path */
+    tag(&p,CONTEXT,PRIM, 2); wr_int(&p,270); /* Line Progression */
+    tag(&p,CONTEXT,CONS, 3); ind(&p);   /* Pixel Aspect Ratio */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1); /* PP Pixel Dist */
+    tag(&p,CONTEXT,PRIM, 1); wr_int(&p,1); /* LP Pixel Dist */
+    eoc(&p);                /* Pixel Aspect Ratio */
+    tag(&p,CONTEXT,PRIM, 4); wr_int(&p,ip->polarity);  
+        /* Brightness Polarity */
+    tag(&p,CONTEXT,PRIM, 5); wr_int(&p,1);  /* Grid Type    */
+    tag(&p,CONTEXT,PRIM, 7); wr_int(&p,ip->spectral);  /* Spectral Mapping */
+    tag(&p,CONTEXT,CONS,10); ind(&p);   /* Pixel Group Info */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1); /* Pixel Group Size */
+    tag(&p,CONTEXT,PRIM, 1); wr_int(&p,1); /* Pixel Group Order */
+    eoc(&p);                /* Pixel Group Info */
+    eoc(&p);                     /* Image Presentation Attributes */
+    tag(&p,CONTEXT,CONS, 1); ind(&p);    /* Component Space Attributes */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1);  /* Component Space Organization */
+    tag(&p,CONTEXT,PRIM, 1); wr_int(&p,1);  /* Planes per Pixel */
+    tag(&p,CONTEXT,PRIM, 2); wr_int(&p,1);  /* Plane Significance   */
+    tag(&p,CONTEXT,PRIM, 3); wr_int(&p,ip->components);  
+        /* Number of Components    */
+    tag(&p,CONTEXT,CONS, 4); ind(&p);   /* Bits per Component   */
+    for (i = 0; i < ip->components; i++) {
+        tag(&p,UNIVERSAL,PRIM,2); wr_int(&p,ip->bits_per_component);
+    }
+    eoc(&p);                /* Bits per Component   */
+    tag(&p,CONTEXT,CONS, 5); ind(&p);   /* Component Quantization Levels */
+    for (i = 0; i < ip->components; i++) {
+        tag(&p,UNIVERSAL,PRIM,2); wr_int(&p,1 << ip->bits_per_component);
+    }
+    eoc(&p);                /* Component Quantization Levels */
+    eoc(&p);                 /* Component Space Attributes */
+    eoc(&p);                  /* Image Attributes */
+    tag(&p,CONTEXT,CONS,23); ind(&p);     /* Frame Parameters */
+    tag(&p,CONTEXT,CONS, 1); ind(&p);    /* Bounding Box */
+    tag(&p,CONTEXT,CONS, 0); ind(&p);   /* lower-left   */
+    tag(&p,CONTEXT,CONS, 0); ind(&p);  /* XCoordinate  */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,0);
+    eoc(&p);                           /* XCoordinate  */
+    tag(&p,CONTEXT,CONS, 1); ind(&p);  /* YCoordinate  */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,0);
+    eoc(&p);                               /* YCoordinate  */
+    eoc(&p);                /* lower left */
+    tag(&p,CONTEXT,CONS, 1); ind(&p);       /* upper right */
+    tag(&p,CONTEXT,CONS, 0); ind(&p);      /* XCoordinate  */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,bounding_x);
+    eoc(&p);               /* XCoordinate  */
+    tag(&p,CONTEXT,CONS, 1); ind(&p);      /* YCoordinate  */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,bounding_y);
+    eoc(&p);                   /* YCoordinate  */
+    eoc(&p);                            /* upper right */
+    eoc(&p);                 /* Bounding Box */
+    tag(&p,CONTEXT,CONS, 4); ind(&p);    /* Frame Position */
+    tag(&p,CONTEXT,CONS, 0); ind(&p);   /* XCoordinate  */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,0);
+    eoc(&p);                /* XCoordinate  */
+    tag(&p,CONTEXT,CONS, 1); ind(&p);   /* YCoordinate  */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,0);
+    eoc(&p);                    /* YCoordinate  */
+    eoc(&p);                 /* Frame Position */
+    eoc(&p);                  /* Frame Parameters */
+    eoc(&p);                        /* Segment Specific Attributes */
+    eoc(&p);                    /* Segment */
+    tag(&p,APPLICATION,CONS,17); ind(&p);   /* Image Data Descriptor */
+    tag(&p,UNIVERSAL,CONS,16); ind(&p);    /* Sequence */
+    tag(&p,CONTEXT,CONS, 0); ind(&p);     /* Image Coding Attributes */
+    tag(&p,CONTEXT,PRIM, 1); wr_int(&p,ip->width); /* Pixels per Line    */
+    tag(&p,CONTEXT,PRIM, 2); wr_int(&p,ip->height);  /* Number of Lines  */
+    tag(&p,CONTEXT,PRIM, 3); wr_int(&p,2);   /* Compression Type */
+    tag(&p,CONTEXT,PRIM, 5); wr_int(&p,0);   /* Data Offset  */
+    tag(&p,CONTEXT,PRIM, 6); wr_int(&p,ip->bits_per_pixel);  /* Pixel Stride */
+    tag(&p,CONTEXT,PRIM, 7); wr_int(&p,ip->bytes_per_line * 8);
+        /* Scanline Stride    */
+    tag(&p,CONTEXT,PRIM, 8); wr_int(&p,1);   /* Bit Order        */
+    tag(&p,CONTEXT,PRIM, 9); wr_int(&p,ip->bits_per_pixel);  
+        /* Planebits per Pixel */
+    tag(&p,CONTEXT,CONS,10); ind(&p);    /* Byteorder Info   */
+    tag(&p,CONTEXT,PRIM, 0); wr_int(&p,1);  /* Byte Unit        */
+    tag(&p,CONTEXT,PRIM, 1); wr_int(&p,1);  /* Byte Order   */
+    eoc(&p);                 /* Byteorder Info   */
+    tag(&p,CONTEXT,PRIM,11); wr_int(&p,3);   /* Data Type        */
+    eoc(&p);                              /* Image Coding Attributes */
+    tag(&p,CONTEXT,PRIM, 1); wr_length(&p,ip->bytes_per_line*ip->height);  
+        /* Component Plane Data */
+    /* End of DDIF document Indentation */
+    headersize = p - buffer;
+    if (headersize >= 300)  {
+        fprintf(stderr,"Overran buffer area %d >= 300\n",headersize);
+        exit(1);
+    }
+
+    return (fwrite(buffer, 1, headersize, file) == headersize);
+}
+
+
+
+/* Write all the closing brackets of the DDIF grammar that are missing */
+/* The strange indentation reflects exactly the same indentation that  */
+/* we left off in the write_header procedure.                  */
+static int 
+write_trailer(FILE * file)
+{
+    unsigned char buffer[30];
+    unsigned char *p = buffer;
+    int trailersize;
+
+    /* Indentation below gives DDIF document structure */
+    eoc(&p);                        /* Sequence */
+    eoc(&p);                     /* Image Data Descriptor */
+    tag(&p,APPLICATION,PRIM,1); wr_null(&p);     /* End Segment */
+    tag(&p,APPLICATION,PRIM,1); wr_null(&p);     /* End Segment */
+    eoc(&p);                  /* Document Content */
+    eoc(&p);                   /* DDIF Document */
+    /* End of DDIF document Indentation */
+    trailersize = p - buffer;
+    if (trailersize >= 30)  {
+        fprintf(stderr,"Overran buffer area %d >= 30\n",trailersize);
+        exit(1);
+    }
+
+    return(fwrite(buffer, 1, trailersize, file) == trailersize);
+}
+
+
+
+int main(int argc, char *argv[])
+{
+    FILE           *ifd;
+    FILE       *ofd;
+    int             rows, cols;
+    xelval          maxval;
+    int             format;
+    const char     * const usage = "[-resolution x y] [pnmfile [ddiffile]]";
+    int             i, j;
+    char           *outfile;
+    int       argn;
+    int hor_resolution = 75;
+    int ver_resolution = 75;
+    imageparams ip;
+    unsigned char  *data, *p;
+
+    pnm_init(&argc, argv);
+
+    for (argn = 1;argn < argc && argv[argn][0] == '-';argn++) {
+        int arglen = strlen(argv[argn]);
+
+        if (!strncmp (argv[argn],"-resolution", arglen)) {
+            if (argn + 2 < argc) {
+                hor_resolution = atoi(argv[argn+1]);
+                ver_resolution = atoi(argv[argn+2]);
+                argn += 2;
+                continue;
+            } else {
+                pm_usage(usage);
+            }
+        } else {
+            pm_usage(usage);
+        }
+    }
+
+    if (hor_resolution <= 0 || ver_resolution <= 0) {
+        fprintf(stderr,"Unreasonable resolution values: %d x %d\n",
+                hor_resolution,ver_resolution);
+        exit(1);
+    }
+
+    if (argn == argc - 2) {
+        ifd = pm_openr(argv[argn]);
+        outfile = argv[argn+1];
+        if (!(ofd = fopen(outfile,"wb"))) {
+            perror(outfile);
+            exit(1);
+        }
+    } else if (argn == argc - 1) {
+        ifd = pm_openr(argv[argn]);
+        ofd = stdout;
+    } else {
+        ifd = stdin;
+        ofd = stdout;
+    }
+
+    pnm_readpnminit(ifd, &cols, &rows, &maxval, &format);
+
+    ip.width = cols;
+    ip.height = rows;
+    ip.h_res = hor_resolution;
+    ip.v_res = ver_resolution;
+
+    switch (PNM_FORMAT_TYPE(format)) {
+    case PBM_TYPE:
+        ip.bits_per_pixel = 1;
+        ip.bytes_per_line = (cols + 7) / 8;
+        ip.spectral = 2;
+        ip.components = 1;
+        ip.bits_per_component = 1;
+        ip.polarity = 1;
+        break;
+    case PGM_TYPE:
+        ip.bytes_per_line = cols;
+        ip.bits_per_pixel = 8;
+        ip.spectral = 2;
+        ip.components = 1;
+        ip.bits_per_component = 8;
+        ip.polarity = 2;
+        break;
+    case PPM_TYPE:
+        ip.bytes_per_line = 3 * cols;
+        ip.bits_per_pixel = 24;
+        ip.spectral = 5;
+        ip.components = 3;
+        ip.bits_per_component = 8;
+        ip.polarity = 2;
+        break;
+    default:
+        fprintf(stderr, "Unrecognized PBMPLUS format %d\n", format);
+        exit(1);
+    }
+
+    if (!write_header(ofd,&ip)) {
+        perror("Writing header");
+        exit(1);
+    }
+
+    if (!(p = data = (unsigned char*)  malloc(ip.bytes_per_line))) {
+        perror("allocating line buffer");
+        exit(1);
+    }
+
+    switch (PNM_FORMAT_TYPE(format)) {
+    case PBM_TYPE:
+    {
+        bit            *pixels;
+        int             mask;
+        int             k;
+
+        pixels = pbm_allocrow(cols);
+
+        for (i = 0; i < rows; i++) {
+            pbm_readpbmrow(ifd, pixels, cols, format);
+            mask = 0;
+            p = data;
+            for (j = 0, k = 0; j < cols; j++) {
+                if (pixels[j] == PBM_BLACK) {
+                    mask |= 1 << k;
+                }
+                if (k == 7) {
+                    *p++ = mask;
+                    mask = 0;
+                    k = 0;
+                } else {
+                    k++;
+                }
+            }
+            if (k != 7) {       /* Flush the rest of the column */
+                *p = mask;
+            }
+            if (fwrite(data,1,ip.bytes_per_line,ofd) != ip.bytes_per_line) {
+                perror("Writing image data\n");
+                exit(1);
+            }
+        }
+    }
+    break;
+    case PGM_TYPE:
+    {
+        gray           *pixels;
+
+        pixels = (gray *) data;
+
+        for (i = 0; i < rows; i++) {
+            pgm_readpgmrow(ifd, pixels, cols, maxval, format);
+            if (fwrite(data,1,ip.bytes_per_line,ofd) != ip.bytes_per_line) {
+                perror("Writing image data\n");
+                exit(1);
+            }
+        }
+    }
+    break;
+    case PPM_TYPE:
+    {
+        pixel          *pixels = ppm_allocrow(cols);
+
+        for (i = 0; i < rows; i++) {
+            p = data;
+            ppm_readppmrow(ifd, pixels, cols, maxval, format);
+            for (j = 0; j < cols; j++) {
+                *p++ = PPM_GETR(pixels[j]);
+                *p++ = PPM_GETG(pixels[j]);
+                *p++ = PPM_GETB(pixels[j]);
+            }
+            if (fwrite(data,1,ip.bytes_per_line,ofd) != ip.bytes_per_line) {
+                perror("Writing image data\n");
+                exit(1);
+            }
+        }
+        ppm_freerow(pixels);
+    }
+    break;
+    }
+
+    pm_close(ifd);
+
+    free(data);
+
+    if (!write_trailer(ofd)) {
+        perror("Writing trailer");
+        exit(1);
+    }
+
+    if (fclose(ofd) == EOF) {
+        perror("Closing output file");
+        exit(1);
+    };
+
+    return(0);
+}
diff --git a/converter/other/pnmtojpeg.c b/converter/other/pnmtojpeg.c
new file mode 100644
index 00000000..a0262331
--- /dev/null
+++ b/converter/other/pnmtojpeg.c
@@ -0,0 +1,1098 @@
+/*****************************************************************************
+                                pnmtojpeg
+******************************************************************************
+  This program is part of the Netpbm package.
+
+  This program converts from the PNM formats to the JFIF format
+  which is based on JPEG.
+
+  This program is by Bryan Henderson on 2000.03.06, but is derived
+  with permission from the program cjpeg, which is in the Independent
+  Jpeg Group's JPEG library package.  Under the terms of that permission,
+  redistribution of this software is restricted as described in the 
+  file README.JPEG.
+
+  Copyright (C) 1991-1998, Thomas G. Lane.
+
+*****************************************************************************/
+
+#define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include <ctype.h>		/* to declare isdigit(), etc. */
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+/* Note: jpeglib.h prerequires stdlib.h and ctype.h.  It should include them
+   itself, but doesn't.
+*/
+#include <jpeglib.h>
+#include "pnm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+
+#define EXIT_WARNING 2   /* Goes with EXIT_SUCCESS, EXIT_FAILURE in stdlib.h */
+
+enum restart_unit {RESTART_MCU, RESTART_ROW, RESTART_NONE};
+enum density_unit {DEN_UNSPECIFIED, DEN_DOTS_PER_INCH, DEN_DOTS_PER_CM};
+
+struct density {
+    enum density_unit unit;
+        /* The units of density for 'horiz', 'vert' */
+    unsigned short horiz;  /* Not 0 */
+        /* Horizontal density, in units specified by 'unit' */
+    unsigned short vert;   /* Not 0 */
+        /* Same as 'horiz', but vertical */
+};
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+     */
+    char *input_filespec;
+    unsigned int verbose;
+    unsigned int quality;
+    unsigned int force_baseline;
+    unsigned int progressive;
+    unsigned int arith_code;
+    J_DCT_METHOD dct_method;
+    unsigned int grayscale;
+    unsigned int rgb;
+    long int max_memory_to_use;
+    unsigned int trace_level;
+    char *qslots;
+    char *qtablefile;
+    char *sample;
+    char *scans;
+    int smoothing_factor;
+    unsigned int optimize;
+    unsigned int restart_value;
+    enum restart_unit restart_unit;
+    char *restart;
+    char *comment;              /* NULL if none */
+    const char *exif_filespec;  /* NULL if none */
+    unsigned int density_spec;
+        /* boolean: JFIF should specify a density.  If false, 'density'
+           is undefined.
+        */
+    struct density density;
+};
+
+static void 
+interpret_maxmemory (const char * const maxmemory, 
+                     long int * const max_memory_to_use_p) { 
+    long int lval;
+    char ch;
+    
+    if (maxmemory == NULL) {
+        *max_memory_to_use_p = -1;  /* unspecified */
+    } else if (sscanf(maxmemory, "%ld%c", &lval, &ch) < 1) {
+        pm_error("Invalid value for --maxmemory option: '%s'.", maxmemory);
+        exit(EXIT_FAILURE);
+    } else {
+        if (ch == 'm' || ch == 'M') lval *= 1000L;
+        *max_memory_to_use_p = lval * 1000L;
+    }
+}
+
+
+
+static void
+interpret_restart(const char * const restart,
+                  unsigned int * const restart_value_p,
+                  enum restart_unit * const restart_unit_p) {
+/*----------------------------------------------------------------------------
+   Interpret the restart command line option.  Return values suitable
+   for plugging into a jpeg_compress_struct to control compression.
+-----------------------------------------------------------------------------*/
+    if (restart == NULL) {
+        /* No --restart option.  Set default */
+        *restart_unit_p = RESTART_NONE;
+    } else {
+        /* Restart interval in MCU rows (or in MCUs with 'b'). */
+        long lval;
+        char ch;
+        unsigned int matches;
+        
+        matches= sscanf(restart, "%ld%c", &lval, &ch);
+        if (matches == 0) 
+            pm_error("Invalid value for the --restart option : '%s'.",
+                     restart);
+        else {
+            if (lval < 0 || lval > 65535L) {
+                pm_error("--restart value %ld is out of range.", lval);
+                exit(EXIT_FAILURE);
+            } else {
+                if (matches == 1) {
+                    *restart_value_p = lval;
+                    *restart_unit_p = RESTART_ROW;
+                } else {
+                    if (ch == 'b' || ch == 'B') {
+                        *restart_value_p = lval;
+                        *restart_unit_p = RESTART_MCU;
+                    } else pm_error("Invalid --restart value '%s'.", restart);
+                }
+            }
+        }
+    }
+}
+
+
+
+
+static void
+interpret_density(const char *        const densityString,
+                  struct density *    const densityP) {
+/*----------------------------------------------------------------------------
+   Interpret the value of the "-density" option.
+-----------------------------------------------------------------------------*/
+    if (strlen(densityString) < 1)
+        pm_error("-density value cannot be null.");
+    else {
+        char * unitName;  /* malloc'ed */
+        int matched;
+        int horiz, vert;
+
+        unitName = malloc(strlen(densityString)+1);
+    
+        matched = sscanf(densityString, "%dx%d%s", &horiz, &vert, unitName);
+
+        if (matched < 2)
+            pm_error("Invalid format for density option value '%s'.  It "
+                     "should follow the example '3x2' or '3x2dpi' or "
+                     "'3x2dpcm'.", densityString);
+        else {
+            if (horiz <= 0 || horiz >= 1<<16)
+                pm_error("Horizontal density %d is outside the range 1-65535",
+                         horiz);
+            else if (vert <= 0 || vert >= 1<<16)
+                pm_error("Vertical density %d is outside the range 1-65535",
+                         vert);
+            else {
+                densityP->horiz = horiz;
+                densityP->vert  = vert;
+
+                if (matched < 3) 
+                    densityP->unit = DEN_UNSPECIFIED;
+                else {
+                    if (streq(unitName, "dpi") || streq(unitName, "DPI"))
+                        densityP->unit = DEN_DOTS_PER_INCH;
+                    else if (streq(unitName, "dpcm") ||
+                             streq(unitName, "DPCM"))
+                        densityP->unit = DEN_DOTS_PER_CM;
+                    else
+                        pm_error("Unrecognized unit '%s' in the density value "
+                                 "'%s'.  I recognize only 'dpi' and 'dpcm'",
+                                 unitName, densityString);
+                }
+            }
+        }
+        free(unitName);
+    }
+}
+
+
+
+static void
+parseCommandLine(const int argc, char ** argv,
+                   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
+   sometimes, one of these strings is actually just a suffix of an entry
+   in argv!
+
+   On the other hand, unlike other option processing functions, we do
+   not change argv at all.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def = malloc(100*sizeof(optEntry));
+        /* Instructions to OptParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    int i;  /* local loop variable */
+
+    const char *dctval;
+    const char *maxmemory;
+    const char *restart;
+    const char *density;
+
+    unsigned int qualitySpec, smoothSpec;
+
+    unsigned int option_def_index;
+
+    int argc_parse;       /* argc, except we modify it as we parse */
+    char ** argv_parse;
+        /* argv, except we modify it as we parse */
+
+    MALLOCARRAY(argv_parse, argc);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "verbose",     OPT_FLAG,   NULL, &cmdlineP->verbose,        0);
+    OPTENT3(0, "quality",     OPT_UINT,   &cmdlineP->quality, 
+            &qualitySpec,        0);
+    OPTENT3(0, "baseline",    OPT_FLAG,   NULL, &cmdlineP->force_baseline, 0);
+    OPTENT3(0, "progressive", OPT_FLAG,   NULL, &cmdlineP->progressive,    0);
+    OPTENT3(0, "arithmetic",  OPT_FLAG,   NULL, &cmdlineP->arith_code,     0);
+    OPTENT3(0, "dct",         OPT_STRING, &dctval, NULL,                    0);
+    OPTENT3(0, "grayscale",   OPT_FLAG,   NULL, &cmdlineP->grayscale,      0);
+    OPTENT3(0, "greyscale",   OPT_FLAG,   NULL, &cmdlineP->grayscale,      0);
+    OPTENT3(0, "rgb",         OPT_FLAG,   NULL, &cmdlineP->rgb,            0);
+    OPTENT3(0, "maxmemory",   OPT_STRING, &maxmemory, NULL,                 0);
+    OPTENT3(0, "tracelevel",  OPT_UINT,   &cmdlineP->trace_level, NULL,    0);
+    OPTENT3(0, "qslots",      OPT_STRING, &cmdlineP->qslots,      NULL,    0);
+    OPTENT3(0, "qtables",     OPT_STRING, &cmdlineP->qtablefile,  NULL,    0);
+    OPTENT3(0, "sample",      OPT_STRING, &cmdlineP->sample,      NULL,    0);
+    OPTENT3(0, "scans",       OPT_STRING, &cmdlineP->scans,       NULL,    0);
+    OPTENT3(0, "smooth",      OPT_UINT,   &cmdlineP->smoothing_factor, 
+            &smoothSpec,  0);
+    OPTENT3(0, "optimize",    OPT_FLAG,   NULL, &cmdlineP->optimize,       0);
+    OPTENT3(0, "optimise",    OPT_FLAG,   NULL, &cmdlineP->optimize,       0);
+    OPTENT3(0, "restart",     OPT_STRING, &restart, NULL,                   0);
+    OPTENT3(0, "comment",     OPT_STRING, &cmdlineP->comment, NULL,        0);
+    OPTENT3(0, "exif",        OPT_STRING, &cmdlineP->exif_filespec, NULL,  0);
+    OPTENT3(0, "density",     OPT_STRING, &density, 
+            &cmdlineP->density_spec, 0);
+
+    /* Set the defaults */
+    dctval = NULL;
+    maxmemory = NULL;
+    cmdlineP->trace_level = 0;
+    cmdlineP->qslots = NULL;
+    cmdlineP->qtablefile = NULL;
+    cmdlineP->sample = NULL;
+    cmdlineP->scans = NULL;
+    restart = NULL;
+    cmdlineP->comment = NULL;
+    cmdlineP->exif_filespec = NULL;
+
+    /* Make private copy of arguments for optParseOptions to corrupt */
+    argc_parse = argc;
+    for (i=0; i < argc; i++) argv_parse[i] = argv[i];
+
+    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_parse, argv_parse, opt, sizeof(opt), 0);
+
+    if (!qualitySpec)
+        cmdlineP->quality = -1;  /* unspecified */
+
+    if (!smoothSpec)
+        cmdlineP->smoothing_factor = -1;
+
+    if (cmdlineP->rgb && cmdlineP->grayscale)
+        pm_error("You can't specify both -rgb and -grayscale");
+
+    if (argc_parse - 1 == 0)
+        cmdlineP->input_filespec = strdup("-");  /* he wants stdin */
+    else if (argc_parse - 1 == 1)
+        cmdlineP->input_filespec = strdup(argv_parse[1]);
+    else 
+        pm_error("Too many arguments.  The only argument accepted "
+                 "is the input file specification.");
+    if (dctval == NULL)
+        cmdlineP->dct_method = JDCT_DEFAULT;
+    else {
+        if (streq(dctval, "int"))
+            cmdlineP->dct_method = JDCT_ISLOW;
+        else if (streq(dctval, "fast"))
+            cmdlineP->dct_method = JDCT_IFAST;
+        else if (streq(dctval, "float"))
+            cmdlineP->dct_method = JDCT_FLOAT;
+        else
+            pm_error("Invalid value for the --dct option: '%s'.", dctval);
+    }
+
+    interpret_maxmemory(maxmemory, &cmdlineP->max_memory_to_use);
+    interpret_restart(restart, &cmdlineP->restart_value,
+                      &cmdlineP->restart_unit);
+    if (cmdlineP->density_spec) 
+        interpret_density(density, &cmdlineP->density);
+    
+    if (cmdlineP->smoothing_factor > 100)
+        pm_error("Smoothing factor %d is greater than 100 (%%).",
+                 cmdlineP->smoothing_factor);
+
+    if (streq(cmdlineP->input_filespec, "=") &&
+        cmdlineP->exif_filespec && 
+        streq(cmdlineP->exif_filespec, "-"))
+
+        pm_error("Cannot have both input image and exif header be from "
+                 "Standard Input.");
+
+
+    free(argv_parse);
+}
+
+
+static void
+compute_rescaling_array(JSAMPLE ** const rescale_p, const pixval maxval,
+                        const struct jpeg_compress_struct cinfo);
+static void
+convert_scanlines(struct jpeg_compress_struct *cinfo_p, FILE *input_file,
+                  const pixval maxval, const int input_fmt,
+                  JSAMPLE xlate_table[]);
+
+static boolean read_quant_tables (j_compress_ptr cinfo, char * filename,
+                                  int scale_factor, boolean force_baseline);
+
+static boolean read_scan_script (j_compress_ptr cinfo, char * filename);
+
+static boolean set_quant_slots (j_compress_ptr cinfo, char *arg);
+
+static boolean set_sample_factors (j_compress_ptr cinfo, char *arg);
+
+
+static void
+report_compressor(const struct jpeg_compress_struct cinfo) {
+    
+    if (cinfo.scan_info == NULL)
+        pm_message("No scan script is being used");
+    else {
+        int i;
+        pm_message("A scan script with %d entries is being used:",
+                   cinfo.num_scans);
+        for (i = 0; i < cinfo.num_scans; i++) {
+            int j;
+            pm_message("    Scan %2d: Ss=%2d Se=%2d Ah=%2d Al=%2d  "
+                       "%d components", 
+                       i,
+                       cinfo.scan_info[i].Ss,
+                       cinfo.scan_info[i].Se,
+                       cinfo.scan_info[i].Ah,
+                       cinfo.scan_info[i].Al,
+                       cinfo.scan_info[i].comps_in_scan
+                       );
+            for (j = 0; j < cinfo.scan_info[i].comps_in_scan; j++)
+                pm_message("        Color component %d index: %d", j,
+                           cinfo.scan_info[i].component_index[j]);
+        }
+    }
+}
+
+
+
+static void
+setup_jpeg_source_parameters(struct jpeg_compress_struct * const cinfoP, 
+                             int const width, int const height, 
+                             int const format) {
+/*----------------------------------------------------------------------------
+   Set up in the compressor descriptor *cinfoP the description of the 
+   source image as required by the compressor.
+-----------------------------------------------------------------------------*/
+
+    switch PNM_FORMAT_TYPE(format) {
+    case PBM_TYPE:
+    case PGM_TYPE:
+        cinfoP->in_color_space = JCS_GRAYSCALE;
+        cinfoP->input_components = 1;
+        break;
+    case PPM_TYPE:
+        cinfoP->in_color_space = JCS_RGB; 
+        cinfoP->input_components = 3;
+        break;
+    default:
+        pm_error("INTERNAL ERROR; invalid format in "
+                 "setup_jpeg_source_parameters()");
+    }
+}
+
+
+
+static void
+setup_jpeg_density(struct jpeg_compress_struct * const cinfoP, 
+                   struct density                const density) {
+/*----------------------------------------------------------------------------
+   Set up in the compressor descriptor *cinfoP the density information
+   'density'.
+-----------------------------------------------------------------------------*/
+    switch(density.unit) {
+    case DEN_UNSPECIFIED:   cinfoP->density_unit = 0; break;
+    case DEN_DOTS_PER_INCH: cinfoP->density_unit = 1; break;
+    case DEN_DOTS_PER_CM:   cinfoP->density_unit = 2; break;
+    }
+    
+    cinfoP->X_density = density.horiz;
+    cinfoP->Y_density = density.vert;
+}
+
+
+
+static void
+setup_jpeg(struct jpeg_compress_struct * const cinfoP,
+           struct jpeg_error_mgr       * const jerrP,
+           struct cmdlineInfo            const cmdline, 
+           int                           const width,
+           int                           const height,
+           pixval                        const maxval,
+           int                           const input_fmt,
+           FILE *                        const output_file) {
+  
+    int quality;
+    int q_scale_factor;
+
+    /* Initialize the JPEG compression object with default error handling. */
+    cinfoP->err = jpeg_std_error(jerrP);
+    jpeg_create_compress(cinfoP);
+
+    setup_jpeg_source_parameters(cinfoP, width, height, input_fmt);
+
+    jpeg_set_defaults(cinfoP);
+
+    cinfoP->data_precision = BITS_IN_JSAMPLE; 
+        /* we always rescale data to this */
+    cinfoP->image_width = (unsigned int) width;
+    cinfoP->image_height = (unsigned int) height;
+
+    cinfoP->arith_code = cmdline.arith_code;
+    cinfoP->dct_method = cmdline.dct_method;
+    if (cmdline.trace_level == 0 && cmdline.verbose) 
+        cinfoP->err->trace_level = 1;
+    else cinfoP->err->trace_level = cmdline.trace_level;
+    if (cmdline.grayscale)
+        jpeg_set_colorspace(cinfoP, JCS_GRAYSCALE);
+    else if (cmdline.rgb)
+        /* This is not legal if the input is not JCS_RGB too, i.e. it's PPM */
+        jpeg_set_colorspace(cinfoP, JCS_RGB);
+    else
+        /* This default will be based on the in_color_space set above */
+        jpeg_default_colorspace(cinfoP);
+    if (cmdline.max_memory_to_use != -1)
+        cinfoP->mem->max_memory_to_use = cmdline.max_memory_to_use;
+    cinfoP->optimize_coding = cmdline.optimize;
+    if (cmdline.quality == -1) {
+        quality = 75;
+        q_scale_factor = 100;
+    } else {
+        quality = cmdline.quality;
+        q_scale_factor = jpeg_quality_scaling(cmdline.quality);
+    }
+    if (cmdline.smoothing_factor != -1) 
+        cinfoP->smoothing_factor = cmdline.smoothing_factor;
+
+    /* Set quantization tables for selected quality. */
+    /* Some or all may be overridden if user specified --qtables. */
+    jpeg_set_quality(cinfoP, quality, cmdline.force_baseline);
+                   
+    if (cmdline.qtablefile != NULL) {
+        if (! read_quant_tables(cinfoP, cmdline.qtablefile,
+                                q_scale_factor, cmdline.force_baseline)) 
+            pm_error("Can't use quantization table file '%s'.",
+                     cmdline.qtablefile);
+    }
+   
+    if (cmdline.qslots != NULL) {
+        if (! set_quant_slots(cinfoP, cmdline.qslots))
+            pm_error("Bad quantization-table-selectors parameter string '%s'.", 
+                     cmdline.qslots);
+    }
+          
+    if (cmdline.sample != NULL) {
+        if (! set_sample_factors(cinfoP, cmdline.sample))
+            pm_error("Bad sample-factors parameters string '%s'.",
+                     cmdline.sample);
+    }
+
+    if (cmdline.progressive)
+        jpeg_simple_progression(cinfoP);
+
+    if (cmdline.density_spec)
+        setup_jpeg_density(cinfoP, cmdline.density);
+
+    if (cmdline.scans != NULL) {
+        if (! read_scan_script(cinfoP, cmdline.scans)) {
+            pm_message("Error in scan script '%s'.", cmdline.scans);
+        }
+    }
+
+    /* Specify data destination for compression */
+    jpeg_stdio_dest(cinfoP, output_file);
+
+    if (cmdline.verbose) report_compressor(*cinfoP);
+
+    /* Start compressor */
+    jpeg_start_compress(cinfoP, TRUE);
+
+}
+
+
+
+static void
+write_exif_header(struct jpeg_compress_struct * const cinfoP,
+                  const char * const exif_filespec) {
+/*----------------------------------------------------------------------------
+   Generate an APP1 marker in the JFIF output that is an Exif header.
+
+   The contents of the Exif header are in the file with filespec 
+   'exif_filespec' (file spec and contents are not validated).
+
+   exif_filespec = "-" means Standard Input.
+
+   If the file contains just two bytes of zero, don't write any marker
+   but don't recognize any error either.
+-----------------------------------------------------------------------------*/
+    FILE * exif_file;
+    unsigned short length;
+    
+    exif_file = pm_openr(exif_filespec);
+
+    pm_readbigshort(exif_file, (short*)&length);
+
+    if (length == 0) {
+        /* Special value meaning "no header" */
+    } else if (length < 3)
+        pm_error("Invalid length %u at start of exif file", length);
+    else {
+        unsigned char * exif_data;
+        int rc;
+        size_t const data_length = length - 2;  
+            /* Subtract 2 byte length field*/
+
+        assert(data_length > 0);
+
+        exif_data = malloc(data_length);
+        if (exif_data == NULL)
+            pm_error("Unable to allocate %d bytes for exif header buffer",
+                     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);
+
+        jpeg_write_marker(cinfoP, JPEG_APP0+1, 
+                          (const JOCTET *) exif_data, data_length);
+
+        free(exif_data);
+    }
+    
+    pm_close(exif_file);
+}
+
+                  
+
+static void
+compute_rescaling_array(JSAMPLE ** const rescale_p, const pixval maxval,
+                        const struct jpeg_compress_struct cinfo) {
+/*----------------------------------------------------------------------------
+   Compute the rescaling array for a maximum pixval of 'maxval'.
+   Allocate the memory for it too.
+-----------------------------------------------------------------------------*/
+  const long half_maxval = maxval / 2;
+  long val;
+
+  *rescale_p = (JSAMPLE *)
+    (cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
+                              (size_t) (((long) maxval + 1L) * 
+                                        sizeof(JSAMPLE)));
+  for (val = 0; val <= maxval; val++) {
+    /* The multiplication here must be done in 32 bits to avoid overflow */
+    (*rescale_p)[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval);
+  }
+}
+
+
+
+static void
+translate_row(const pixel pnm_buffer[], 
+              JSAMPLE jpeg_buffer[], 
+              int const width, 
+              int const input_components,
+              const JSAMPLE translate[]) {
+/*----------------------------------------------------------------------------
+   Convert the input row, in pnm format, to an output row in JPEG compressor
+   input format.
+
+   This is a byte for byte copy, translated through the array 'translate'.
+-----------------------------------------------------------------------------*/
+  unsigned int column;
+  /* I'm not sure why the JPEG library data structures don't have some kind
+     of pixel data structure (such that a row buffer is an array of pixels,
+     rather than an array of samples).  But because of this, we have to
+     index jpeg_buffer the old fashioned way.
+     */
+
+  switch (input_components) {
+  case 1:
+      for (column = 0; column < width; column++) 
+          jpeg_buffer[column] = translate[(int)PNM_GET1(pnm_buffer[column])];
+      break;
+  case 3:
+      for (column = 0; column < width; column++) {
+          jpeg_buffer[column*3+0] = 
+              translate[(int)PPM_GETR(pnm_buffer[column])];
+          jpeg_buffer[column*3+1] = 
+              translate[(int)PPM_GETG(pnm_buffer[column])];
+          jpeg_buffer[column*3+2] = 
+              translate[(int)PPM_GETB(pnm_buffer[column])];
+      }
+      break;
+  default:
+      pm_error("INTERNAL ERROR: invalid number of input components in "
+               "translate_row()");
+  }
+
+}
+
+
+
+static void
+convert_scanlines(struct jpeg_compress_struct * const cinfo_p,
+                  FILE *                        const input_file,
+                  pixval                        const maxval,
+                  int                           const input_fmt,
+                  JSAMPLE                             xlate_table[]){
+/*----------------------------------------------------------------------------
+   Read scan lines from the input file, which is already opened in the 
+   netpbm library sense and ready for reading, and write them to the 
+   output JPEG object.  Translate the pnm sample values to JPEG sample
+   values through the thable xlate_table[].
+-----------------------------------------------------------------------------*/
+  xel * pnm_buffer;  
+    /* contains the row of the input image currently being processed,
+       in pnm_readpnmrow format
+    */
+  JSAMPARRAY buffer;
+    /* Row 0 of this array contains the row of the output image currently 
+       being processed, in JPEG compressor input format.  The array only
+       has that one row.
+    */
+
+  /* Allocate the libpnm output and compressor input buffers */
+  buffer = (*cinfo_p->mem->alloc_sarray)
+    ((j_common_ptr) cinfo_p, JPOOL_IMAGE,
+     (unsigned int) cinfo_p->image_width * cinfo_p->input_components, 
+     (unsigned int) 1);
+  
+  pnm_buffer = pnm_allocrow(cinfo_p->image_width);
+
+  while (cinfo_p->next_scanline < cinfo_p->image_height) {
+    if (cinfo_p->err->trace_level > 1) 
+        pm_message("Converting Row %d...", cinfo_p->next_scanline);
+    pnm_readpnmrow(input_file, pnm_buffer, cinfo_p->image_width, 
+                   maxval, input_fmt);
+    translate_row(pnm_buffer, buffer[0], 
+                  cinfo_p->image_width, cinfo_p->input_components,
+                  xlate_table);
+    jpeg_write_scanlines(cinfo_p, buffer, 1);
+    if (cinfo_p->err->trace_level > 1) 
+        pm_message("Done.");
+  }
+
+  pnm_freerow(pnm_buffer);
+  /* Dont' worry about the compressor input buffer; it gets freed 
+     automatically
+  */
+
+}
+
+/*----------------------------------------------------------------------------
+   The functions below here are essentially the file rdswitch.c from
+   the JPEG library.  They perform the functions specifed by the following
+   pnmtojpeg options:
+
+   -qtables file          Read quantization tables from text file
+   -scans file            Read scan script from text file
+   -qslots N[,N,...]      Set component quantization table selectors
+   -sample HxV[,HxV,...]  Set component sampling factors
+-----------------------------------------------------------------------------*/
+
+static int
+text_getc (FILE * file)
+/* Read next char, skipping over any comments (# to end of line) */
+/* A comment/newline sequence is returned as a newline */
+{
+    register int ch;
+  
+    ch = getc(file);
+    if (ch == '#') {
+        do {
+            ch = getc(file);
+        } while (ch != '\n' && ch != EOF);
+    }
+    return ch;
+}
+
+
+static boolean
+read_text_integer (FILE * file, long * result, int * termchar)
+/* Read an unsigned decimal integer from a file, store it in result */
+/* Reads one trailing character after the integer; returns it in termchar */
+{
+    register int ch;
+    register long val;
+  
+    /* Skip any leading whitespace, detect EOF */
+    do {
+        ch = text_getc(file);
+        if (ch == EOF) {
+            *termchar = ch;
+            return FALSE;
+        }
+    } while (isspace(ch));
+  
+    if (! isdigit(ch)) {
+        *termchar = ch;
+        return FALSE;
+    }
+
+    val = ch - '0';
+    while ((ch = text_getc(file)) != EOF) {
+        if (! isdigit(ch))
+            break;
+        val *= 10;
+        val += ch - '0';
+    }
+    *result = val;
+    *termchar = ch;
+    return TRUE;
+}
+
+
+static boolean
+read_quant_tables (j_compress_ptr cinfo, char * filename,
+                   int scale_factor, boolean force_baseline)
+/* Read a set of quantization tables from the specified file.
+ * The file is plain ASCII text: decimal numbers with whitespace between.
+ * Comments preceded by '#' may be included in the file.
+ * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
+ * The tables are implicitly numbered 0,1,etc.
+ * NOTE: does not affect the qslots mapping, which will default to selecting
+ * table 0 for luminance (or primary) components, 1 for chrominance components.
+ * You must use -qslots if you want a different component->table mapping.
+ */
+{
+    FILE * fp;
+    int tblno, i, termchar;
+    long val;
+    unsigned int table[DCTSIZE2];
+
+    if ((fp = fopen(filename, "rb")) == NULL) {
+        pm_message("Can't open table file %s", filename);
+        return FALSE;
+    }
+    tblno = 0;
+
+    while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
+        if (tblno >= NUM_QUANT_TBLS) {
+            pm_message("Too many tables in file %s", filename);
+            fclose(fp);
+            return FALSE;
+        }
+        table[0] = (unsigned int) val;
+        for (i = 1; i < DCTSIZE2; i++) {
+            if (! read_text_integer(fp, &val, &termchar)) {
+                pm_message("Invalid table data in file %s", filename);
+                fclose(fp);
+                return FALSE;
+            }
+            table[i] = (unsigned int) val;
+        }
+        jpeg_add_quant_table(cinfo, tblno, table, scale_factor, 
+                             force_baseline);
+        tblno++;
+    }
+
+    if (termchar != EOF) {
+        pm_message("Non-numeric data in file %s", filename);
+        fclose(fp);
+        return FALSE;
+    }
+
+    fclose(fp);
+    return TRUE;
+}
+
+
+static boolean
+read_scan_integer (FILE * file, long * result, int * termchar)
+/* Variant of read_text_integer that always looks for a non-space termchar;
+ * this simplifies parsing of punctuation in scan scripts.
+ */
+{
+    register int ch;
+
+    if (! read_text_integer(file, result, termchar))
+        return FALSE;
+    ch = *termchar;
+    while (ch != EOF && isspace(ch))
+        ch = text_getc(file);
+    if (isdigit(ch)) {		/* oops, put it back */
+        if (ungetc(ch, file) == EOF)
+            return FALSE;
+        ch = ' ';
+    } else {
+        /* Any separators other than ';' and ':' are ignored;
+         * this allows user to insert commas, etc, if desired.
+         */
+        if (ch != EOF && ch != ';' && ch != ':')
+            ch = ' ';
+    }
+    *termchar = ch;
+    return TRUE;
+}
+
+
+boolean
+read_scan_script (j_compress_ptr cinfo, char * filename)
+/* Read a scan script from the specified text file.
+ * Each entry in the file defines one scan to be emitted.
+ * Entries are separated by semicolons ';'.
+ * An entry contains one to four component indexes,
+ * optionally followed by a colon ':' and four progressive-JPEG parameters.
+ * The component indexes denote which component(s) are to be transmitted
+ * in the current scan.  The first component has index 0.
+ * Sequential JPEG is used if the progressive-JPEG parameters are omitted.
+ * The file is free format text: any whitespace may appear between numbers
+ * and the ':' and ';' punctuation marks.  Also, other punctuation (such
+ * as commas or dashes) can be placed between numbers if desired.
+ * Comments preceded by '#' may be included in the file.
+ * Note: we do very little validity checking here;
+ * jcmaster.c will validate the script parameters.
+ */
+{
+    FILE * fp;
+    int nscans, ncomps, termchar;
+    long val;
+#define MAX_SCANS  100      /* quite arbitrary limit */
+    jpeg_scan_info scans[MAX_SCANS];
+
+    if ((fp = fopen(filename, "r")) == NULL) {
+        pm_message("Can't open scan definition file %s", filename);
+        return FALSE;
+    }
+    nscans = 0;
+
+    while (read_scan_integer(fp, &val, &termchar)) {
+        nscans++;  /* We got another scan */
+        if (nscans > MAX_SCANS) {
+            pm_message("Too many scans defined in file %s", filename);
+            fclose(fp);
+            return FALSE;
+        }
+        scans[nscans-1].component_index[0] = (int) val;
+        ncomps = 1;
+        while (termchar == ' ') {
+            if (ncomps >= MAX_COMPS_IN_SCAN) {
+                pm_message("Too many components in one scan in file %s", 
+                           filename);
+                fclose(fp);
+                return FALSE;
+            }
+            if (! read_scan_integer(fp, &val, &termchar))
+                goto bogus;
+            scans[nscans-1].component_index[ncomps] = (int) val;
+            ncomps++;
+        }
+        scans[nscans-1].comps_in_scan = ncomps;
+        if (termchar == ':') {
+            if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+                goto bogus;
+            scans[nscans-1].Ss = (int) val;
+            if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+                goto bogus;
+            scans[nscans-1].Se = (int) val;
+            if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+                goto bogus;
+            scans[nscans-1].Ah = (int) val;
+            if (! read_scan_integer(fp, &val, &termchar))
+                goto bogus;
+            scans[nscans-1].Al = (int) val;
+        } else {
+            /* set non-progressive parameters */
+            scans[nscans-1].Ss = 0;
+            scans[nscans-1].Se = DCTSIZE2-1;
+            scans[nscans-1].Ah = 0;
+            scans[nscans-1].Al = 0;
+        }
+        if (termchar != ';' && termchar != EOF) {
+        bogus:
+            pm_message("Invalid scan entry format in file %s", filename);
+            fclose(fp);
+            return FALSE;
+        }
+    }
+
+    if (termchar != EOF) {
+        pm_message("Non-numeric data in file %s", filename);
+        fclose(fp);
+        return FALSE;
+    }
+
+    if (nscans > 0) {
+        /* Stash completed scan list in cinfo structure.  NOTE: in
+         * this program, JPOOL_IMAGE is the right lifetime for this
+         * data, but if you want to compress multiple images you'd
+         * want JPOOL_PERMANENT.  
+         */
+        const unsigned int scan_info_size = nscans * sizeof(jpeg_scan_info);
+        jpeg_scan_info * const scan_info = 
+            (jpeg_scan_info *)
+            (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+                                        scan_info_size);
+        memcpy(scan_info, scans, scan_info_size);
+        cinfo->scan_info = scan_info;
+        cinfo->num_scans = nscans;
+    }
+
+    fclose(fp);
+    return TRUE;
+}
+
+
+static boolean
+set_quant_slots (j_compress_ptr cinfo, char *arg)
+/* Process a quantization-table-selectors parameter string, of the form
+ *     N[,N,...]
+ * If there are more components than parameters, the last value is replicated.
+ */
+{
+    int val = 0;			/* default table # */
+    int ci;
+    char ch;
+
+    for (ci = 0; ci < MAX_COMPONENTS; ci++) {
+        if (*arg) {
+            ch = ',';			/* if not set by sscanf, will be ',' */
+            if (sscanf(arg, "%d%c", &val, &ch) < 1)
+                return FALSE;
+            if (ch != ',')		/* syntax check */
+                return FALSE;
+            if (val < 0 || val >= NUM_QUANT_TBLS) {
+                pm_message("Invalid quantization table number: %d.  "
+                           "JPEG quantization tables are numbered 0..%d",
+                           val, NUM_QUANT_TBLS - 1);
+                return FALSE;
+            }
+            cinfo->comp_info[ci].quant_tbl_no = val;
+            while (*arg && *arg++ != ',') 
+                /* advance to next segment of arg string */
+                ;
+        } else {
+            /* reached end of parameter, set remaining components to last tbl*/
+            cinfo->comp_info[ci].quant_tbl_no = val;
+        }
+    }
+    return TRUE;
+}
+
+
+static boolean
+set_sample_factors (j_compress_ptr cinfo, char *arg)
+/* Process a sample-factors parameter string, of the form
+ *     HxV[,HxV,...]
+ * If there are more components than parameters, "1x1" is assumed for the rest.
+ */
+{
+    int ci, val1, val2;
+    char ch1, ch2;
+
+    for (ci = 0; ci < MAX_COMPONENTS; ci++) {
+        if (*arg) {
+            ch2 = ',';		/* if not set by sscanf, will be ',' */
+            if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
+                return FALSE;
+            if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
+                return FALSE;
+            if (val1 <= 0 || val1 > 4) {
+                pm_message("Invalid sampling factor: %d.  " 
+                           "JPEG sampling factors must be 1..4", val1);
+                return FALSE;
+            }
+            if (val2 <= 0 || val2 > 4) {
+                pm_message("Invalid sampling factor: %d.  "
+                           "JPEG sampling factors must be 1..4", val2);
+                return FALSE;
+            }
+            cinfo->comp_info[ci].h_samp_factor = val1;
+            cinfo->comp_info[ci].v_samp_factor = val2;
+            while (*arg && *arg++ != ',') 
+                /* advance to next segment of arg string */
+                ;
+        } else {
+            /* reached end of parameter, set remaining components 
+               to 1x1 sampling */
+            cinfo->comp_info[ci].h_samp_factor = 1;
+            cinfo->comp_info[ci].v_samp_factor = 1;
+        }
+    }
+    return TRUE;
+}
+
+
+
+int
+main(int argc, char ** argv) {
+
+    struct cmdlineInfo cmdline;
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    FILE *input_file;
+    FILE * output_file;
+    int height;  
+        /* height of the input image in rows, as specified by its header */
+    int width;   
+        /* width of the input image in columns, as specified by its header */
+    pixval maxval;  
+        /* maximum value of an input pixel component, as specified by header */
+    int input_fmt;
+        /* The input format, as determined by its header.  */
+    JSAMPLE *rescale;         /* => maxval-remapping array, or NULL */
+        /* This is an array that maps each possible pixval in the input to
+           a new value such that while the range of the input values is
+           0 .. maxval, the range of the output values is 0 .. MAXJSAMPLE.
+        */
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    input_file = pm_openr(cmdline.input_filespec);
+    free(cmdline.input_filespec);
+
+    output_file = stdout;
+
+    /* Open the pnm input */
+    pnm_readpnminit(input_file, &width, &height, &maxval, &input_fmt);
+    if (cmdline.verbose) {
+        pm_message("Input file has format %c%c.\n"
+                   "It has %d rows of %d columns of pixels "
+                   "with max sample value of %d.", 
+                   (char) (input_fmt/256), (char) (input_fmt % 256),
+                   height, width, maxval);
+    }
+
+    setup_jpeg(&cinfo, &jerr, cmdline, width, height, maxval, input_fmt,
+               output_file);
+
+    compute_rescaling_array(&rescale, maxval, cinfo);
+
+    if (cmdline.comment) 
+        jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *) cmdline.comment, 
+                          strlen(cmdline.comment));
+
+    if (cmdline.exif_filespec)
+        write_exif_header(&cinfo, cmdline.exif_filespec);
+    
+    /* Translate and copy over the actual scanlines */
+    convert_scanlines(&cinfo, input_file, maxval, input_fmt, rescale);
+
+    /* Finish compression and release memory */
+    jpeg_finish_compress(&cinfo);
+    jpeg_destroy_compress(&cinfo);
+
+    /* Close files, if we opened them */
+    if (input_file != stdin)
+        fclose(input_file);
+
+    /* Program may have exited with non-zero completion code via
+       various function calls above. 
+    */
+    return jerr.num_warnings > 0 ? EXIT_WARNING : EXIT_SUCCESS;
+}
diff --git a/converter/other/pnmtopalm/LICENSE b/converter/other/pnmtopalm/LICENSE
new file mode 100644
index 00000000..740b6080
--- /dev/null
+++ b/converter/other/pnmtopalm/LICENSE
@@ -0,0 +1,16 @@
+LICENSE FOR PNMTOPALM SUBPACKAGE OF NETPBM.  THIS LICENSE APPLIES TO ALL
+THE MATERIALS IN THE PNMTOPALM DIRECTORY OF THE NETPBM SOURCE PACKAGE.
+
+Copyright 1995-2001 by Ian Goldberg, George Caswell, and Bill Janssen.
+
+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.
+
+
+(Bryan Henderson extracted this license memorandum from the comments in the
+original man page nroff source supplied to him with the rest of the Pnmtopalm
+package in January 2001 by Bill Janssen).
diff --git a/converter/other/pnmtopalm/Makefile b/converter/other/pnmtopalm/Makefile
new file mode 100644
index 00000000..2a76297e
--- /dev/null
+++ b/converter/other/pnmtopalm/Makefile
@@ -0,0 +1,35 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/other/pnmtopalm
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+BINARIES = palmtopnm pnmtopalm
+SCRIPTS =
+OBJECTS = $(BINARIES:%=%.o) palmcolormap.o
+MERGE_OBJECTS = $(BINARIES:%=%.o2) palmcolormap.o
+MERGEBINARIES = $(BINARIES)
+DATAFILES = palmcolor8.map palmgray1.map palmgray2.map palmgray4.map
+
+all: $(BINARIES)
+
+include $(SRCDIR)/Makefile.common
+
+LIBOPTS = $(shell $(LIBOPT) $(NETPBMLIB))
+
+$(BINARIES): %: %.o palmcolormap.o $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o $@ $< palmcolormap.o $(LIBOPTS) \
+	  $(MATHLIB) $(LDLIBS) $(RPATH) $(LADD)
+
+gen_palm_colormap : $(SUBDIR)/gen_palm_colormap.c palmcolormap.o
+	$(CC) $(INCLUDES) $(CFLAGS) $(LDFLAGS) -o $@ $< palmcolormap.o \
+	  $(LIBOPTS) $(MATHLIB) $(LDLIBS) $(LADD)
+
+
+clean: cleanspecial
+.PHONY: cleanspecial
+cleanspecial:
+	rm -f gen_palm_colormap
diff --git a/converter/other/pnmtopalm/README b/converter/other/pnmtopalm/README
new file mode 100644
index 00000000..ebae9492
--- /dev/null
+++ b/converter/other/pnmtopalm/README
@@ -0,0 +1,57 @@
+This is version 1.0 of pnmpalm, netpbm converters for Palm pixmaps.
+
+It's derived from version 1.0 of ppmtoTbmp.  The original 'ppmtoTbmp'
+program has been renamed 'pnmtopalm', and has been rewritten to handle
+the various bitmaps that exist as of PalmOS 3.5, and to handle
+colormaps, a transparent color, and the various compression formats
+recognized by Palm OS.  The 'Tbmptopnm' program is now 'palmtopnm',
+and has been updated to handle the various newer bitmap formats as
+well.  Man pages for 'pnmtopalm' and 'palmtopnm' have been added.  See
+those man pages for more information.  Note that command-line switches
+have changed.
+
+As with Tbmptoppm, ppm images must be quantified properly before
+being passed to pnmtopalm.  Several colormap files are provided to
+use for this:
+ - palmgray1.map -- 1-bit grayscale (i.e. monochrome)
+ - palmgray2.map -- 2-bit grayscale
+ - palmgray4.map -- 4-bit grayscale
+ - palmcolor8.map -- 8-bit color, using the default color palette
+
+-- Bill Janssen  <bill@janssen.org>
+
+
+One source of information on Palm image formats is
+http://www.kawt.de/doc/palmimages.html.
+
+
+
+The original ppmtoTbmp README read as follows:
+
+This is version 1.0 of ppmtoTbmp, a ppm to Pilot bitmap converter.
+
+To compile it, you'll need the netpbm package.  Last I checked, it was
+available at "ftp://ftp.x.org/contrib/utilities/netpbm-1mar1994.p1.tar.gz".
+Change the Makefile to point to the directory that contains the netpbm
+header files, and make.
+
+Usage: ppmtoTbmp [-2bit] [file.ppm]
+
+If the ppm file is not specified, one is read from stdin.  The -2bit option
+produces a 2-bit bitmap instead of the normal 1-bit bitmap.  The ppm must
+have at most 4 colors in it (for 2-bit) or at most 2 colors (for 1-bit).
+Common invokations might be:
+
+xbmtopbm icon.xbm | ppmquant -fs -map q2.map | ppmtoTbmp > tAIB03e8.bin
+giftopnm image.gif | ppmquant -fs -map q4.map | ppmtoTbmp -2bit > Tbmp0bb8.bin
+
+(q2.map and q4.map are trivial 2 and 4 color maps, respectively, and are
+included in this distribution.)
+
+To include the resulting bitmap in a .prc file, just name the output
+tAIB03e8.bin (for an application icon) or Tbmpxxxx.bin (for a form bitmap,
+where xxxx is replaced by four hex digits giving the bitmap ID).
+
+I'll probably make Tbmptopnm later, and put it in the 1.1 release.
+
+   - Ian Goldberg <iang@cs.berkeley.edu>
diff --git a/converter/other/pnmtopalm/gen_palm_colormap.c b/converter/other/pnmtopalm/gen_palm_colormap.c
new file mode 100644
index 00000000..4b65e631
--- /dev/null
+++ b/converter/other/pnmtopalm/gen_palm_colormap.c
@@ -0,0 +1,24 @@
+/* gen_palm_colormap.c - generate a ppm file containing the default Palm colormap
+ *
+ * Bill Janssen  <bill@janssen.org>
+ */
+
+#include "pnm.h"
+
+#include "palm.h"
+
+int main( int argc, char **argv ) {
+
+  int i;
+  Color_s current;
+  Colormap default_map = palmcolor_build_default_8bit_colormap ();
+
+  printf("P3\n%d 1\n255\n", default_map->ncolors);
+  for (i = 0;  i < default_map->ncolors;  i++) {
+    current = default_map->color_entries[i];
+    printf ("%d %d %d\n", (current & 0xFF0000) >> 16, (current & 0xFF00) >> 8, (current & 0xFF));
+    /* printf ("%x:  %d %d %d\n", (current & 0xFF000000) >> 24, (current & 0xFF0000) >> 16, (current & 0xFF00) >> 8, (current & 0xFF)); */
+  };
+  return 0;
+}
+
diff --git a/converter/other/pnmtopalm/palm.h b/converter/other/pnmtopalm/palm.h
new file mode 100644
index 00000000..170c8cec
--- /dev/null
+++ b/converter/other/pnmtopalm/palm.h
@@ -0,0 +1,66 @@
+#ifndef PALM_H_INCLUDED
+#define PALM_H_INCLUDED
+
+#define PALM_IS_COMPRESSED_FLAG     0x8000
+#define PALM_HAS_COLORMAP_FLAG      0x4000
+#define PALM_HAS_TRANSPARENCY_FLAG  0x2000
+#define PALM_INDIRECT_BITMAP        0x1000  /* Palm says internal use only */
+#define PALM_FOR_SCREEN             0x0800  /* Palm says internal use only */
+#define PALM_DIRECT_COLOR_FLAG      0x0400
+#define PALM_INDIRECT_COLORMAP      0x0200  /* Palm says internal use only */ 
+#define PALM_NO_DITHER_FLAG         0x0100  /* rather mysterious */
+
+#define PALM_COMPRESSION_SCANLINE   0x00
+#define PALM_COMPRESSION_RLE        0x01
+#define PALM_COMPRESSION_PACKBITS   0x02
+#define PALM_COMPRESSION_END        0x03    /* Palm says internal use only */
+#define PALM_COMPRESSION_BEST       0x64    /* Palm says internal use only */
+#define PALM_COMPRESSION_NONE       0xFF    /* Palm says internal use only */
+
+#define PALM_DENSITY_LOW             72
+#define PALM_DENSITY_ONEANDAHALF    108
+#define PALM_DENSITY_DOUBLE         144
+#define PALM_DENSITY_TRIPLE         216
+#define PALM_DENSITY_QUADRUPLE      288
+
+#define PALM_FORMAT_INDEXED     0x00
+#define PALM_FORMAT_565         0x01
+#define PALM_FORMAT_565LE       0x02    /* Palm says internal use only */
+#define PALM_FORMAT_INDEXEDLE   0x03    /* Palm says internal use only */
+
+typedef unsigned long Color_s;
+
+typedef Color_s * Color;
+
+typedef struct {
+    unsigned int nentries;
+        /* number of allocated entries in 'color_entries' */
+    unsigned int ncolors;
+        /* number of colors actually in 'color_entries' -- entries are
+           filled from 0 consecutively, one color per entry.
+        */
+    Color_s * color_entries;  /* Array of colors */
+} Colormap_s;
+
+typedef Colormap_s * Colormap;
+
+int
+palmcolor_compare_indices(const void * const p1,
+                          const void * const p2);
+
+int
+palmcolor_compare_colors(const void * const p1,
+                         const void * const p2);
+
+Colormap
+palmcolor_build_custom_8bit_colormap(unsigned int const rows,
+                                     unsigned int const cols,
+                                     pixel **     const pixels);
+
+Colormap
+palmcolor_build_default_8bit_colormap(void);
+
+Colormap
+palmcolor_read_colormap (FILE * const ifP);
+
+#endif
diff --git a/converter/other/pnmtopalm/palmcolor8.map b/converter/other/pnmtopalm/palmcolor8.map
new file mode 100644
index 00000000..2e054616
--- /dev/null
+++ b/converter/other/pnmtopalm/palmcolor8.map
@@ -0,0 +1,235 @@
+P3
+232 1
+255
+0 0 0
+0 0 0
+0 0 51
+0 0 102
+0 0 153
+0 0 204
+0 0 255
+0 51 0
+0 51 51
+0 51 102
+0 51 153
+0 51 204
+0 51 255
+0 102 0
+0 102 51
+0 102 102
+0 102 153
+0 102 204
+0 102 255
+0 128 0
+0 128 128
+0 153 0
+0 153 51
+0 153 102
+0 153 153
+0 153 204
+0 153 255
+0 204 0
+0 204 51
+0 204 102
+0 204 153
+0 204 204
+0 204 255
+0 255 0
+0 255 51
+0 255 102
+0 255 153
+0 255 204
+0 255 255
+17 17 17
+34 34 34
+51 0 0
+51 0 51
+51 0 102
+51 0 153
+51 0 204
+51 0 255
+51 51 0
+51 51 51
+51 51 102
+51 51 153
+51 51 204
+51 51 255
+51 102 0
+51 102 51
+51 102 102
+51 102 153
+51 102 204
+51 102 255
+51 153 0
+51 153 51
+51 153 102
+51 153 153
+51 153 204
+51 153 255
+51 204 0
+51 204 51
+51 204 102
+51 204 153
+51 204 204
+51 204 255
+51 255 0
+51 255 51
+51 255 102
+51 255 153
+51 255 204
+51 255 255
+68 68 68
+85 85 85
+102 0 0
+102 0 51
+102 0 102
+102 0 153
+102 0 204
+102 0 255
+102 51 0
+102 51 51
+102 51 102
+102 51 153
+102 51 204
+102 51 255
+102 102 0
+102 102 51
+102 102 102
+102 102 153
+102 102 204
+102 102 255
+102 153 0
+102 153 51
+102 153 102
+102 153 153
+102 153 204
+102 153 255
+102 204 0
+102 204 51
+102 204 102
+102 204 153
+102 204 204
+102 204 255
+102 255 0
+102 255 51
+102 255 102
+102 255 153
+102 255 204
+102 255 255
+119 119 119
+128 0 0
+128 0 128
+136 136 136
+153 0 0
+153 0 51
+153 0 102
+153 0 153
+153 0 204
+153 0 255
+153 51 0
+153 51 51
+153 51 102
+153 51 153
+153 51 204
+153 51 255
+153 102 0
+153 102 51
+153 102 102
+153 102 153
+153 102 204
+153 102 255
+153 153 0
+153 153 51
+153 153 102
+153 153 153
+153 153 204
+153 153 255
+153 204 0
+153 204 51
+153 204 102
+153 204 153
+153 204 204
+153 204 255
+153 255 0
+153 255 51
+153 255 102
+153 255 153
+153 255 204
+153 255 255
+170 170 170
+187 187 187
+192 192 192
+204 0 0
+204 0 51
+204 0 102
+204 0 153
+204 0 204
+204 0 255
+204 51 0
+204 51 51
+204 51 102
+204 51 153
+204 51 204
+204 51 255
+204 102 0
+204 102 51
+204 102 102
+204 102 153
+204 102 204
+204 102 255
+204 153 0
+204 153 51
+204 153 102
+204 153 153
+204 153 204
+204 153 255
+204 204 0
+204 204 51
+204 204 102
+204 204 153
+204 204 204
+204 204 255
+204 255 0
+204 255 51
+204 255 102
+204 255 153
+204 255 204
+204 255 255
+221 221 221
+238 238 238
+255 0 0
+255 0 51
+255 0 102
+255 0 153
+255 0 204
+255 0 255
+255 51 0
+255 51 51
+255 51 102
+255 51 153
+255 51 204
+255 51 255
+255 102 0
+255 102 51
+255 102 102
+255 102 153
+255 102 204
+255 102 255
+255 153 0
+255 153 51
+255 153 102
+255 153 153
+255 153 204
+255 153 255
+255 204 0
+255 204 51
+255 204 102
+255 204 153
+255 204 204
+255 204 255
+255 255 0
+255 255 51
+255 255 102
+255 255 153
+255 255 204
+255 255 255
diff --git a/converter/other/pnmtopalm/palmcolormap.c b/converter/other/pnmtopalm/palmcolormap.c
new file mode 100644
index 00000000..a1a1cec1
--- /dev/null
+++ b/converter/other/pnmtopalm/palmcolormap.c
@@ -0,0 +1,277 @@
+/* See LICENSE file for licensing information.
+*/
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "pnm.h"
+
+#include "palm.h"
+
+int
+palmcolor_compare_indices(const void * const p1,
+                          const void * const p2) {
+
+    if ((*((Color) p1) & 0xFF000000) < (*((Color) p2) & 0xFF000000))
+        return -1;
+    else if ((*((Color) p1) & 0xFF000000) > (*((Color) p2) & 0xFF000000))
+        return 1;
+    else
+        return 0;
+}
+
+
+
+int
+palmcolor_compare_colors(const void * const p1,
+                         const void * const p2) {
+
+    unsigned long const val1 = *((const unsigned long *) p1) & 0xFFFFFF;
+    unsigned long const val2 = *((const unsigned long *) p2) & 0xFFFFFF;
+
+    if (val1 < val2)
+        return -1;
+    else if (val1 > val2)
+        return 1;
+    else
+        return 0;
+}
+
+/***********************************************************************
+ ***********************************************************************
+ ***********************************************************************
+ ******* colortables from pilrc-2.6/bitmap.c ***************************
+ ***********************************************************************
+ ***********************************************************************
+ ***********************************************************************/
+
+#if 0
+
+/*
+ * The 1bit-2 color system palette for Palm Computing Devices.
+ */
+static int PalmPalette1bpp[2][3] = 
+{
+  { 255, 255, 255}, {   0,   0,   0 }
+};
+
+/*
+ * The 2bit-4 color system palette for Palm Computing Devices.
+ */
+static int PalmPalette2bpp[4][3] = 
+{
+  { 255, 255, 255}, { 192, 192, 192}, { 128, 128, 128 }, {   0,   0,   0 }
+};
+
+/*
+ * The 4bit-16 color system palette for Palm Computing Devices.
+ */
+static int PalmPalette4bpp[16][3] = 
+{
+  { 255, 255, 255}, { 238, 238, 238 }, { 221, 221, 221 }, { 204, 204, 204 },
+  { 187, 187, 187}, { 170, 170, 170 }, { 153, 153, 153 }, { 136, 136, 136 },
+  { 119, 119, 119}, { 102, 102, 102 }, {  85,  85,  85 }, {  68,  68,  68 },
+  {  51,  51,  51}, {  34,  34,  34 }, {  17,  17,  17 }, {   0,   0,   0 }
+};
+
+/*
+ * The 4bit-16 color system palette for Palm Computing Devices.
+ */
+static int PalmPalette4bppColor[16][3] = 
+{
+  { 255, 255, 255}, { 128, 128, 128 }, { 128,   0,   0 }, { 128, 128,   0 },
+  {   0, 128,   0}, {   0, 128, 128 }, {   0,   0, 128 }, { 128,   0, 128 },
+  { 255,   0, 255}, { 192, 192, 192 }, { 255,   0,   0 }, { 255, 255,   0 },
+  {   0, 255,   0}, {   0, 255, 255 }, {   0,   0, 255 }, {   0,   0,   0 }
+};
+
+#endif  /* 0 */
+
+/*
+ * The 8bit-256 color system palette for Palm Computing Devices.
+ *
+ * NOTE:  only the first 231, plus the last one, are valid.
+ */
+static int PalmPalette8bpp[256][3] = 
+{
+  { 255, 255, 255 }, { 255, 204, 255 }, { 255, 153, 255 }, { 255, 102, 255 }, 
+  { 255,  51, 255 }, { 255,   0, 255 }, { 255, 255, 204 }, { 255, 204, 204 }, 
+  { 255, 153, 204 }, { 255, 102, 204 }, { 255,  51, 204 }, { 255,   0, 204 }, 
+  { 255, 255, 153 }, { 255, 204, 153 }, { 255, 153, 153 }, { 255, 102, 153 }, 
+  { 255,  51, 153 }, { 255,   0, 153 }, { 204, 255, 255 }, { 204, 204, 255 },
+  { 204, 153, 255 }, { 204, 102, 255 }, { 204,  51, 255 }, { 204,   0, 255 },
+  { 204, 255, 204 }, { 204, 204, 204 }, { 204, 153, 204 }, { 204, 102, 204 },
+  { 204,  51, 204 }, { 204,   0, 204 }, { 204, 255, 153 }, { 204, 204, 153 },
+  { 204, 153, 153 }, { 204, 102, 153 }, { 204,  51, 153 }, { 204,   0, 153 },
+  { 153, 255, 255 }, { 153, 204, 255 }, { 153, 153, 255 }, { 153, 102, 255 },
+  { 153,  51, 255 }, { 153,   0, 255 }, { 153, 255, 204 }, { 153, 204, 204 },
+  { 153, 153, 204 }, { 153, 102, 204 }, { 153,  51, 204 }, { 153,   0, 204 },
+  { 153, 255, 153 }, { 153, 204, 153 }, { 153, 153, 153 }, { 153, 102, 153 },
+  { 153,  51, 153 }, { 153,   0, 153 }, { 102, 255, 255 }, { 102, 204, 255 },
+  { 102, 153, 255 }, { 102, 102, 255 }, { 102,  51, 255 }, { 102,   0, 255 },
+  { 102, 255, 204 }, { 102, 204, 204 }, { 102, 153, 204 }, { 102, 102, 204 },
+  { 102,  51, 204 }, { 102,   0, 204 }, { 102, 255, 153 }, { 102, 204, 153 },
+  { 102, 153, 153 }, { 102, 102, 153 }, { 102,  51, 153 }, { 102,   0, 153 },
+  {  51, 255, 255 }, {  51, 204, 255 }, {  51, 153, 255 }, {  51, 102, 255 },
+  {  51,  51, 255 }, {  51,   0, 255 }, {  51, 255, 204 }, {  51, 204, 204 },
+  {  51, 153, 204 }, {  51, 102, 204 }, {  51,  51, 204 }, {  51,   0, 204 },
+  {  51, 255, 153 }, {  51, 204, 153 }, {  51, 153, 153 }, {  51, 102, 153 },
+  {  51,  51, 153 }, {  51,   0, 153 }, {   0, 255, 255 }, {   0, 204, 255 },
+  {   0, 153, 255 }, {   0, 102, 255 }, {   0,  51, 255 }, {   0,   0, 255 },
+  {   0, 255, 204 }, {   0, 204, 204 }, {   0, 153, 204 }, {   0, 102, 204 },
+  {   0,  51, 204 }, {   0,   0, 204 }, {   0, 255, 153 }, {   0, 204, 153 },
+  {   0, 153, 153 }, {   0, 102, 153 }, {   0,  51, 153 }, {   0,   0, 153 },
+  { 255, 255, 102 }, { 255, 204, 102 }, { 255, 153, 102 }, { 255, 102, 102 },
+  { 255,  51, 102 }, { 255,   0, 102 }, { 255, 255,  51 }, { 255, 204,  51 },
+  { 255, 153,  51 }, { 255, 102,  51 }, { 255,  51,  51 }, { 255,   0,  51 },
+  { 255, 255,   0 }, { 255, 204,   0 }, { 255, 153,   0 }, { 255, 102,   0 },
+  { 255,  51,   0 }, { 255,   0,   0 }, { 204, 255, 102 }, { 204, 204, 102 },
+  { 204, 153, 102 }, { 204, 102, 102 }, { 204,  51, 102 }, { 204,   0, 102 },
+  { 204, 255,  51 }, { 204, 204,  51 }, { 204, 153,  51 }, { 204, 102,  51 },
+  { 204,  51,  51 }, { 204,   0,  51 }, { 204, 255,   0 }, { 204, 204,   0 },
+  { 204, 153,   0 }, { 204, 102,   0 }, { 204,  51,   0 }, { 204,   0,   0 },
+  { 153, 255, 102 }, { 153, 204, 102 }, { 153, 153, 102 }, { 153, 102, 102 },
+  { 153,  51, 102 }, { 153,   0, 102 }, { 153, 255,  51 }, { 153, 204,  51 },
+  { 153, 153,  51 }, { 153, 102,  51 }, { 153,  51,  51 }, { 153,   0,  51 },
+  { 153, 255,   0 }, { 153, 204,   0 }, { 153, 153,   0 }, { 153, 102,   0 },
+  { 153,  51,   0 }, { 153,   0,   0 }, { 102, 255, 102 }, { 102, 204, 102 },
+  { 102, 153, 102 }, { 102, 102, 102 }, { 102,  51, 102 }, { 102,   0, 102 },
+  { 102, 255,  51 }, { 102, 204,  51 }, { 102, 153,  51 }, { 102, 102,  51 },
+  { 102,  51,  51 }, { 102,   0,  51 }, { 102, 255,   0 }, { 102, 204,   0 },
+  { 102, 153,   0 }, { 102, 102,   0 }, { 102,  51,   0 }, { 102,   0,   0 },
+  {  51, 255, 102 }, {  51, 204, 102 }, {  51, 153, 102 }, {  51, 102, 102 },
+  {  51,  51, 102 }, {  51,   0, 102 }, {  51, 255,  51 }, {  51, 204,  51 },
+  {  51, 153,  51 }, {  51, 102,  51 }, {  51,  51,  51 }, {  51,   0,  51 },
+  {  51, 255,   0 }, {  51, 204,   0 }, {  51, 153,   0 }, {  51, 102,   0 },
+  {  51,  51,   0 }, {  51,   0,   0 }, {   0, 255, 102 }, {   0, 204, 102 },
+  {   0, 153, 102 }, {   0, 102, 102 }, {   0,  51, 102 }, {   0,   0, 102 },
+  {   0, 255,  51 }, {   0, 204,  51 }, {   0, 153,  51 }, {   0, 102,  51 },
+  {   0,  51,  51 }, {   0,   0,  51 }, {   0, 255,   0 }, {   0, 204,   0 },
+  {   0, 153,   0 }, {   0, 102,   0 }, {   0,  51,   0 }, {  17,  17,  17 },
+  {  34,  34,  34 }, {  68,  68,  68 }, {  85,  85,  85 }, { 119, 119, 119 },
+  { 136, 136, 136 }, { 170, 170, 170 }, { 187, 187, 187 }, { 221, 221, 221 },
+  { 238, 238, 238 }, { 192, 192, 192 }, { 128,   0,   0 }, { 128,   0, 128 },
+  {   0, 128,   0 }, {   0, 128, 128 }, {   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 }, {   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 },
+  {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }
+};
+
+
+
+Colormap
+palmcolor_build_default_8bit_colormap(void) {
+
+    unsigned int i;
+
+    Colormap cm;
+
+    MALLOCVAR_NOFAIL(cm);
+    cm->nentries = 232;
+    MALLOCARRAY_NOFAIL(cm->color_entries, cm->nentries);
+
+    /* Fill in the colors */
+    for (i = 0; i < 231; ++i) {
+        cm->color_entries[i] = ((i << 24) |
+                                (PalmPalette8bpp[i][0] << 16) |
+                                (PalmPalette8bpp[i][1] << 8) |
+                                (PalmPalette8bpp[i][2]));
+    }
+    cm->color_entries[231] = 0xFF000000;
+    cm->ncolors = 232;
+
+    /* now sort the table */
+    qsort (cm->color_entries, cm->ncolors, sizeof(Color_s), 
+           palmcolor_compare_colors);
+    return cm;
+}
+
+
+
+Colormap
+palmcolor_build_custom_8bit_colormap(unsigned int const rows,
+                                     unsigned int const cols,
+                                     pixel **     const pixels) {
+    unsigned int row;
+    Colormap colormap;
+
+    MALLOCVAR_NOFAIL(colormap);
+    colormap->nentries = 256;
+    MALLOCARRAY_NOFAIL(colormap->color_entries, colormap->nentries);
+    colormap->ncolors = 0;  /* initial value */
+    
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; ++col) {
+            Color found;
+            Color_s temp;
+
+            temp = ((PPM_GETR(pixels[row][col]) << 16) |
+                    (PPM_GETG(pixels[row][col]) << 8) |
+                    PPM_GETB(pixels[row][col]));
+            found = (bsearch (&temp,
+                              colormap->color_entries, colormap->ncolors,
+                              sizeof(Color_s), palmcolor_compare_colors));
+            if (!found) {
+                if (colormap->ncolors >= colormap->nentries)
+                    pm_error("Too many colors for custom colormap "
+                             "(max 256).  "
+                             "Try using pnmquant to reduce the number "
+                             "of colors.");
+                else {
+                    /* add the new color, and re-sort */
+                    temp |= ((colormap->ncolors) << 24);
+                    colormap->color_entries[colormap->ncolors] = temp;
+                    colormap->ncolors += 1;
+                    qsort(colormap->color_entries, colormap->ncolors, 
+                          sizeof(Color_s), palmcolor_compare_colors);
+                }
+            }
+        }
+    }
+    return colormap;
+}
+
+
+
+Colormap
+palmcolor_read_colormap (FILE * const ifP) {
+
+    unsigned short ncolors;
+    Colormap retval;
+    int rc;
+    
+    rc = pm_readbigshort(ifP, (short *) &ncolors);
+    if (rc != 0)
+        retval = NULL;
+    else {
+        long colorentry;
+        Colormap colormap;
+        unsigned int i;
+        bool error;
+
+        MALLOCVAR_NOFAIL(colormap);
+        colormap->nentries = ncolors;
+        MALLOCARRAY_NOFAIL(colormap->color_entries, colormap->nentries);
+        
+        for (i = 0, error = FALSE;  i < ncolors && !error;  ++i) {
+            int rc;
+            rc = pm_readbiglong(ifP, &colorentry);
+            if (rc != 0)
+                error = TRUE;
+            else
+                colormap->color_entries[i] = (colorentry & 0xFFFFFFFF);
+        }
+        if (error) {
+            free (colormap->color_entries);
+            free (colormap);
+            retval = NULL;
+        } else {
+            colormap->ncolors = ncolors;
+            retval = colormap;
+        }
+    }
+    return retval;
+}
diff --git a/converter/other/pnmtopalm/palmgray1.map b/converter/other/pnmtopalm/palmgray1.map
new file mode 100644
index 00000000..96e20400
--- /dev/null
+++ b/converter/other/pnmtopalm/palmgray1.map
@@ -0,0 +1,4 @@
+P1
+# Black and white palette
+1 2
+0 1
diff --git a/converter/other/pnmtopalm/palmgray2.map b/converter/other/pnmtopalm/palmgray2.map
new file mode 100644
index 00000000..e8c95b01
--- /dev/null
+++ b/converter/other/pnmtopalm/palmgray2.map
@@ -0,0 +1,6 @@
+P2
+# 4 level grayscale palette
+2 2
+3
+0 1
+2 3
diff --git a/converter/other/pnmtopalm/palmgray4.map b/converter/other/pnmtopalm/palmgray4.map
new file mode 100644
index 00000000..bba2e6b8
--- /dev/null
+++ b/converter/other/pnmtopalm/palmgray4.map
@@ -0,0 +1,8 @@
+P2
+# 16 level grayscale palette
+4 4
+15
+ 0  1  2  3
+ 4  5  6  7
+ 8  9 10 11
+12 13 14 15
diff --git a/converter/other/pnmtopalm/palmtopnm.c b/converter/other/pnmtopalm/palmtopnm.c
new file mode 100644
index 00000000..9cd695e3
--- /dev/null
+++ b/converter/other/pnmtopalm/palmtopnm.c
@@ -0,0 +1,1131 @@
+/******************************************************************************
+                             palmtopnm
+*******************************************************************************
+  By Bryan Henderson, San Jose, California, June 2004.
+
+  Inspired by and using methods from Tbmptopnm by Ian Goldberg
+  <iang@cs.berkeley.edu>, and Bill Janssen <bill@janssen.org>.
+
+  Major fixes and new capability added by Paul Bolle <pebolle@tiscali.nl>
+  in late 2004 / early 2005.
+
+  Bryan's work is contributed to the public domain by its author.
+******************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+
+#include "pnm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+
+#include "palm.h"
+
+
+
+enum palmCompressionType {
+    COMPRESSION_NONE, 
+    COMPRESSION_RLE, 
+    COMPRESSION_SCANLINE,
+    COMPRESSION_PACKBITS
+};
+
+struct palmHeader {
+    unsigned short cols;
+    unsigned short rows;
+    unsigned short bytesPerRow;
+    unsigned short flags;
+    bool           directColor;
+        /* The header indicates a direct color raster, either by flag
+           (the old way) or by pixel format (the new way)
+        */
+    bool           hasColormap;
+    bool           hasTransparency;
+    unsigned char  pixelSizeCode;
+    unsigned int   pixelSize;
+    unsigned char  version;
+    unsigned int   transparentIndex;
+    enum palmCompressionType compressionType;
+    /* version 3 encoding specific */
+    unsigned char  size;
+    unsigned char  pixelFormat;
+    unsigned short density;
+    unsigned long  transparentValue;
+};
+
+
+
+struct directPixelFormat {
+    unsigned int redbits;
+    unsigned int greenbits;
+    unsigned int bluebits;
+};
+
+
+
+struct directColorInfo {
+    struct directPixelFormat pixelFormat;
+    Color_s                  transparentColor;
+};
+
+
+
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inputFilespec;
+    unsigned int verbose;
+    unsigned int rendition;
+    unsigned int showhist;
+    unsigned int transparent;
+};
+
+
+static void
+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.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def = malloc( 100*sizeof( optEntry ) );
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int renditionSpec;
+
+    unsigned int option_def_index;
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "verbose",     OPT_FLAG, NULL,
+            &cmdlineP->verbose,  0);
+    OPTENT3(0, "showhist",    OPT_FLAG, NULL,
+            &cmdlineP->showhist, 0);
+    OPTENT3(0, "transparent",    OPT_FLAG, NULL,
+            &cmdlineP->transparent, 0);
+    OPTENT3(0, "rendition",  OPT_UINT, &cmdlineP->rendition, 
+            &renditionSpec, 0);
+
+    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 */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+
+    if (renditionSpec) {
+        if (cmdlineP->rendition < 1)
+            pm_error("The -rendition value must be at least 1");
+    } else 
+        cmdlineP->rendition = 1;
+    
+    if (cmdlineP->transparent && cmdlineP->showhist)
+        pm_error("You can't specify -showhist with -transparent");
+
+    if (argc-1 < 1)
+        cmdlineP->inputFilespec = "-";
+    else {
+        cmdlineP->inputFilespec = argv[1];
+        if (argc-1 > 1)
+            pm_error("Too many arguments (%d).  The only non-option "
+                     "argument is the file name", argc-1);
+    }
+}
+
+
+
+static xelval *
+createGraymap(unsigned int const ncolors, 
+              xelval       const maxval) {
+    int i;
+    xelval *map;
+
+    MALLOCARRAY_NOFAIL(map, ncolors);
+    for (i = 0; i < ncolors; ++i) {
+        map[i] = maxval - (i * maxval) / (ncolors - 1);
+    }
+    return map;
+}
+
+
+
+static void 
+skipbytes(FILE *       const ifP, 
+          unsigned int const nbytes) {
+
+    unsigned char buf[256];
+    unsigned int n;
+    size_t bytesRead;
+
+    n = nbytes;  /* initial value */
+
+    while (n > 0) {
+        if (n > sizeof(buf)) {
+            bytesRead = fread(buf, sizeof(char), sizeof(buf), ifP);
+            if (bytesRead != sizeof(buf))
+               pm_error("Error reading Palm file.  Short read.");
+            n -= sizeof(buf);
+        } else {
+            bytesRead = fread(buf, sizeof(char), n, ifP);
+            if (bytesRead != n)
+               pm_error("Error reading Palm file.  Short read.");
+            n = 0;
+        }
+    }    
+}
+
+
+
+static void
+interpretCompression(unsigned char              const compressionValue,
+                     enum palmCompressionType * const compressionTypeP) {
+    
+    switch (compressionValue) {
+    case PALM_COMPRESSION_RLE:
+        *compressionTypeP = COMPRESSION_RLE;
+        break;
+    case PALM_COMPRESSION_SCANLINE:
+        *compressionTypeP = COMPRESSION_SCANLINE;
+        break;
+    case PALM_COMPRESSION_PACKBITS:
+        *compressionTypeP = COMPRESSION_PACKBITS;
+        break;
+    case PALM_COMPRESSION_NONE:
+        /* according to the spec this is not possible */
+        *compressionTypeP = COMPRESSION_NONE;
+        break;
+    default:
+        pm_error("The Palm image header has an unrecognized value for "
+                 "compression type: 0x%02x", (unsigned)compressionValue);
+    }
+}
+
+
+
+static void
+readRestOfHeaderVersion3(FILE *           const ifP,
+                         unsigned int     const pixelSize,
+                         unsigned char *  const sizeP,
+                         unsigned char *  const pixelFormatP,
+                         unsigned char *  const compressionTypeP,
+                         short *          const densityP,
+                         unsigned int *   const transparentIndexP,
+                         long *           const transparentValueP,
+                         long *           const nextBitmapOffsetP,
+                         short *          const nextDepthOffsetP) {
+
+    unsigned char unused;
+    
+    pm_readcharu(ifP, sizeP);
+    /* should be 0x18, but I can't see why we should really care */
+    if (*sizeP != 0x18)
+        pm_message("Strange value for Palm bitmap header size: %hu", *sizeP);
+
+    pm_readcharu(ifP, pixelFormatP);
+    if (*pixelFormatP != PALM_FORMAT_INDEXED &&
+        *pixelFormatP != PALM_FORMAT_565)
+        pm_error("Unrecognized pixelformat type: %u", *pixelFormatP);
+    
+    pm_readcharu(ifP, &unused);
+
+
+    pm_readcharu(ifP, compressionTypeP);
+
+    pm_readbigshort(ifP, densityP);
+    /* the specs imply that 0x00 is not valid */
+    if (*densityP != PALM_DENSITY_LOW &&
+        *densityP != PALM_DENSITY_ONEANDAHALF &&
+        *densityP != PALM_DENSITY_DOUBLE &&
+        *densityP != PALM_DENSITY_TRIPLE &&
+        *densityP != PALM_DENSITY_QUADRUPLE)
+        pm_error("Invalid value for -density: %d.", *densityP);
+ 
+    pm_readbiglong(ifP, transparentValueP);
+    if (pixelSize < 16)
+        *transparentIndexP = *transparentValueP;
+    else
+        *transparentIndexP = 0;
+ 
+    pm_readbiglong(ifP, nextBitmapOffsetP);
+    
+    /* version < 3 specific */
+    *nextDepthOffsetP = 0;
+}
+
+
+
+static void
+readRestOfHeaderOld(FILE *           const ifP,
+                    unsigned char *  const sizeP,
+                    unsigned char *  const pixelFormatP,
+                    unsigned char *  const compressionTypeP,
+                    short *          const densityP,
+                    unsigned int *   const transparentIndexP,
+                    long *           const transparentValueP,
+                    long *           const nextBitmapOffsetP,
+                    short *          const nextDepthOffsetP) {
+    
+    short pad;
+    unsigned char transparentIndex;
+    
+    pm_readbigshort(ifP, nextDepthOffsetP);
+    pm_readcharu(ifP, &transparentIndex);
+    *transparentIndexP = transparentIndex;
+ 
+    pm_readcharu(ifP,compressionTypeP);
+    
+    pm_readbigshort(ifP, &pad); /* reserved by Palm as of 8/9/00 */
+    
+    /* version 3 specific */
+    *sizeP = 0;
+    *pixelFormatP = 0;
+    *densityP = 0;
+    *transparentValueP = 0;
+    *nextBitmapOffsetP = 0;
+}
+
+
+
+static void
+interpretHeader(struct palmHeader * const palmHeaderP,
+                short               const cols,
+                short               const rows,
+                short               const bytesPerRow,
+                short               const flags,
+                unsigned char       const pixelSizeCode,
+                unsigned int        const pixelSize,
+                unsigned char       const version,
+                unsigned char       const size,
+                unsigned char       const pixelFormat,
+                short               const density,
+                long                const transparentValue,
+                unsigned int        const transparentIndex,
+                unsigned char       const compressionType) {
+    
+    palmHeaderP->cols = cols;
+    palmHeaderP->rows = rows;
+    palmHeaderP->bytesPerRow = bytesPerRow;
+    palmHeaderP->flags = flags;  /* Just for diagnostics */
+    palmHeaderP->hasColormap = !!(flags & PALM_HAS_COLORMAP_FLAG);
+    palmHeaderP->hasTransparency = !!(flags & PALM_HAS_TRANSPARENCY_FLAG);
+    palmHeaderP->pixelSizeCode = pixelSizeCode;
+    palmHeaderP->pixelSize = pixelSize;
+    palmHeaderP->version = version;
+    palmHeaderP->size = size;
+    palmHeaderP->pixelFormat = pixelFormat;
+    palmHeaderP->density = density;
+    palmHeaderP->transparentValue = transparentValue;
+    palmHeaderP->transparentIndex = transparentIndex;
+
+    if (palmHeaderP->version == 3 && (flags & PALM_DIRECT_COLOR_FLAG))
+        /* There's no directColorInfoType section in a version 3 Palm Bitmap */
+        pm_error("PALM_DIRECT_COLOR_FLAG is not valid for version 3 "
+                 "encoding type.");
+        
+    palmHeaderP->directColor = ((flags & PALM_DIRECT_COLOR_FLAG) || 
+                                palmHeaderP->pixelFormat == PALM_FORMAT_565);
+    
+    if (flags & PALM_IS_COMPRESSED_FLAG) 
+        interpretCompression(compressionType,
+                             &palmHeaderP->compressionType);
+    else
+        palmHeaderP->compressionType = COMPRESSION_NONE;
+}
+
+
+
+static void
+readHeader(FILE *              const ifP,
+           unsigned int        const requestedRendition,
+           struct palmHeader * const palmHeaderP) {
+/*----------------------------------------------------------------------------
+   Read the Palm Bitmap header from the file 'ifP'.  Read past all
+   renditions up to 'requestedRendition' and read the header of that
+   rendition.  Return the information contained in the header as *palmHeaderP.
+-----------------------------------------------------------------------------*/
+    bool gotHeader;
+    unsigned int currentRendition;
+
+    gotHeader = FALSE;
+    currentRendition = 1;
+    while (!gotHeader) {
+        short cols, rows, bytesPerRow, flags, nextDepthOffset, density;
+        unsigned char pixelSizeCode, version, compressionType, 
+            size, pixelFormat;
+        long transparentValue, nextBitmapOffset;
+        unsigned int pixelSize, transparentIndex;
+
+        pm_readbigshort(ifP, &cols);
+        pm_readbigshort(ifP, &rows);
+        pm_readbigshort(ifP, &bytesPerRow);
+        pm_readbigshort(ifP, &flags);
+ 
+        pm_readcharu(ifP, &pixelSizeCode);
+        pixelSize = pixelSizeCode == 0 ? 1 : pixelSizeCode;
+        if (pixelSizeCode != 0x00 &&
+            pixelSizeCode != 0x01 &&
+            pixelSizeCode != 0x02 &&
+            pixelSizeCode != 0x04 &&
+            pixelSizeCode != 0x08 &&
+            pixelSizeCode != 0x10 &&
+            pixelSizeCode != 0xFF)
+            pm_error("Invalid value for bits per pixel: %u.", pixelSizeCode);
+
+        if ((bytesPerRow * 8) < (cols * pixelSize))
+            pm_error("%u bytes per row is not valid with %u columns and %u "
+                     "bits per pixel.", bytesPerRow, cols, pixelSize);
+
+        pm_readcharu(ifP, &version);
+        if (version > 3) 
+            pm_error("Unknown encoding version type: %d", version);
+        else if (version == 3)
+            readRestOfHeaderVersion3(ifP, pixelSize,
+                                     &size, &pixelFormat, &compressionType,
+                                     &density, &transparentIndex, 
+                                     &transparentValue, &nextBitmapOffset,
+                                     &nextDepthOffset);
+        else
+            readRestOfHeaderOld(ifP,
+                                &size, &pixelFormat, &compressionType,
+                                &density, &transparentIndex,
+                                &transparentValue, &nextBitmapOffset,
+                                &nextDepthOffset);
+
+        if (currentRendition < requestedRendition) {
+             if (version < 3 && nextDepthOffset == 0 && pixelSizeCode != 0xFF) 
+                 pm_error("Not enough renditions in the input Palm Bitmap "
+                          "to extract the %dth", requestedRendition);
+             if (version == 3 && nextBitmapOffset == 0) 
+                 pm_error("Not enough renditions in the input Palm Bitmap "
+                          "to extract the %dth", requestedRendition);
+             /* nextDepthOffset is calculated in 4 byte words
+                from the beginning of this bitmap (so it equals its size) 
+             */
+             if (version < 3 && pixelSizeCode != 0xFF )
+                 skipbytes(ifP, (nextDepthOffset*4)-16);
+             else if (version == 3)
+                 /* FIXME rewrite skipbytes to accept longs? */
+                 skipbytes(ifP, (short) nextBitmapOffset-24); 
+             if (pixelSizeCode != 0xFF)
+                 ++currentRendition;
+        } else if (pixelSizeCode != 0xFF) {
+            gotHeader = TRUE;
+            
+            interpretHeader(palmHeaderP,
+                            cols, rows, bytesPerRow, flags, pixelSizeCode,
+                            pixelSize, version, size, pixelFormat, density,
+                            transparentValue, transparentIndex, 
+                            compressionType);
+        }
+    }
+}
+
+
+
+static const char *
+yesno(bool const arg) {
+
+    if (arg)
+        return "YES";
+    else
+        return "NO";
+}
+
+
+static void
+reportPalmHeader(struct palmHeader      const palmHeader,
+                 struct directColorInfo const directColorInfo) {
+
+    const char *ctype;
+
+    switch (palmHeader.compressionType) {
+    case COMPRESSION_RLE:
+        ctype = "rle (Palm OS 3.5)";
+        break;
+    case COMPRESSION_SCANLINE:
+        ctype = "scanline (Palm OS 2.0)";
+        break;
+    case COMPRESSION_PACKBITS:
+        ctype = "packbits (Palm OS 4.0)";
+        break;
+    case COMPRESSION_NONE:
+        ctype = "none";
+        break;
+    }
+    pm_message("Dimensions: %hu columns x %hu rows",
+               palmHeader.cols, palmHeader.rows);
+    pm_message("Row layout: %hu bytes per row, %hu bits per pixel",
+               palmHeader.bytesPerRow, palmHeader.pixelSize);
+    pm_message("Pixel Size code: %hu", palmHeader.pixelSizeCode);
+    pm_message("Flags: 0x%04hx", palmHeader.flags);
+    pm_message("  Direct Color: %s", yesno(palmHeader.directColor));
+    pm_message("  Colormap:     %s", yesno(palmHeader.hasColormap));
+    pm_message("  Transparency: %s", yesno(palmHeader.hasTransparency));
+    pm_message("Version %d", palmHeader.version);
+    if (palmHeader.hasTransparency) {
+        if (palmHeader.directColor) {
+            /* Copied from doTransparent(...) */
+            Color_s const color = directColorInfo.transparentColor;
+            pm_message("Transparent value: #%02x%02x%02x", 
+                       (unsigned int)((color >> 16) & 0xFF), 
+                       (unsigned int)((color >>  8) & 0xFF), 
+                       (unsigned int)((color >>  0) & 0xFF));
+        } else
+            pm_message("Transparent index: %u", palmHeader.transparentIndex);
+    }
+    pm_message("Compression type: %s", ctype);
+    if (palmHeader.version == 3)
+        pm_message("Density: %d", palmHeader.density);
+}
+
+
+
+static void
+determineOutputFormat(struct palmHeader const palmHeader,
+                      int *             const formatP,
+                      xelval *          const maxvalP) {
+
+    if (palmHeader.directColor) {
+        *formatP = PPM_TYPE;
+        *maxvalP = 255;
+    } else if (palmHeader.hasColormap) {
+        *formatP = PPM_TYPE;
+        *maxvalP = 255;
+    } else if (palmHeader.pixelSize == 1) {
+        *formatP = PBM_TYPE;
+        *maxvalP = 1;
+    } else if (palmHeader.pixelSize >= 8) {
+        *formatP = PPM_TYPE;
+        *maxvalP = pm_bitstomaxval(palmHeader.pixelSize);
+    } else {
+        *formatP = PGM_TYPE;
+        *maxvalP = pm_bitstomaxval(palmHeader.pixelSize);
+    }
+}
+
+
+
+static void
+readRgbFormat(FILE *                     const ifP,
+              struct directPixelFormat * const pixelFormatP) {
+
+    unsigned char r, g, b;
+
+    pm_readcharu(ifP, &r);
+    pm_readcharu(ifP, &g);
+    pm_readcharu(ifP, &b);
+    
+    if (r != 5 || g != 6 || b != 5)
+        pm_error("This image has a direct color pixel format of "
+                 "%u red, %u green, %u blue bits.  This program "
+                 "can handle only 5, 6, 5.", r, g, b);
+    else {
+        pixelFormatP->redbits   = r;
+        pixelFormatP->greenbits = g;
+        pixelFormatP->bluebits  = b;
+    }
+}
+
+
+
+static void
+readDirectTransparentColor(FILE *    const ifP,
+                           Color_s * const colorP) {
+
+    unsigned char r, g, b;
+
+    pm_readcharu(ifP, &r);
+    pm_readcharu(ifP, &g);
+    pm_readcharu(ifP, &b);
+
+    *colorP = (r << 16) | (g << 8) | (b << 0);
+}
+
+
+
+static void
+readDirectInfoType(FILE *                   const ifP,
+                   struct palmHeader        const palmHeader,
+                   struct directColorInfo * const directInfoTypeP) {
+/*----------------------------------------------------------------------------
+   Read the Palm Bitmap Direct Info Type section, if any.
+
+   The Direct Info Type section is a section of a pre-Version 3 direct
+   color Palm Bitmap that tells how to interpret the direct color
+   raster.
+
+   Return an undefined value as *directInfoTypeP if there is no such
+   section in this Palm Bitmap.
+-----------------------------------------------------------------------------*/
+    if ((palmHeader.directColor) && palmHeader.pixelSize != 16)
+        pm_error("The image is of the direct color type, but has %u "
+                 "bits per pixel.  The only kind of direct color images "
+                 "this program understands are 16 bit ones.", 
+                 palmHeader.pixelSize);
+
+    if (palmHeader.version == 3) {
+        /* All direct color info is in the header, because it'sversion
+           3 encoding.  No Direct Info Type section.  
+        */
+    } else {
+        if (palmHeader.directColor) {
+            unsigned char padding;
+
+            readRgbFormat(ifP, &directInfoTypeP->pixelFormat);
+
+            pm_readcharu(ifP, &padding);
+            pm_readcharu(ifP, &padding);
+
+            readDirectTransparentColor(ifP, 
+                                       &directInfoTypeP->transparentColor);
+        } else {
+            /* Not a direct color image; no Direct Info Type section. */
+        }
+    }
+}
+
+
+
+static void
+readColormap(FILE *            const ifP,
+             struct palmHeader const palmHeader,
+             Colormap *        const colormapP) {
+/*----------------------------------------------------------------------------
+   Read the colormap, if any from the Palm Bitmap.
+
+   If the image described by 'palmHeader' doesn't have a colormap,
+   return an undefined value as *colormapP.
+-----------------------------------------------------------------------------*/
+    if (palmHeader.hasColormap)
+        *colormapP = palmcolor_read_colormap(ifP);
+}
+
+
+
+static void
+getColorInfo(struct palmHeader        const palmHeader,
+             struct directColorInfo   const directInfoType,
+             Colormap                 const colormapFromImage,
+             Colormap *               const colormapP,
+             unsigned int *           const ncolorsP,
+             struct directColorInfo * const directColorInfoP) {
+/*----------------------------------------------------------------------------
+   Gather color encoding information from the various sources.
+
+   Note that 'directInfoType' and 'colormapFromImage' are meaningful only
+   with certain values of 'palmHeader'.
+
+   If it's a version 3 direct color, the pixel format must be "565".
+-----------------------------------------------------------------------------*/
+    if (palmHeader.version == 3 && palmHeader.directColor) {
+        *colormapP = NULL;
+
+        assert(palmHeader.pixelFormat == PALM_FORMAT_565);
+
+        directColorInfoP->pixelFormat.redbits   = 5;
+        directColorInfoP->pixelFormat.greenbits = 6;
+        directColorInfoP->pixelFormat.bluebits  = 5;
+        /* FIXME Just guessing here ... */
+        directColorInfoP->transparentColor = 
+            (((palmHeader.transparentValue >> 11) & 0x1F) << 16) |
+            (((palmHeader.transparentValue >>  5) & 0x3F) <<  8) |
+            (((palmHeader.transparentValue >>  0) & 0x1F) <<  0);
+    } else if (palmHeader.directColor) {
+        *colormapP = NULL;
+        *directColorInfoP = directInfoType;
+    } else if (palmHeader.hasColormap)
+        *colormapP = colormapFromImage;
+    else if (palmHeader.pixelSize >= 8) {
+        Colormap colormap;
+        colormap = palmcolor_build_default_8bit_colormap();
+        qsort(colormap->color_entries, colormap->ncolors, 
+              sizeof(Color_s), palmcolor_compare_indices);
+        *colormapP = colormap;
+    } else
+        *colormapP = NULL;
+
+    *ncolorsP = 1 << palmHeader.pixelSize;
+}
+
+
+
+static void
+doTransparent(FILE *                 const ofP,
+              bool                   const hasTransparency,
+              bool                   const directColor,
+              unsigned char          const transparentIndex,
+              unsigned char          const pixelSize,
+              Colormap               const colormap,
+              struct directColorInfo const directColorInfo) {
+/*----------------------------------------------------------------------------
+   Generate a PNM comment on *ofP telling what color in the raster is
+   supposed to be transparent.
+
+   Note that PNM itself doesn't have any way to represent transparency.
+   (But this program could be converted to a PAM program and use the
+   RGB_ALPHA and GRAYSCALE_ALPHA tuple types).
+-----------------------------------------------------------------------------*/
+    if (hasTransparency) {
+        if (colormap) {
+            Color_s const color = transparentIndex << 24;
+            Color const actualColor = (bsearch(&color,
+                                               colormap->color_entries, 
+                                               colormap->ncolors,
+                                               sizeof(color), 
+                                               palmcolor_compare_indices));
+            fprintf(ofP, "#%02x%02x%02x\n", 
+                   (unsigned int) ((*actualColor >> 16) & 0xFF),
+                   (unsigned int) ((*actualColor >>  8) & 0xFF), 
+                   (unsigned int) ((*actualColor >>  0) & 0xFF));
+        } else if (directColor) {
+            Color_s const color = directColorInfo.transparentColor;
+            fprintf(ofP, "#%02x%02x%02x\n", 
+                   (unsigned int)((color >> 16) & 0xFF), 
+                   (unsigned int)((color >>  8) & 0xFF), 
+                   (unsigned int)((color >>  0) & 0xFF));
+        } else {
+            unsigned int const maxval = pm_bitstomaxval(pixelSize);
+            unsigned int const grayval = 
+                ((maxval - transparentIndex) * 256) / maxval;
+            fprintf(ofP, "#%02x%02x%02x\n", grayval, grayval, grayval);
+        }
+    }
+}
+
+
+
+static void
+createHistogram(unsigned int    const ncolors,
+                unsigned int ** const seenP) {
+
+    unsigned int * seen;
+
+    MALLOCARRAY(seen, ncolors);
+    if (!seen)
+        pm_error("Can't allocate array for keeping track of "
+                 "how many pixels of each of %u colors are in the image.", 
+                 ncolors);
+
+    {    
+        /* Initialize the counter for each color to zero */
+        unsigned int i;
+        for (i = 0; i < ncolors; ++i)
+            seen[i] = 0;
+    }
+    *seenP = seen;
+}
+
+
+
+static void
+readScanlineRow(FILE *          const ifP,
+                unsigned char * const palmrow,
+                unsigned char * const lastrow,
+                unsigned int    const bytesPerRow,
+                bool            const firstRow) {
+
+    unsigned int j;
+
+    for (j = 0; j < bytesPerRow; j += 8) {
+        unsigned char diffmask;
+            /* A mask telling whether each of the 8 raster bytes indexed
+               j through j+7 is the same as in the previous row ('lastrow')
+               or is to be read from the file.  Bit 0 of the mask refers
+               to byte j, Bit 1 to byte j + 1, etc.
+            */
+        unsigned int byteCount;
+            /* How many bytes are covered by 'diffmask'.  Normally 8, but
+               at the end of the row, could be less.
+            */
+        unsigned int k;
+
+        pm_readcharu(ifP, &diffmask);
+        byteCount = MIN(bytesPerRow - j, 8);
+        
+        for (k = 0; k < byteCount; ++k) {
+            /* the first row cannot be compressed */
+            if (firstRow || ((diffmask & (1 << (7 - k))) != 0)) {
+                unsigned char inval;
+                pm_readcharu(ifP, &inval);
+                palmrow[j + k] = inval;
+            } else
+                palmrow[j + k] = lastrow[j + k];
+        }
+    }
+    memcpy(lastrow, palmrow, bytesPerRow);
+}
+
+
+
+static void
+readRleRow(FILE *          const ifP,
+           unsigned char * const palmrow,
+           unsigned int    const bytesPerRow) {
+
+    unsigned int j;
+
+    for (j = 0;  j < bytesPerRow; ) {
+        unsigned char incount;
+        unsigned char inval;
+
+        pm_readcharu(ifP, &incount);
+        if (incount == 0)
+            pm_error("Invalid (zero) count in RLE compression.");
+        if (j + incount > bytesPerRow)
+            pm_error("Bytes in RLE compressed row exceed bytes per row.  "
+                     "Bytes per row is %u.  A run length of %u bytes "
+                     "pushes the bytes in this row up to %u bytes (and then"
+                     "we gave up.", bytesPerRow, incount, j + incount);
+        pm_readcharu(ifP, &inval);
+        memset(palmrow + j, inval, incount);
+        j += incount;
+    }
+} 
+
+
+
+static void
+readPackBitsRow(FILE *          const ifP,
+                unsigned char * const palmrow,
+                unsigned int    const bytesPerRow) {
+
+    unsigned int j;
+
+    for (j = 0;  j < bytesPerRow; ) {
+        char incount;
+        pm_readchar(ifP, &incount);
+        if (incount < 0) { 
+            /* How do we handle incount == -128 ? */
+            unsigned int const runlength = -incount + 1;
+            unsigned char inval;
+            pm_readcharu(ifP, &inval);
+            memset(palmrow + j, inval, runlength);
+            j += runlength;
+        } else {
+            unsigned int const nonrunlength = incount + 1;
+            unsigned int k;
+            for (k = 0; k < nonrunlength; ++k) {
+                unsigned char inval;
+                pm_readcharu(ifP, &inval);
+                palmrow[j + k] = inval;
+            }
+            j += nonrunlength;
+        }
+        if (j > bytesPerRow) 
+            pm_error("Bytes in PackBits compressed row exceed bytes per row.");
+    }
+} 
+
+
+
+static void
+readUncompressedRow(FILE *          const ifP,
+                    unsigned char * const palmrow,
+                    unsigned int    const bytesPerRow) {
+
+    int bytesRead;
+    
+    bytesRead = fread(palmrow, 1, bytesPerRow, ifP);
+    if (bytesRead != bytesPerRow)
+        pm_error("Error reading Palm file.  Short read.");
+}
+
+
+
+static void
+readDecompressedRow(FILE *                   const ifP,
+                    unsigned char *          const palmrow,
+                    unsigned char *          const lastrow,
+                    enum palmCompressionType const compressionType,
+                    unsigned int             const bytesPerRow,
+                    bool                     const firstRow) {
+/*----------------------------------------------------------------------------
+   Read a row from Palm file 'ifP', in uncompressed form (i.e. decompress if
+   necessary).  Assume the row contains 'bytesPerRow' uncompressed bytes,
+   compressed according to 'compressionType'.  Return the data at 'palmrow'.
+
+   'firstRow' means decompress it as if it is the first row of the image
+   (some compression schemes transform the first row differently from the
+   rest, because each row depends on the row before it).
+
+   If 'compressionType' is COMPRESSION_SCANLINE, (which means
+   transformation of a row depends on the contents of the row before
+   it), then 'lastRow' is as input the uncompressed contents of the
+   previous row (undefined if 'firstRow' is true).  In that case, we
+   modify 'lastrow' to contain a copy of 'palmrow' (so Caller can
+   conveniently use it to read the next row).
+
+   If 'compressionType' is not COMPRESSION_SCANLINE, 'lastrow' is
+   undefined both as input and output.
+-----------------------------------------------------------------------------*/
+    switch (compressionType) {
+    case COMPRESSION_RLE:
+        readRleRow(ifP, palmrow, bytesPerRow);
+        break;
+    case COMPRESSION_SCANLINE:
+        readScanlineRow(ifP, palmrow, lastrow, bytesPerRow, firstRow);
+        break;
+    case COMPRESSION_PACKBITS:
+        readPackBitsRow(ifP, palmrow, bytesPerRow);
+        break;
+    case COMPRESSION_NONE:
+        readUncompressedRow(ifP, palmrow, bytesPerRow);
+        break;
+    }
+}
+
+
+
+static void
+convertRowToPnmDirect(const unsigned char * const palmrow,
+                      xel *                 const xelrow,
+                      unsigned int          const cols,
+                      xelval                const maxval,
+                      unsigned int *        const seen) {
+
+    /* There's a problem with this.  Take the Palm 16-bit
+       direct color.  That's 5 bits for the red, 6 for the
+       green, and 5 for the blue.  So what should the MAXVAL
+       be?  I decided to use 255 (8 bits) for everything,
+       since that's the theoretical max of the number of bits
+       in any one color, according to Palm.  So the Palm color
+       0xFFFF (white) would be red=0x1F, green=0x3F, and
+       blue=0x1F.  How do we promote those colors?  Simple
+       shift would give us R=248,G=252,B=248; which is
+       slightly green.  Hardly seems right.
+       
+       So I've perverted the math a bit.  Each color value is
+       multiplied by 255, then divided by either 31 (red or
+       blue) or 63 (green).  That's the right way to do it
+       anyway.  
+    */
+
+    const unsigned char *inbyte;
+    unsigned int j;
+    
+    for (inbyte = palmrow, j = 0;  j < cols;  ++j) {
+        unsigned int inval;
+        inval = *inbyte++ << 8;
+        inval |= *inbyte++;
+        
+        if (seen)
+            ++seen[inval];
+        
+        PPM_ASSIGN(xelrow[j], 
+                   (((inval >> 11) & 0x1F) * maxval) / 0x1F, 
+                   (((inval >>  5) & 0x3F) * maxval) / 0x3F, 
+                   (((inval >>  0) & 0x1F) * maxval) / 0x1F
+            );
+    }
+}
+
+
+
+static void
+convertRowToPnmNotDirect(const unsigned char * const palmrow,
+                         xel *                 const xelrow,
+                         unsigned int          const cols,
+                         Colormap              const colormap,
+                         xelval *              const graymap,
+                         unsigned int *        const seen,
+                         unsigned int          const pixelSize) {
+
+    unsigned int const mask = (1 << pixelSize) - 1;
+
+    const unsigned char *inbyte;
+    unsigned int inbit;
+    unsigned int j;
+    
+    inbit = 8 - pixelSize;
+    inbyte = palmrow;
+    for (j = 0; j < cols; ++j) {
+        short const color = ((*inbyte) & (mask << inbit)) >> inbit;
+        if (seen)
+            ++seen[color];
+        
+        if (colormap) {
+            Color_s const color2      = color << 24;
+            Color   const actualColor = (bsearch (&color2,
+                                                  colormap->color_entries, 
+                                                  colormap->ncolors,
+                                                  sizeof(color2), 
+                                                  palmcolor_compare_indices));
+            PPM_ASSIGN(xelrow[j], 
+                       (*actualColor >> 16) & 0xFF, 
+                       (*actualColor >>  8) & 0xFF, 
+                       (*actualColor >>  0) & 0xFF);
+        } else
+            PNM_ASSIGN1(xelrow[j], graymap[color]);
+        
+        if (!inbit) {
+            ++inbyte;
+            inbit = 8 - pixelSize;
+        } else
+            inbit -= pixelSize;
+    }
+}
+
+
+
+static void
+writePnm(FILE *            const ofP,
+         struct palmHeader const palmHeader,
+         FILE *            const ifP,
+         Colormap          const colormap,
+         xelval *          const graymap,
+         unsigned int      const nColors,
+         int               const format,
+         xelval            const maxval,
+         unsigned int **   const seenP) {
+
+    int const cols = palmHeader.cols;
+    int const rows = palmHeader.rows;
+
+    unsigned char * palmrow;
+    unsigned char * lastrow;
+    xel *           xelrow;
+    unsigned int *  seen;
+    unsigned int    row;
+    
+    pnm_writepnminit(ofP, cols, rows, maxval, format, 0);
+    xelrow = pnm_allocrow(cols);
+
+    /* Read the picture data, one row at a time */
+    MALLOCARRAY_NOFAIL(palmrow, palmHeader.bytesPerRow);
+    MALLOCARRAY_NOFAIL(lastrow, palmHeader.bytesPerRow); 
+    
+    if (seenP) {
+        createHistogram(nColors, &seen);
+        *seenP = seen;
+    } else
+        seen = NULL;
+
+    /* We should actually use compressedDataSizeNN for checking the sanity 
+       of the data we're reading ... 
+    */
+    if (palmHeader.compressionType != COMPRESSION_NONE) {
+        if (palmHeader.version < 3) {
+            short compressedDataSize16;
+            pm_readbigshort(ifP, &compressedDataSize16);
+        } else {
+            long compressedDataSize32;
+            pm_readbiglong(ifP, &compressedDataSize32);
+        }
+    }
+
+    for (row = 0; row < rows; ++row) {
+        readDecompressedRow(ifP, palmrow, lastrow, 
+                            palmHeader.compressionType, 
+                            palmHeader.bytesPerRow,
+                            row == 0);
+
+        if (palmHeader.directColor) {
+            assert(palmHeader.pixelSize == 16);
+            convertRowToPnmDirect(palmrow, xelrow, cols, maxval, seen);
+        } else
+            convertRowToPnmNotDirect(palmrow, xelrow, cols, colormap, graymap,
+                                     seen, palmHeader.pixelSize);
+
+        pnm_writepnmrow(ofP, xelrow, cols, maxval, format, 0);
+    }
+    free(lastrow);
+    free(palmrow);
+    pnm_freerow(xelrow);
+}
+
+
+
+static void
+showHistogram(unsigned int * const seen,
+              Colormap       const colormap,
+              const xelval * const graymap,
+              unsigned int   const ncolors) {
+
+    unsigned int colorIndex;
+    
+    for (colorIndex = 0;  colorIndex < ncolors; ++colorIndex) {
+        if (!colormap)
+            pm_message("%.3d -> %.3d:  %d", 
+                       colorIndex, graymap[colorIndex], seen[colorIndex]);
+        else {
+            Color_s const color = colorIndex << 24;
+            Color const actualColor = (bsearch(&color,
+                                               colormap->color_entries, 
+                                               colormap->ncolors,
+                                               sizeof(color), 
+                                               palmcolor_compare_indices));
+            if (actualColor)
+                pm_message("%.3d -> %ld,%ld,%ld:  %d", colorIndex,
+                           (*actualColor >> 16) & 0xFF,
+                           (*actualColor >> 8) & 0xFF,
+                           (*actualColor & 0xFF), seen[colorIndex]);
+        }
+    }
+}
+
+
+
+int
+main(int argc, char **argv) {
+
+    struct cmdlineInfo cmdline;
+
+    FILE* ifP;
+    struct palmHeader palmHeader;
+    struct directColorInfo directInfoType;
+    Colormap colormapFromImage;
+    Colormap colormap;
+    struct directColorInfo directColorInfo;
+    int format;
+    xelval maxval;
+    unsigned int nColors;
+
+    /* Parse default params */
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    readHeader(ifP, cmdline.rendition, &palmHeader);
+
+    readDirectInfoType(ifP, palmHeader, &directInfoType);
+   
+    readColormap(ifP, palmHeader, &colormapFromImage);
+    
+    determineOutputFormat(palmHeader, &format, &maxval);
+    
+    getColorInfo(palmHeader, directInfoType, colormapFromImage,
+                 &colormap, &nColors, &directColorInfo);
+
+    if (cmdline.verbose)
+        reportPalmHeader(palmHeader, directColorInfo);
+
+    if (cmdline.transparent)
+        doTransparent(stdout, 
+                      palmHeader.hasTransparency, palmHeader.directColor,
+                      palmHeader.transparentIndex, 
+                      palmHeader.pixelSize, colormap, directColorInfo);
+    else {
+        unsigned int * seen;
+        xelval * graymap;
+
+        graymap = createGraymap(nColors, maxval);
+
+        writePnm(stdout,
+                 palmHeader, ifP, colormap, graymap, nColors, format, maxval, 
+                 cmdline.showhist ? &seen : NULL);
+        
+        if (cmdline.showhist)
+            showHistogram(seen, colormap, graymap, nColors);
+        
+        free(graymap);
+    }
+    pm_close(ifP);
+
+    return 0;
+}
diff --git a/converter/other/pnmtopalm/pnmtopalm.c b/converter/other/pnmtopalm/pnmtopalm.c
new file mode 100644
index 00000000..3b9eec8f
--- /dev/null
+++ b/converter/other/pnmtopalm/pnmtopalm.c
@@ -0,0 +1,1235 @@
+/* pnmtopalm.c - read a PNM image and write a Palm Bitmap file
+ *
+ * Inspired by and using methods from ppmtoTbmp.c by Ian Goldberg
+ * <iang@cs.berkeley.edu>, which was based on ppmtopuzz.c by Jef
+ * Poskanzer, from the netpbm-1mar1994 package.
+ *
+ * Mods for multiple bits per pixel were added to ppmtoTbmp.c by
+ * George Caswell <tetsujin@sourceforge.net> and Bill Janssen
+ * <bill@janssen.org>.
+ *
+ * Major fixes and new capability added by Paul Bolle <pebolle@tiscali.nl>
+ * in late 2004 / early 2005.
+ *
+ * See LICENSE file for licensing information.
+ *
+ *  
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+
+#include "pnm.h"
+#include "palm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+
+enum compressionType {COMP_NONE, COMP_SCANLINE, COMP_RLE, COMP_PACKBITS};
+
+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 */
+    unsigned int depth;         /* -depth value.  0 if unspec */
+    unsigned int maxdepth;      /* -maxdepth value.  0 if unspec */
+    enum compressionType compression;
+    unsigned int verbose;
+    unsigned int colormap;
+    unsigned int offset;        /* -offset specified */
+    unsigned int density;       /* screen density */
+    unsigned int withdummy;
+};
+
+
+
+static void
+parseCommandLine(int argc, char ** argv, 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.
+-----------------------------------------------------------------------------*/
+    optStruct3 opt;  /* set by OPTENT3 */
+    optEntry *option_def;
+    unsigned int option_def_index;
+
+    unsigned int transSpec, depthSpec, maxdepthSpec, densitySpec;
+    unsigned int scanline_compression, rle_compression, packbits_compression;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "transparent",      OPT_STRING, 
+            &cmdlineP->transparent, &transSpec, 0);
+    OPTENT3(0, "depth",            OPT_UINT, 
+            &cmdlineP->depth,       &depthSpec, 0);
+    OPTENT3(0, "maxdepth",         OPT_UINT, 
+            &cmdlineP->maxdepth,    &maxdepthSpec, 0);
+    OPTENT3(0, "scanline_compression", OPT_FLAG, 
+            NULL,                   &scanline_compression, 0);
+    OPTENT3(0, "rle_compression",  OPT_FLAG, 
+            NULL,                   &rle_compression, 0);
+    OPTENT3(0, "packbits_compression", OPT_FLAG, 
+            NULL,                   &packbits_compression, 0);
+    OPTENT3(0, "verbose",          OPT_FLAG, 
+            NULL,                   &cmdlineP->verbose, 0);
+    OPTENT3(0, "colormap",         OPT_FLAG, 
+            NULL,                   &cmdlineP->colormap, 0);
+    OPTENT3(0, "offset",           OPT_FLAG, 
+            NULL,                   &cmdlineP->offset, 0);
+    OPTENT3(0, "density",          OPT_UINT, 
+            &cmdlineP->density,     &densitySpec, 0);
+    OPTENT3(0, "withdummy",        OPT_FLAG, 
+            NULL,                   &cmdlineP->withdummy, 0);
+
+    opt.opt_table = option_def;
+    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);
+        /* Uses and sets argc, argv, and some of *cmdline_p and others. */
+
+    if (depthSpec) {
+        if (cmdlineP->depth != 1 && cmdlineP->depth != 2 
+            && cmdlineP->depth != 4 && cmdlineP->depth != 8
+            && cmdlineP->depth != 16)
+            pm_error("invalid value for -depth: %u.  Valid values are "
+                     "1, 2, 4, 8, and 16", cmdlineP->depth);
+    } else
+        cmdlineP->depth = 0;
+
+    if (maxdepthSpec) {
+        if (cmdlineP->maxdepth != 1 && cmdlineP->maxdepth != 2 
+            && cmdlineP->maxdepth != 4 && cmdlineP->maxdepth != 8
+            && cmdlineP->maxdepth != 16)
+            pm_error("invalid value for -maxdepth: %u.  Valid values are "
+                     "1, 2, 4, 8, and 16", cmdlineP->maxdepth);
+    } else
+        cmdlineP->maxdepth = 0;
+
+    if (depthSpec && maxdepthSpec && 
+        cmdlineP->depth > cmdlineP->maxdepth)
+        pm_error("-depth value (%u) is greater than -maxdepth (%u) value.",
+                 cmdlineP->depth, cmdlineP->maxdepth);
+
+    if (!transSpec)
+        cmdlineP->transparent = NULL;
+
+    if (densitySpec) {
+        if (cmdlineP->density != PALM_DENSITY_LOW &&
+            cmdlineP->density != PALM_DENSITY_ONEANDAHALF &&
+            cmdlineP->density != PALM_DENSITY_DOUBLE &&
+            cmdlineP->density != PALM_DENSITY_TRIPLE &&
+            cmdlineP->density != PALM_DENSITY_QUADRUPLE)
+            pm_error("Invalid value for -density: %d.  Valid values are "
+                     "%d, %d, %d, %d and %d.", cmdlineP->density, 
+                     PALM_DENSITY_LOW, PALM_DENSITY_ONEANDAHALF,
+                     PALM_DENSITY_DOUBLE, PALM_DENSITY_TRIPLE,
+                     PALM_DENSITY_QUADRUPLE);
+    } else
+        cmdlineP->density = PALM_DENSITY_LOW;
+
+    if (cmdlineP->density != PALM_DENSITY_LOW && cmdlineP->withdummy)
+            pm_error("You can't specify -withdummy with -density value %u.  "
+                     "It is valid only with low density (%u)",
+                     cmdlineP->density, PALM_DENSITY_LOW);
+
+    if (cmdlineP->withdummy && !cmdlineP->offset)
+        pm_error("-withdummy does not make sense without -offset");
+
+    if (scanline_compression + rle_compression + packbits_compression > 1)
+        pm_error("You may specify only one of -scanline_compression, "
+                 "-rle_compression, and -packbits_compression");
+    else {
+        if (scanline_compression)
+            cmdlineP->compression = COMP_SCANLINE;
+        else if (rle_compression)
+            cmdlineP->compression = COMP_RLE;
+        else if (packbits_compression)
+            cmdlineP->compression = COMP_PACKBITS;
+        else
+            cmdlineP->compression = COMP_NONE;
+    }
+        
+    if (argc-1 > 1)
+        pm_error("This program takes at most 1 argument: the file name.  "
+                 "You specified %d", argc-1);
+    else if (argc-1 > 0) 
+        cmdlineP->inputFilespec = argv[1];
+    else
+        cmdlineP->inputFilespec = "-";
+}
+
+
+
+static void
+determinePalmFormat(unsigned int   const cols, 
+                    unsigned int   const rows, 
+                    xelval         const maxval, 
+                    int            const format, 
+                    xel **         const xels,
+                    unsigned int   const specified_bpp,
+                    unsigned int   const max_bpp, 
+                    bool           const custom_colormap,
+                    bool           const verbose,
+                    unsigned int * const bppP, 
+                    bool *         const directColorP, 
+                    Colormap *     const colormapP) {
+
+    if (PNM_FORMAT_TYPE(format) == PBM_TYPE) {
+        if (custom_colormap)
+            pm_error("You specified -colormap with a black and white input "
+                     "image.  -colormap is valid only with color.");
+        if (specified_bpp)
+            *bppP = specified_bpp;
+        else
+            *bppP = 1;    /* no point in wasting bits */
+        *directColorP = FALSE;
+        *colormapP = NULL;
+        if (verbose)
+            pm_message("output is black and white");
+    } else if (PNM_FORMAT_TYPE(format) == PGM_TYPE) {
+        /* we can usually handle this one, but may not have enough
+           pixels.  So check... */
+        if (custom_colormap)
+            pm_error("You specified -colormap with a black and white input"
+                     "image.  -colormap is valid only with color.");
+        if (specified_bpp)
+            *bppP = specified_bpp;
+        else if (max_bpp && (maxval >= (1 << max_bpp)))
+            *bppP = max_bpp;
+        else if (maxval > 16)
+            *bppP = 4;
+        else {
+            /* scale to minimum number of bpp needed */
+            for (*bppP = 1;  (1 << *bppP) < maxval;  *bppP *= 2)
+                ;
+        }
+        if (*bppP > 4)
+            *bppP = 4;
+        if (verbose)
+            pm_message("output is grayscale %d bits-per-pixel", *bppP);
+        *directColorP = FALSE;
+        *colormapP = NULL;
+    } else if (PNM_FORMAT_TYPE(format) == PPM_TYPE) {
+
+        /* We assume that we only get a PPM if the image cannot be
+           represented as PBM or PGM.  There are two options here: either
+           8-bit with a colormap, either the standard one or a custom one,
+           or 16-bit direct color.  In the 8-bit case, if "custom_colormap"
+           is specified (not recommended by Palm) we will put in our own
+           colormap; otherwise we will assume that the colors have been
+           mapped to the default Palm colormap by appropriate use of
+           pnmquant.  We try for 8-bit color first, since it works on
+           more PalmOS devices. 
+        */
+        if ((specified_bpp == 16) || 
+            (specified_bpp == 0 && max_bpp == 16)) {
+            /* we do the 16-bit direct color */
+            *directColorP = TRUE;
+            *colormapP = NULL;
+            *bppP = 16;
+        } else if (!custom_colormap) {
+            /* standard indexed 8-bit color */
+            *colormapP = palmcolor_build_default_8bit_colormap();
+            *bppP = 8;
+            if (((specified_bpp != 0) && (specified_bpp != 8)) ||
+                ((max_bpp != 0) && (max_bpp < 8)))
+                pm_error("Must use depth of 8 for color Palm Bitmap without "
+                         "custom color table.");
+            *directColorP = FALSE;
+            if (verbose)
+                pm_message("Output is color with default colormap at 8 bpp");
+        } else {
+            /* indexed 8-bit color with a custom colormap */
+            *colormapP = 
+                palmcolor_build_custom_8bit_colormap(rows, cols, xels);
+            for (*bppP = 1; (1 << *bppP) < (*colormapP)->ncolors; *bppP *= 2);
+            if (specified_bpp != 0) {
+                if (specified_bpp >= *bppP)
+                    *bppP = specified_bpp;
+                else
+                    pm_error("Too many colors for specified depth.  "
+                             "Use pnmquant to reduce.");
+            } else if ((max_bpp != 0) && (max_bpp < *bppP)) {
+                pm_error("Too many colors for specified max depth.  "
+                         "Use pnmquant to reduce.");
+            }
+            *directColorP = FALSE;
+            if (verbose)
+                pm_message("Output is color with custom colormap "
+                           "with %d colors at %d bpp", 
+                           (*colormapP)->ncolors, *bppP);
+        }
+    } else {
+        pm_error("unknown format 0x%x on input file", (unsigned) format);
+    }
+}
+
+
+
+static const char * 
+formatName(int const format) {
+    
+    const char * retval;
+
+    switch(PNM_FORMAT_TYPE(format)) {
+    case PBM_TYPE: retval = "black and white"; break;
+    case PGM_TYPE: retval = "grayscale";       break;
+    case PPM_TYPE: retval = "color";           break;
+    default:       retval = "???";             break;
+    }
+    return retval;
+}
+
+        
+
+static void
+findTransparentColor(char *         const colorSpec, 
+                     pixval         const newMaxval,
+                     bool           const directColor, 
+                     pixval         const maxval, 
+                     Colormap       const colormap,
+                     xel *          const transcolorP, 
+                     unsigned int * const transindexP) {
+
+    *transcolorP = ppm_parsecolor(colorSpec, maxval);
+    if (!directColor) {
+        Color_s const temp_color = 
+            ((((PPM_GETR(*transcolorP)*newMaxval) / maxval) << 16) 
+             | (((PPM_GETG(*transcolorP)*newMaxval) / maxval) << 8)
+             | ((PPM_GETB(*transcolorP)*newMaxval) / maxval));
+        Color const found = 
+            (bsearch(&temp_color,
+                     colormap->color_entries, colormap->ncolors,
+                     sizeof(Color_s), palmcolor_compare_colors));
+        if (!found) {
+            pm_error("Specified transparent color %s not found "
+                     "in colormap.", colorSpec);
+        } else
+            *transindexP = (*found >> 24) & 0xFF;
+    }
+}
+
+
+
+static unsigned int
+bitmapVersion(unsigned int         const bpp,
+              bool                 const colormap,
+              bool                 const transparent,
+              enum compressionType const compression,
+              unsigned int         const density) {
+/*----------------------------------------------------------------------------
+   Return the version number of the oldest version that can represent
+   the specified attributes.
+-----------------------------------------------------------------------------*/
+    unsigned int version;
+    /* we need Version 1 if we use more than 1 bpp,
+       Version 2 if we use compression or transparency,
+       Version 3 if density is 108 or higher
+    */
+    if (density > PALM_DENSITY_LOW)
+        version = 3;
+    else if (transparent || compression != COMP_NONE)
+        version = 2;
+    else if (bpp > 1 || colormap)
+        version = 1;
+    else
+        version = 0;
+
+    return version;
+}
+
+
+
+static void
+writeCommonHeader(unsigned int         const cols,
+                  unsigned int         const rows,
+                  unsigned int         const rowbytes,
+                  enum compressionType const compression,
+                  bool                 const colormap,
+                  bool                 const transparent,
+                  bool                 const directColor,
+                  unsigned int         const bpp,
+                  unsigned int         const version) {
+/*----------------------------------------------------------------------------
+   Write the first 10 bytes of the Palm Bitmap header.
+   These are common to all encodings (versions 0, 1, 2 and 3).
+-----------------------------------------------------------------------------*/
+    unsigned short flags;
+
+    if (cols > USHRT_MAX)
+        pm_error("Too many columns for Palm Bitmap: %u", cols);
+    pm_writebigshort(stdout, cols);    /* width */
+    if (rows > USHRT_MAX)
+        pm_error("Too many columns for Palm Bitmap: %u", rows);
+    pm_writebigshort(stdout, rows);    /* height */
+    if (rowbytes > USHRT_MAX)
+        pm_error("Too many bytes per row for Palm Bitmap: %u", rowbytes);
+    pm_writebigshort(stdout, rowbytes);
+
+    flags = 0;  /* initial value */
+    if (compression != COMP_NONE)
+        flags |= PALM_IS_COMPRESSED_FLAG;
+    if (colormap)
+        flags |= PALM_HAS_COLORMAP_FLAG;
+    if (transparent)
+        flags |= PALM_HAS_TRANSPARENCY_FLAG;
+    if (directColor)
+        flags |= PALM_DIRECT_COLOR_FLAG;
+    pm_writebigshort(stdout, flags);
+    assert(bpp <= UCHAR_MAX);
+    fputc(bpp, stdout);
+
+    fputc(version, stdout);
+}
+
+
+
+static unsigned char 
+compressionFieldValue(enum compressionType const compression) {
+
+    unsigned char retval;
+
+    switch (compression) {
+    case COMP_SCANLINE:
+        retval = PALM_COMPRESSION_SCANLINE;
+        break;
+    case COMP_RLE:
+        retval = PALM_COMPRESSION_RLE;
+        break;
+    case COMP_PACKBITS:
+        retval = PALM_COMPRESSION_PACKBITS;
+        break;
+    case COMP_NONE:
+        retval = 0x00;  /* empty */
+        break;
+    }
+    return retval;
+}
+
+
+
+static void
+writeRemainingHeaderLow(unsigned int         const nextDepthOffset,
+                        unsigned int         const transindex,
+                        enum compressionType const compression,
+                        unsigned int         const bpp) {
+/*----------------------------------------------------------------------------
+   Write last 6 bytes of a low density Palm Bitmap header. 
+-----------------------------------------------------------------------------*/
+    if (nextDepthOffset > USHRT_MAX)
+        pm_error("Image too large for Palm Bitmap");
+
+    pm_writebigshort(stdout, nextDepthOffset);
+
+    if (bpp != 16) {
+        assert(transindex <= UCHAR_MAX);
+        fputc(transindex, stdout);    /* transparent index */
+    } else
+        fputc(0, stdout);    /* the DirectInfoType will hold this info */
+    
+    fputc(compressionFieldValue(compression), stdout);
+
+    pm_writebigshort(stdout, 0);  /* reserved by Palm */
+}
+
+
+
+static void
+writeRemainingHeaderHigh(unsigned int         const bpp,
+                         enum compressionType const compression,
+                         unsigned int         const density,
+                         xelval               const maxval,
+                         bool                 const transparent,
+                         xel                  const transcolor,
+                         unsigned int         const transindex,
+                         unsigned int         const nextBitmapOffset) {
+/*----------------------------------------------------------------------------
+   Write last 16 bytes of a high density Palm Bitmap header. 
+-----------------------------------------------------------------------------*/
+    if ((nextBitmapOffset >> 31) > 1)
+        pm_error("Image too large for Palm Bitmap.  nextBitmapOffset "
+            "value doesn't fit in 4 bytes");
+
+    fputc(0x18, stdout); /* size of this high density header */
+
+    if (bpp != 16)
+        fputc(PALM_FORMAT_INDEXED, stdout);
+    else
+        fputc(PALM_FORMAT_565, stdout);
+
+    fputc(0x00, stdout); /* unused */
+
+    fputc(compressionFieldValue(compression), stdout);
+
+    pm_writebigshort(stdout, density);
+
+    if (transparent) {
+        if (bpp == 16) {
+            /* Blind guess here */
+            fputc(0, stdout);
+            fputc((PPM_GETR(transcolor) * 255) / maxval, stdout);
+            fputc((PPM_GETG(transcolor) * 255) / maxval, stdout);
+            fputc((PPM_GETB(transcolor) * 255) / maxval, stdout);
+        } else {
+            assert(transindex <= UCHAR_MAX);
+            fputc(0, stdout);
+            fputc(0, stdout);
+            fputc(0, stdout);
+            fputc(transindex, stdout);   /* transparent index */
+        }
+    } else
+        pm_writebiglong(stdout, 0);
+
+    pm_writebiglong(stdout, nextBitmapOffset);
+}
+
+
+
+static void
+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
+   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
+   in the stream is understandable by a new viewer, but would confuse an
+   old one.
+-----------------------------------------------------------------------------*/
+    pm_writebiglong(stdout, 0x00);
+    pm_writebiglong(stdout, 0x00);
+    fputc(0xFF, stdout);               /* pixelSize */
+    fputc(0x01, stdout);               /* version */
+    pm_writebigshort(stdout, 0x00); 
+    pm_writebiglong(stdout, 0x00);
+}
+
+
+
+static void
+writeColormap(bool         const explicitColormap,
+              Colormap     const colormap,
+              bool         const directColor,
+              unsigned int const bpp,
+              bool         const transparent,
+              xel          const transcolor,
+              xelval       const maxval,
+              unsigned int const version) {
+              
+    /* if there's a colormap, write it out */
+    if (explicitColormap) {
+        unsigned int row;
+        if (!colormap)
+            pm_error("Internal error: user specified -colormap, but we did "
+                     "not generate a colormap.");
+        qsort (colormap->color_entries, colormap->ncolors,
+               sizeof(Color_s), palmcolor_compare_indices);
+        pm_writebigshort( stdout, colormap->ncolors );
+        for (row = 0;  row < colormap->ncolors; ++row)
+            pm_writebiglong (stdout, colormap->color_entries[row]);
+    }
+
+    if (directColor && (version < 3)) {
+        /* write the DirectInfoType (8 bytes) */
+        if (bpp == 16) {
+            fputc(5, stdout);   /* # of bits of red */
+            fputc(6, stdout);   /* # of bits of green */    
+            fputc(5, stdout);   /* # of bits of blue */
+            fputc(0, stdout);   /* reserved by Palm */
+        } else
+            pm_error("Don't know how to create %d bit DirectColor bitmaps.", 
+                     bpp);
+        if (transparent) {
+            fputc(0, stdout);
+            fputc((PPM_GETR(transcolor) * 255) / maxval, stdout);
+            fputc((PPM_GETG(transcolor) * 255) / maxval, stdout);
+            fputc((PPM_GETB(transcolor) * 255) / maxval, stdout);
+        } else
+            pm_writebiglong(stdout, 0);     /* no transparent color */
+    }
+}
+
+
+
+static void
+computeRawRowDirectColor(const xel *     const xelrow,
+                         unsigned int    const cols,
+                         xelval          const maxval,
+                         unsigned char * const rowdata) {
+
+    unsigned int col;
+    unsigned char *outptr;
+    
+    for (col = 0, outptr = rowdata; col < cols; ++col) {
+        unsigned int const color = 
+            ((((PPM_GETR(xelrow[col])*31)/maxval) << 11) |
+             (((PPM_GETG(xelrow[col])*63)/maxval) << 5) |
+             ((PPM_GETB(xelrow[col])*31)/maxval));
+        *outptr++ = (color >> 8) & 0xFF;
+        *outptr++ = color & 0xFF;
+    }
+}
+
+
+
+static void
+computeRawRowNonDirect(const xel *     const xelrow,
+                       unsigned int    const cols,
+                       xelval          const maxval,
+                       unsigned int    const bpp,
+                       Colormap        const colormap,
+                       unsigned int    const newMaxval,
+                       unsigned char * const rowdata) {
+
+    unsigned int col;
+    unsigned char *outptr;
+    unsigned char outbyte;
+        /* Accumulated bits to be output */
+    unsigned char outbit;
+        /* The lowest bit number we want to access for this pixel */
+
+    outbyte = 0x00;
+    outptr = rowdata;
+
+    for (outbit = 8 - bpp, col = 0; col < cols; ++col) {
+        unsigned int color;
+        if (!colormap) {
+            /* we assume grayscale, and use simple scaling */
+            color = (PNM_GET1(xelrow[col]) * newMaxval)/maxval;
+            if (color > newMaxval)
+                pm_error("oops.  Bug in color re-calculation code.  "
+                         "color of %u.", color);
+            color = newMaxval - color; /* note grayscale maps are inverted */
+        } else {
+            Color_s const temp_color =
+                ((((PPM_GETR(xelrow[col])*newMaxval)/maxval)<<16) 
+                 | (((PPM_GETG(xelrow[col])*newMaxval)/maxval)<<8)
+                 | (((PPM_GETB(xelrow[col])*newMaxval)/maxval)));
+            Color const found = (bsearch (&temp_color,
+                                          colormap->color_entries, 
+                                          colormap->ncolors,
+                                          sizeof(Color_s), 
+                                          palmcolor_compare_colors));
+            if (!found) {
+                pm_error("Color %d:%d:%d not found in colormap.  "
+                         "Try using pnmquant to reduce the "
+                         "number of colors.",
+                         PPM_GETR(xelrow[col]), 
+                         PPM_GETG(xelrow[col]), 
+                         PPM_GETB(xelrow[col]));
+            }
+            color = (*found >> 24) & 0xFF;
+        }
+
+        if (color > newMaxval)
+            pm_error("oops.  Bug in color re-calculation code.  "
+                     "color of %u.", color);
+        outbyte |= (color << outbit);
+        if (outbit == 0) {
+            /* Bit buffer is full.  Flush to to rowdata. */
+            *outptr++ = outbyte;
+            outbyte = 0x00;
+            outbit = 8 - bpp;
+        } else
+            outbit -= bpp;
+    }
+    if ((cols % (8 / bpp)) != 0) {
+        /* Flush bits remaining in the bit buffer to rowdata */
+        *outptr++ = outbyte;
+    }
+}
+
+
+struct seqBuffer {
+/*----------------------------------------------------------------------------
+   A buffer to which one can write bytes sequentially.
+-----------------------------------------------------------------------------*/
+    char * buffer;
+    unsigned int allocatedSize;
+    unsigned int occupiedSize;
+};
+
+
+static void
+createBuffer(struct seqBuffer ** const bufferPP) {
+
+    struct seqBuffer * bufferP;
+
+    MALLOCVAR_NOFAIL(bufferP);
+
+    bufferP->allocatedSize = 4096;
+    MALLOCARRAY(bufferP->buffer, bufferP->allocatedSize);
+    if (bufferP == NULL)
+        pm_error("Unable to allocate %u bytes of buffer", 
+                 bufferP->allocatedSize);
+    bufferP->occupiedSize = 0;
+
+    *bufferPP = bufferP;
+}
+
+
+
+static void
+destroyBuffer(struct seqBuffer * const bufferP) {
+
+    free(bufferP->buffer);
+    free(bufferP);
+}
+
+
+
+static void
+addByteToBuffer(struct seqBuffer * const bufferP,
+                unsigned char      const newByte) {
+
+    assert(bufferP->allocatedSize >= bufferP->occupiedSize);
+
+    if (bufferP->allocatedSize == bufferP->occupiedSize) {
+        bufferP->allocatedSize *= 2;
+        REALLOCARRAY(bufferP->buffer, bufferP->allocatedSize);
+        if (bufferP->buffer == NULL)
+            pm_error("Couldn't (re)allocate %u bytes of memory "
+                     "for buffer.", bufferP->allocatedSize);
+    }
+    bufferP->buffer[bufferP->occupiedSize++] = newByte;
+}
+
+
+
+static unsigned int
+bufferLength(struct seqBuffer * const bufferP) {
+    return bufferP->occupiedSize;
+}
+
+
+
+static void
+writeOutBuffer(struct seqBuffer * const bufferP,
+               FILE *             const fileP) {
+
+    size_t bytesWritten;
+
+    bytesWritten = fwrite(bufferP->buffer, sizeof(char), 
+                          bufferP->occupiedSize, fileP);
+
+    if (bytesWritten != bufferP->occupiedSize)
+        pm_error("fwrite() failed to write out the buffer.");
+}
+
+
+
+static void
+copyRowToBuffer(const unsigned char * const rowdata,
+                unsigned int          const rowbytes,
+                struct seqBuffer *    const rasterBufferP) {
+
+    unsigned int pos;
+    for (pos = 0; pos < rowbytes; ++pos)
+        addByteToBuffer(rasterBufferP, rowdata[pos]);
+} 
+
+
+
+static void
+scanlineCompressAndBufferRow(const unsigned char * const rowdata,
+                             unsigned int          const rowbytes,
+                             struct seqBuffer *    const rasterBufferP,
+                             const unsigned char * const lastrow) {
+/*----------------------------------------------------------------------------
+   Take the raw Palm Bitmap row 'rowdata', which is 'rowbytes'
+   columns, and add the scanline-compressed representation of it to
+   the buffer with handle 'rasterBufferP'.
+
+   'lastrow' is the raw contents of the row immediately before the one
+   we're compressing -- i.e. we compress with respect to that row.  This
+   function does not work on the first row of an image.
+-----------------------------------------------------------------------------*/
+    unsigned int pos;
+
+    for (pos = 0;  pos < rowbytes;  pos += 8) {
+        unsigned int const limit = MIN(rowbytes - pos, 8);
+
+        unsigned char map;
+            /* mask indicating which of the next 8 pixels are
+               different from the previous row, and therefore present
+               in the file immediately following the map byte.  
+            */
+        unsigned char differentPixels[8];
+        unsigned char *outptr;
+        unsigned char outbit;
+            
+        for (outbit = 0, map = 0x00, outptr = differentPixels;
+             outbit < limit;  
+             ++outbit) {
+            if (!lastrow 
+                || (lastrow[pos + outbit] != rowdata[pos + outbit])) {
+                map |= (1 << (7 - outbit));
+                *outptr++ = rowdata[pos + outbit];
+            }
+        }
+
+        addByteToBuffer(rasterBufferP, map);
+        {
+            unsigned int j;
+            for (j = 0; j < (outptr - differentPixels); ++j)
+                addByteToBuffer(rasterBufferP, differentPixels[j]);
+        }
+    }
+}
+
+
+
+static void
+rleCompressAndBufferRow(const unsigned char * const rowdata,
+                        unsigned int          const rowbytes,
+                        struct seqBuffer *    const rasterBufferP) {
+/*----------------------------------------------------------------------------
+   Take the raw Palm Bitmap row 'rowdata', which is 'rowbytes' bytes,
+   and add the rle-compressed representation of it to the buffer with
+   handle 'rasterBufferP'.
+-----------------------------------------------------------------------------*/
+    unsigned int pos;
+
+    /* we output a count of the number of bytes a value is
+       repeated, followed by that byte value 
+    */
+    pos = 0;
+    while (pos < rowbytes) {
+        unsigned int repeatcount;
+        for (repeatcount = 1;  
+             repeatcount < (rowbytes - pos) && repeatcount  < 255;  
+             ++repeatcount)
+            if (rowdata[pos + repeatcount] != rowdata[pos])
+                break;
+
+        addByteToBuffer(rasterBufferP, repeatcount);
+        addByteToBuffer(rasterBufferP, rowdata[pos]);
+        pos += repeatcount;
+    }
+}
+
+
+
+static void
+computeNextPackbitsRun(const unsigned char * const rowdata,
+                       unsigned int          const rowbytes,
+                       unsigned int          const startPos,
+                       unsigned int *        const nextPosP,
+                       unsigned char *       const output,
+                       int *                 const countP) {
+
+    unsigned int pos;
+    int count;
+    
+    pos = startPos;
+    count = 0;
+    
+    if (rowdata[pos] == rowdata[pos + 1]) {
+        ++pos;
+        --count;
+        while ((count > -127) && (pos < (rowbytes - 1)) &&
+               (rowdata[pos] == rowdata[pos + 1])) {
+            ++pos;
+            --count;
+        }
+        ++pos;  /* push pos past end of this run */
+    } else {
+        output[count] = rowdata[pos];
+        ++pos;
+        while ((count < 127) && (pos < (rowbytes - 1)) && 
+               (rowdata[pos] != rowdata[pos + 1])) {
+            ++count;
+            output[count] = rowdata[pos];
+            ++pos;
+        }
+        /* trailing literal */
+        if ((count < 127) && (pos == (rowbytes - 1)) &&
+            (rowdata[pos - 1] != rowdata[pos])) {
+            ++count;
+            output[count] = rowdata[pos];
+            ++pos;
+        }
+    }
+    *nextPosP = pos;
+    *countP = count;
+}
+
+
+
+static void
+addPackbitsRunToBuffer(const unsigned char * const rowdata,
+                       unsigned int          const rowbytes,
+                       unsigned int          const pos,
+                       unsigned char *       const output,
+                       int                   const count,
+                       struct seqBuffer *    const rasterBufferP) {
+
+    addByteToBuffer(rasterBufferP, (unsigned char)(signed char)count);
+    if (count < 0) {
+        addByteToBuffer(rasterBufferP, rowdata[pos - 1]);
+    } else {
+        unsigned int j;
+        for (j = 0; j <= count; j++)
+            addByteToBuffer(rasterBufferP, output[j]);
+    }
+    
+    if (pos == (rowbytes - 1) && (rowdata[pos - 1] != rowdata[pos])) {
+        /* orphaned byte, treat as literal */
+        addByteToBuffer(rasterBufferP, 0);
+        addByteToBuffer(rasterBufferP, rowdata[pos]);
+    }
+}
+
+
+
+static void
+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
+   add the packbits-compressed representation of it to the buffer 
+   with handle 'rasterBufferP'.
+-----------------------------------------------------------------------------*/
+    unsigned int position;
+        /* byte position within the row */
+
+    position = 0;  /* Start at beginning of row */
+
+    while (position < rowbytes - 1) {
+        unsigned char output[128];
+        int count;
+
+        computeNextPackbitsRun(rowdata, rowbytes, position, 
+                               &position, output, &count);
+
+        addPackbitsRunToBuffer(rowdata, rowbytes, position, output, count,
+                               rasterBufferP);
+    }
+}
+
+
+
+static void
+bufferRowFromRawRowdata(const unsigned char *  const rowdata,
+                        unsigned int           const rowbytes,
+                        enum compressionType   const compression,
+                        const unsigned char *  const lastrow,
+                        struct seqBuffer *     const rasterBufferP) {
+/*----------------------------------------------------------------------------
+   Starting with a raw (uncompressed) Palm raster line, do the
+   compression identified by 'compression' and add the compressed row
+   to the buffer with handle 'rasterBufferP'.
+
+   If 'compression' indicates scanline compression, 'lastrow' is the
+   row immediately preceding this one in the image (and this function
+   doesn't work on the first row of an image).  Otherwise, 'lastrow'
+   is meaningless.
+-----------------------------------------------------------------------------*/
+    switch (compression) {
+    case COMP_NONE:
+        copyRowToBuffer(rowdata, rowbytes, rasterBufferP);
+        break;
+    case COMP_SCANLINE:
+        scanlineCompressAndBufferRow(rowdata, rowbytes, rasterBufferP, 
+                                     lastrow);
+        break;
+    case COMP_RLE:
+        rleCompressAndBufferRow(rowdata, rowbytes, rasterBufferP);
+        break;
+    case COMP_PACKBITS:
+        packbitsCompressAndBufferRow(rowdata, rowbytes, rasterBufferP);
+        break;
+    }
+}
+
+
+
+static void
+bufferRow(const xel *          const xelrow,
+          unsigned int         const cols,
+          xelval               const maxval,
+          unsigned int         const rowbytes,
+          unsigned int         const bpp,
+          unsigned int         const newMaxval,
+          enum compressionType const compression,
+          bool                 const directColor,
+          Colormap             const colormap,
+          unsigned char *      const rowdata,
+          unsigned char *      const lastrow,
+          struct seqBuffer *   const rasterBufferP) {
+/*----------------------------------------------------------------------------
+   Add a row of the Palm Bitmap raster to buffer 'rasterBufferP'.
+   
+   'xelrow' is the image contents of row.  It is 'cols' columns wide.
+
+   If 'compression' indicates scanline compression, 'lastrow' is the
+   row immediately preceding this one in the image (and this function
+   doesn't work on the first row of an image).  Otherwise, 'lastrow'
+   is meaningless.
+
+   'rowdata' is a work buffer 'rowbytes' in size.
+-----------------------------------------------------------------------------*/
+    if (directColor)
+        computeRawRowDirectColor(xelrow, cols, maxval, rowdata);
+    else 
+        computeRawRowNonDirect(xelrow, cols, maxval, bpp, colormap, newMaxval,
+                               rowdata);
+
+    bufferRowFromRawRowdata(rowdata, rowbytes, compression,
+                            lastrow, rasterBufferP);
+}
+
+
+
+static void 
+bufferRaster(xel **               const xels,
+             unsigned int         const cols,
+             unsigned int         const rows,
+             xelval               const maxval,
+             unsigned int         const rowbytes,
+             unsigned int         const bpp,
+             unsigned int         const newMaxval,
+             enum compressionType const compression,
+             bool                 const directColor,
+             Colormap             const colormap,
+             struct seqBuffer **  const rasterBufferPP) {
+    
+    unsigned char * rowdata;
+    unsigned char * lastrow;
+    unsigned int row;
+
+    createBuffer(rasterBufferPP);
+    
+    MALLOCARRAY_NOFAIL(rowdata, rowbytes);
+    MALLOCARRAY_NOFAIL(lastrow, rowbytes);
+
+    /* And write out the data. */
+    for (row = 0; row < rows; ++row) {
+        bufferRow(xels[row], cols, maxval, rowbytes, bpp, newMaxval,
+                  compression,
+                  directColor, colormap, rowdata, row > 0 ? lastrow : NULL,
+                  *rasterBufferPP);
+
+        if (compression == COMP_SCANLINE)
+            memcpy(lastrow, rowdata, rowbytes);
+    }
+    free(lastrow);
+    free(rowdata);
+}
+
+
+
+static void
+computeOffsetStuff(bool                 const offsetWanted,
+                   unsigned int         const version,
+                   bool                 const directColor,
+                   enum compressionType const compression,
+                   bool                 const colormap,
+                   unsigned int         const colormapColorCount,
+                   unsigned int         const sizePlusRasterSize,
+                   unsigned int *       const nextDepthOffsetP,
+                   unsigned int *       const nextBitmapOffsetP,
+                   unsigned int *       const padBytesRequiredP) {
+    
+    if (offsetWanted) {
+        /* Offset is measured in 4-byte words (double words in
+           Intel/Microsoft terminology).  Account for header,
+           colormap, and raster size and round up 
+        */
+        unsigned int const headerSize = ((version < 3) ? 16 : 24);
+        unsigned int const colormapSize =
+            (colormap ? (2 + colormapColorCount * 4) : 0);
+        if (version < 3) {
+            unsigned int const directSize = 
+                (directColor && version < 3) ? 8 : 0; 
+            if (compression != COMP_NONE && sizePlusRasterSize > USHRT_MAX)
+                pm_error("Oversized compressed bitmap: %u bytes",
+                         sizePlusRasterSize);
+            *padBytesRequiredP = 4 - (sizePlusRasterSize + headerSize + 
+                                      directSize + colormapSize) % 4;
+            *nextDepthOffsetP = 
+                (sizePlusRasterSize + headerSize + 
+                 directSize + colormapSize + *padBytesRequiredP) / 4;
+        } else {
+            if (compression != COMP_NONE && (sizePlusRasterSize >> 31) > 1)
+                pm_error("Oversized compressed bitmap: %u bytes",
+                         sizePlusRasterSize);
+            /* Does version 3 need padding? Probably won't hurt */
+            *padBytesRequiredP = 4 - (sizePlusRasterSize + headerSize +
+                                      colormapSize) % 4;
+            *nextBitmapOffsetP = sizePlusRasterSize + headerSize + 
+                colormapSize + *padBytesRequiredP;
+        }
+    } else {
+        *padBytesRequiredP = 0;
+        *nextDepthOffsetP = 0;
+        *nextBitmapOffsetP = 0;
+    }
+}
+
+
+
+static void
+writeRasterSize(unsigned int const sizePlusRasterSize,
+                unsigned int const version,
+                FILE *       const fileP) {
+/*----------------------------------------------------------------------------
+   Write to file 'fileP' a raster size field for a Palm Bitmap version
+   'version' header, indicating 'sizePlusRasterSize' bytes.
+-----------------------------------------------------------------------------*/
+    if (version < 3) 
+        pm_writebigshort(fileP, sizePlusRasterSize);
+    else
+        pm_writebiglong(fileP, sizePlusRasterSize);
+}
+
+
+
+static void
+writeBitmap(xel **               const xels,
+            unsigned int         const cols,
+            unsigned int         const rows,
+            xelval               const maxval,
+            unsigned int         const rowbytes,
+            unsigned int         const bpp,
+            unsigned int         const newMaxval,
+            enum compressionType const compression,
+            bool                 const transparent,
+            bool                 const directColor,
+            bool                 const offsetWanted,
+            bool                 const hasColormap,
+            Colormap             const colormap,
+            unsigned int         const transindex,
+            xel                  const transcolor,
+            unsigned int         const version,
+            unsigned int         const density,
+            bool                 const withdummy) {
+    
+    unsigned int sizePlusRasterSize;
+    unsigned int nextDepthOffset;
+    unsigned int nextBitmapOffset;
+        /* Offset from the beginning of the image we write to the beginning
+           of the next one, assuming user writes another one following this
+           one.
+           nextDepthOffset is used in encodings 1, 2 and is in 4 byte words 
+           nextBitmapOffset is used in encoding 3, is in 4 bytes 
+        */
+    unsigned int padBytesRequired;
+        /* Number of bytes of padding we need to put after the image in
+           order to align properly for User to add the next image to the
+           stream.
+        */
+    struct seqBuffer * rasterBufferP;
+
+    writeCommonHeader(cols, rows, rowbytes, compression, hasColormap, 
+                      transparent, directColor, bpp, version);
+    
+    bufferRaster(xels, cols, rows, maxval, rowbytes, bpp, newMaxval,
+                 compression, directColor, colormap, &rasterBufferP);
+
+    /* rasterSize itself takes 2 or 4 bytes */
+    if (version < 3)
+        sizePlusRasterSize = 2 + bufferLength(rasterBufferP);
+    else
+        sizePlusRasterSize = 4 + bufferLength(rasterBufferP);
+    
+    computeOffsetStuff(offsetWanted, version, directColor, compression,
+                       hasColormap, hasColormap ? colormap->ncolors : 0, 
+                       sizePlusRasterSize,
+                       &nextDepthOffset, &nextBitmapOffset,
+                       &padBytesRequired);
+
+    if (version < 3)
+        writeRemainingHeaderLow(nextDepthOffset, transindex, compression, bpp);
+    else
+        writeRemainingHeaderHigh(bpp, compression, density,
+                                 maxval, transparent, transcolor,
+                                 transindex, nextBitmapOffset);
+
+    writeColormap(hasColormap, colormap, directColor, bpp, 
+                  transparent, transcolor, maxval, version);
+
+    if (compression != COMP_NONE)
+        writeRasterSize(sizePlusRasterSize, version, stdout);
+
+    writeOutBuffer(rasterBufferP, stdout);
+
+    destroyBuffer(rasterBufferP);
+
+    {
+        unsigned int i;
+        for (i = 0; i < padBytesRequired; ++i)
+            fputc(0x00, stdout);
+    }
+
+    if (withdummy)
+        writeDummy();
+}        
+
+
+
+int 
+main( int argc, char **argv ) {
+    struct cmdline_info cmdline;
+    unsigned int version;
+    FILE* ifP;
+    xel** xels;
+    xel transcolor;
+    unsigned int transindex;
+    int rows, cols;
+    unsigned int rowbytes;
+    xelval maxval;
+    int format;
+    unsigned int bpp;
+    bool directColor;
+    unsigned int newMaxval;
+    Colormap colormap;
+    
+    /* Parse default params */
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    xels = pnm_readpnm(ifP, &cols, &rows, &maxval, &format);
+    pm_close(ifP);
+
+    if (cmdline.verbose)
+        pm_message("Input is %dx%d %s, maxval %d", 
+                   cols, rows, formatName(format), maxval);
+    
+    determinePalmFormat(cols, rows, maxval, format, xels, cmdline.depth,
+                        cmdline.maxdepth, cmdline.colormap, cmdline.verbose,
+                        &bpp, &directColor, &colormap);
+
+    newMaxval = (1 << bpp) - 1;
+
+    if (cmdline.transparent) 
+        findTransparentColor(cmdline.transparent, newMaxval, directColor,
+                             maxval, colormap, &transcolor, &transindex);
+    else 
+        transindex = 0;
+
+    rowbytes = ((cols + (16 / bpp -1)) / (16 / bpp)) * 2;    
+        /* bytes per row - always a word boundary */
+
+    version = bitmapVersion(bpp, cmdline.colormap, !!cmdline.transparent, 
+                            cmdline.compression, cmdline.density);
+
+    writeBitmap(xels, cols, rows, maxval,
+                rowbytes, bpp, newMaxval, cmdline.compression,
+                !!cmdline.transparent, directColor, cmdline.offset, 
+                cmdline.colormap, colormap, transindex, transcolor,
+                version, cmdline.density, cmdline.withdummy);
+    
+    return 0;
+}
diff --git a/converter/other/pnmtopclxl.c b/converter/other/pnmtopclxl.c
new file mode 100644
index 00000000..79ee092c
--- /dev/null
+++ b/converter/other/pnmtopclxl.c
@@ -0,0 +1,1204 @@
+/*
+ * -------------------------------------------------------------
+ *
+ *  (C) 2002 Jochen Karrer, Linuxdata GbR
+ *
+ *      convert a pnm to PCL-XL image 
+ *
+ * -------------------------------------------------------------
+ */
+
+/* Engineering note: One PCL-XL printer prints an error message like
+   this when it doesn't like the PCL it sees:
+
+   PCL XL error
+      Subsystem:  IMAGE
+      Error:      IllegalAttributeValue
+      Operator:   ReadImage
+      Position:   8
+
+   "Position" is the sequence number of the PCL operator it was trying
+   to execute.
+*/
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+#include "pam.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+
+#include "pclxl.h"
+
+#define PAPERWIDTH(format) (xlPaperFormats[format].width)
+#define PAPERHEIGHT(format) (xlPaperFormats[format].height)
+
+
+
+typedef struct InputSource {
+    const char *         name; 
+    struct InputSource * next;
+} InputSource;
+
+
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    InputSource * sourceP;
+    int dpi;
+    enum MediaSize format;
+    unsigned int feederSpec;
+    int feeder;
+    unsigned int outtraySpec;
+    int outtray;
+    unsigned int duplexSpec;
+    enum DuplexPageMode duplex;
+    unsigned int copiesSpec;
+    int copies;
+    unsigned int center;
+    float xoffs;
+    float yoffs;
+    unsigned int colorok;
+    unsigned int verbose;
+    const char * jobsetup;  /* -jobsetup option value.  NULL if none */
+    unsigned int rendergray;
+};
+
+
+
+static void
+parseCommandLine(int argc, 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 = malloc( 100*sizeof( optEntry ) );
+        /* Instructions to optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    char *formatOpt;
+    char *duplexOpt;
+    unsigned int dpiSpec, xoffsSpec, yoffsSpec, formatSpec, jobsetupSpec;
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "dpi",       OPT_UINT,    &cmdlineP->dpi,
+            &dpiSpec,         0);
+    OPTENT3(0, "xoffs",     OPT_FLOAT,   &cmdlineP->xoffs, 
+            &xoffsSpec,        0);
+    OPTENT3(0, "yoffs",     OPT_FLOAT,   &cmdlineP->yoffs, 
+            &yoffsSpec,        0);
+    OPTENT3(0, "format",    OPT_STRING,  &formatOpt, 
+            &formatSpec,        0);
+    OPTENT3(0, "duplex",    OPT_STRING,  &duplexOpt, 
+            &cmdlineP->duplexSpec,        0);
+    OPTENT3(0, "copies",    OPT_UINT,    &cmdlineP->copies,
+            &cmdlineP->copiesSpec,        0);
+    OPTENT3(0, "colorok",   OPT_FLAG,    NULL,                  
+            &cmdlineP->colorok, 0);
+    OPTENT3(0, "center",    OPT_FLAG,    NULL,                  
+            &cmdlineP->center, 0 );
+    OPTENT3(0, "feeder",    OPT_STRING,  &cmdlineP->feeder,
+            &cmdlineP->feederSpec,        0);
+    OPTENT3(0, "outtray",   OPT_STRING,  &cmdlineP->outtray,
+            &cmdlineP->outtraySpec,       0);
+    OPTENT3(0, "verbose",   OPT_FLAG,    NULL,                  
+            &cmdlineP->verbose, 0);
+    OPTENT3(0, "jobsetup",  OPT_STRING,  &cmdlineP->jobsetup,
+            &jobsetupSpec,      0);
+    OPTENT3(0, "rendergray", OPT_FLAG,    NULL,
+            &cmdlineP->rendergray, 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);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (!dpiSpec)
+        cmdlineP->dpi = 300;
+    if (!xoffsSpec)
+        cmdlineP->xoffs = 0.0;
+    if (!yoffsSpec)
+        cmdlineP->yoffs = 0.0;
+
+    if (cmdlineP->duplexSpec) {
+        if (strncmp(duplexOpt, "vertical", strlen(duplexOpt)) == 0)
+            cmdlineP->duplex = eDuplexVerticalBinding;
+        else if (strncmp(duplexOpt, "horizontal", strlen(duplexOpt)) == 0)
+            cmdlineP->duplex = eDuplexHorizontalBinding;
+        else
+            pm_error("Invalid value '%s' for -duplex option", duplexOpt);
+    }
+
+    if (formatSpec) {
+        bool found;
+        int i;
+        for (i = 0, found=FALSE; xlPaperFormats[i].name && !found; ++i) {
+            if (STREQ(xlPaperFormats[i].name, formatOpt)) {
+                found = TRUE;
+                cmdlineP->format = xlPaperFormats[i].xl_nr;
+            }
+        }
+        if (!found) {
+            int i;
+            pm_message("Valid -format values:");
+            for (i = 0; xlPaperFormats[i].name; ++i) {
+                if (xlPaperFormats[i].width > 0)
+                    pm_message("   %s", xlPaperFormats[i].name);
+            }
+            pm_error("Invalid -format option '%s' specified.", formatOpt);
+        }
+    } else
+        cmdlineP->format = eLetterPaper;
+
+    if (!jobsetupSpec)
+        cmdlineP->jobsetup = NULL;
+
+    if (argc-1 < 1) {
+        MALLOCVAR(cmdlineP->sourceP);
+        cmdlineP->sourceP->name = "-";
+    } else {
+        int i;
+        InputSource ** nextLinkP;
+
+        nextLinkP = &cmdlineP->sourceP;
+        for (i = 1; i < argc; ++i) {
+            InputSource * sourceP;
+            MALLOCVAR(sourceP);
+            sourceP->name = argv[i];
+            *nextLinkP = sourceP;
+            nextLinkP = &sourceP->next;
+            *nextLinkP = NULL;
+        }
+    }
+}
+
+
+
+#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 
+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;
+    }
+    return rle;
+}
+static void
+XY_RLEdelete(XY_rle *rle) {
+    free(rle->fbuf);
+    free(rle);
+}
+
+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;
+    }
+    if(rle->fbpos+129>rle->fbufsize) {
+        rle->fbufsize*=1.2; 
+        rle->fbuf=realloc(rle->fbuf,rle->fbufsize);
+        if(rle->fbuf==NULL) {
+            rle->error=-1;
+            rle->fbpos=0;
+            return -1;
+        }
+    }
+    rle->bpos=0;
+    rle->state=eSTART;
+    return 0;
+}
+static int
+XY_RLEfinish (XY_rle *rle) {
+    out(rle,rle->bpos);
+    if(rle->error<0) 
+        return rle->error;
+    else
+        return rle->fbpos;
+}
+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;
+    
+    }
+    rle->buf[rle->bpos++]=u;
+    if(rle->bpos==128) {
+        out(rle,rle->bpos);
+    }
+}
+
+
+
+static void
+XY_RLEput(XY_rle *rle,const unsigned char buf[],int count) 
+{
+    int i;
+    for(i=0;i<count;i++) {
+        rle_putbyte(rle,buf[i]);
+    }
+    
+}
+
+
+static int
+XY_Write(int fd, const void *buf,int cnt) {
+        int len=0;
+        while(len<cnt) {
+                int n = write(fd,(char*)buf+len,cnt-len);
+                if(n<=0)
+                        return n;
+                len+=n;
+        }
+        return len;
+}
+#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;
+
+struct tPrinter { 
+    const char *name;
+    float topmargin;
+    float bottommargin;
+    float leftmargin;
+    float rightmargin;
+} xlPrinters[] = {
+    { "lj2200",0,0,0,0 }
+};
+
+
+
+static int
+out_ubyte(int fd,unsigned char data) {
+    return XY_Write(fd,&data,1);
+}
+static  int 
+XL_Operator(int fd,enum Operator const data)  {
+    return out_ubyte(fd,data);
+}
+static int
+out_uint16(int fd,unsigned short data ) {
+    unsigned char c[2];
+    c[0]=data&0xff; c[1]=data>>8;
+    return XY_Write(fd,c,2);
+}
+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;    
+    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);
+}
+static int
+xl_sint16(int fd,signed short data ) {
+    unsigned char const c=0xc3;
+    XY_Write(fd,&c,1);
+    return out_sint16(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);
+}
+#endif
+
+
+
+static int
+xl_ubyte_array(int                   const fd,
+               const unsigned char * const data,
+               int                   const len) {
+
+    unsigned int i;
+    unsigned char head[4];
+    
+    head[0] = 0xc8;
+    head[1] = 0xc1;
+    head[2] = len&0xff;
+    head[3] = (len>>8)&0xff;
+
+    XY_Write(fd, head, 4);
+
+    for (i = 0; i < len; ++i)
+        out_ubyte(fd, data[i]);
+
+    return 0;
+}
+
+
+
+#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<len;i++) {
+        out_uint16(fd,data[i]);
+    }
+    return 0;
+}
+static int
+xl_uint32_array(int fd,unsigned int *data,int len) {
+    int i;
+    unsigned char head[4];
+    head[0]=0xca;head[1]=0xc1;head[2]=len&0xff;head[3]=(len>>8)&0xff;
+    XY_Write(fd,head,4);
+    for(i=0;i<len;i++) {
+        out_uint32(fd,data[i]);
+    }
+    return 0;
+}
+static int
+xl_sint16_array(int fd,signed short *data,int len) {
+    int i;
+    unsigned char head[4];
+    head[0]=0xcb;head[1]=0xc1;head[2]=len&0xff;head[3]=(len>>8)&0xff;
+    XY_Write(fd,head,4);
+    for(i=0;i<len;i++) {
+        out_sint16(fd,data[i]);
+    }
+    return 0;
+}
+static int
+xl_sint32_array(int fd,signed int *data,int len) {
+    int i;
+    unsigned char head[4];
+    head[0]=0xcc;head[1]=0xc1;head[2]=len&0xff;head[3]=(len>>8)&0xff;
+    XY_Write(fd,head,4);
+    for(i=0;i<len;i++) {
+        out_sint32(fd,data[i]);
+    }
+    return 0;
+}
+
+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);
+}
+
+#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);
+}
+#endif 
+
+
+
+static void
+copyFile(const char * const sourceFileName,
+         int          const destFd) {
+
+    FILE * sourceFileP;
+
+    sourceFileP = pm_openr(sourceFileName);
+
+    while (!feof(sourceFileP)) {
+        char buffer[1024];
+        size_t bytesRead;
+        size_t totalBytesWritten;
+
+        bytesRead = fread(buffer, 1, sizeof(buffer), sourceFileP);
+
+        if (ferror(sourceFileP))
+            pm_error("Read from file failed.  errno=%d (%s)",
+                     errno, strerror(errno));
+        
+        totalBytesWritten = 0;
+        
+        while (totalBytesWritten < bytesRead) {
+            ssize_t rc;
+
+            rc = write(destFd, buffer, bytesRead);
+
+            if (rc < 0)
+                pm_error("Write to file failed. errno=%d (%s)",
+                         errno, strerror(errno));
+            else
+                totalBytesWritten += rc;
+        }
+    }
+    pm_close(sourceFileP);
+}
+
+
+
+static void
+jobHead(int          const outFd,
+        bool         const renderGray,
+        const char * const userJobSetupFileName) {
+/*----------------------------------------------------------------------------
+   Start a PJL job.
+
+   Switch printer to PCL-XL mode.  This is called "entering a printer
+   language" in PCL terms.  In particular, we enter the PCL-XL language,
+   as opposed to e.g. Postscript.
+-----------------------------------------------------------------------------*/
+    /* Reset */
+    XY_Puts(outFd,"\033%-12345X");  
+
+    if (userJobSetupFileName)
+        copyFile(userJobSetupFileName, outFd);
+
+    if (renderGray)
+        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");  
+}
+
+
+
+static void
+jobEnd(int const outFd) {
+/*----------------------------------------------------------------------------
+   End a PJL job.
+
+   Reset printer to quiescent mode.  Exit the printer language.
+-----------------------------------------------------------------------------*/
+    XY_Puts(outFd,"\033%-12345X");  
+}
+
+
+
+static void
+beginPage(int                 const outFd,
+          bool                const doDuplex,
+          enum DuplexPageMode const duplex,
+          bool                const doMediaSource,
+          int                 const mediaSource,
+          bool                const doMediaDestination,
+          int                 const mediaDestination,
+          enum MediaSize      const format) {
+/*----------------------------------------------------------------------------
+   Emit a BeginPage printer command.
+-----------------------------------------------------------------------------*/
+    if (doDuplex) {
+        xl_ubyte(outFd, duplex);  xl_attr_ubyte(outFd, aDuplexPageMode);
+    }
+
+    if (doMediaSource) {
+        /* if not included same as last time in same session is selected */
+        xl_ubyte(outFd, mediaSource);  xl_attr_ubyte(outFd, aMediaSource);
+    }
+
+    if (doMediaDestination) {
+        xl_ubyte(outFd, mediaDestination);  
+        xl_attr_ubyte(outFd, aMediaDestination);
+    }
+
+    xl_ubyte(outFd, ePortraitOrientation); xl_attr_ubyte(outFd, aOrientation);
+    xl_ubyte(outFd, format); xl_attr_ubyte(outFd, aMediaSize);
+
+    XL_Operator(outFd, oBeginPage);
+}
+
+
+
+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,
+              const unsigned char * const palette,
+              unsigned int          const paletteSize,
+              enum ColorDepth       const paletteDepth) {
+/*----------------------------------------------------------------------------
+   Emit printer control to set the color space.
+
+   'palette' == NULL means no palette (raster contains colors, not indexes
+   into a palette).
+
+   'paletteSize' is the number of bytes in the palette (undefined if
+   'palette' is NULL)
+
+   'paletteDepth' is the color depth of the entries in the palette.
+   e8Bit means the palette contains 8 bit values.
+
+   The palette is a "direct color" palette: A separate table for each
+   color component (i.e. one table for grayscale; three tables for
+   RGB).  Each table is indexed by a value from the raster and yields
+   a byte of color component value.
+
+   The palette has to be the right size to fit the number of color
+   components and raster color depth (bits per component in the raster).
+
+   E.g. with raster color depth of 1 bit (e1Bit) and RGB color (eRGB),
+   'paletteSize' would have to be 6 -- a table for each of R, G, and
+   B, of two elements each.
+
+   It is not clear from the documentation what the situation is when
+   paletteDepth is not e8Bit.  Is each palette entry still a byte and only
+   some of the byte gets used?  Or are there multiple entries per byte?
+-----------------------------------------------------------------------------*/
+    xl_ubyte(outFd, colorSpace); xl_attr_ubyte(outFd, aColorSpace);   
+    if (palette) {
+        xl_ubyte(outFd, paletteDepth); 
+        xl_attr_ubyte(outFd, aPaletteDepth);   
+        xl_ubyte_array(outFd, palette, paletteSize); 
+        xl_attr_ubyte(outFd, aPaletteData);
+    }
+    XL_Operator(outFd, oSetColorSpace);
+}
+
+
+
+static void
+positionCursor(int            const outFd,
+               bool           const center,
+               float          const xoffs,
+               float          const yoffs,
+               int            const imageWidth,
+               int            const imageHeight,
+               int            const dpi,
+               enum MediaSize const format) {
+/*----------------------------------------------------------------------------
+   Emit printer control to position the cursor to start the page.
+-----------------------------------------------------------------------------*/
+    float xpos, ypos;
+
+    if (center) {
+        float const width  = 1.0 * imageWidth/dpi;  
+        float const height = 1.0 * imageHeight/dpi;    
+        xpos = (PAPERWIDTH(format) - width)/2;
+        ypos = (PAPERHEIGHT(format) - height)/2;
+    } else {
+        xpos = xoffs;
+        ypos = yoffs;
+    }
+    /* cursor positioning */
+    xl_sint16_xy(outFd, xpos * dpi, ypos * dpi); xl_attr_ubyte(outFd, aPoint);
+    XL_Operator(outFd, oSetCursor);
+}
+
+
+
+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);
+
+    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,
+        unsigned int const copies) {
+/*----------------------------------------------------------------------------
+   Emit an EndPage printer command.
+-----------------------------------------------------------------------------*/
+    if (doCopies) {
+        /* wrong in example in PCL-XL manual. Type is uint16 ! */
+        xl_uint16(outFd, copies); xl_attr_ubyte(outFd, aPageCopies);
+    }
+    XL_Operator(outFd, oEndPage);
+}
+
+
+
+static void
+convertAndPrintPage(int                  const outFd,
+                    const pclGenerator * const pclGeneratorP,
+                    struct pam *         const pamP,
+                    enum MediaSize       const format,
+                    int                  const dpi,
+                    bool                 const center,
+                    float                const xoffs,
+                    float                const yoffs,
+                    bool                 const doDuplex,
+                    enum DuplexPageMode  const duplex,
+                    bool                 const doCopies,
+                    unsigned int         const copies,
+                    bool                 const doMediaSource,
+                    int                  const mediaSource,
+                    bool                 const doMediaDestination,
+                    int                  const mediaDestination) {
+
+    beginPage(outFd, doDuplex, duplex, doMediaSource, mediaSource,
+              doMediaDestination, mediaDestination, format);
+
+    /* Before Netpbm 10.27 (March 2005), we always set up a two-byte 8
+       bit deep palette: {0, 255}.  I don't know why, because this
+       works only for e1Bit color depth an eGray color space, and in
+       that case does the same thing as having no palette at all.  But
+       in other cases, it doesn't work.  E.g. with eRGB, e8Bit, we got
+       an IllegalArraySize error from the printer on the SetColorSpace
+       command.
+
+       So we don't use a palette at all now.  
+    */
+    setColorSpace(outFd, pclGeneratorP->colorSpace, NULL, 0, 0);
+
+    positionCursor(outFd, center, xoffs, yoffs, 
+                   pclGeneratorP->width, pclGeneratorP->height, dpi, format);
+
+    convertAndWriteImage(outFd, pclGeneratorP, pamP);
+
+    endPage(outFd, doCopies, copies);
+}
+
+
+
+static void
+beginSession(int              const outFd,
+             unsigned int     const xdpi,
+             unsigned int     const ydpi,
+             enum Measure     const measure,
+             bool             const noReporting,
+             enum ErrorReport const errorReport) {
+
+    xl_uint16_xy(outFd, xdpi, ydpi); xl_attr_ubyte(outFd, aUnitsPerMeasure); 
+    xl_ubyte(outFd, measure);  xl_attr_ubyte(outFd, aMeasure);
+    /* xl_ubyte(outFd,eNoReporting); xl_attr_ubyte(outFd,aErrorReport); */
+    xl_ubyte(outFd,errorReport); xl_attr_ubyte(outFd,aErrorReport);
+    XL_Operator(outFd,oBeginSession);
+}
+
+
+             
+static void 
+endSession(int outFd) {
+    XL_Operator(outFd,oEndSession);
+}
+
+
+
+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,
+           bool                const center,
+           float               const xoffs,
+           float               const yoffs,
+           bool                const doDuplex,
+           enum DuplexPageMode const duplex,
+           bool                const doCopies,
+           unsigned int        const copies,
+           bool                const doMediaSource,
+           int                 const mediaSource,
+           bool                const doMediaDestination,
+           int                 const mediaDestination,
+           bool                const colorok) {
+/*----------------------------------------------------------------------------
+  Loop over all input files, and each file, all images.
+-----------------------------------------------------------------------------*/
+    InputSource * sourceP;
+    unsigned int sourceNum;
+
+    sourceP = firstSourceP;    
+
+    openDataSource(outFd, eBinaryLowByteFirst, eDefaultSource);
+
+    sourceNum = 0;   /* initial value */
+
+    while (sourceP) {
+        FILE * in_file;
+        struct pam pam;
+        bool eof;
+        unsigned int pageNum;
+
+        in_file = pm_openr(sourceP->name);
+
+        ++sourceNum;
+
+        pageNum = 0;  /* initial value */
+
+        eof = FALSE;
+        while(!eof) {
+            pnm_nextimage(in_file, &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));
+                
+                createPclGenerator(&pam, &pclGeneratorP, colorok);
+                
+                convertAndPrintPage(
+                    outFd, pclGeneratorP, &pam,
+                    format, dpi, center, xoffs, yoffs, doDuplex, duplex,
+                    doCopies, copies, doMediaSource, mediaSource,
+                    doMediaDestination, mediaDestination);
+
+                destroyPclGenerator(pclGeneratorP);
+            }
+        }
+        pm_close(in_file);
+        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;
+    }
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+    int const outFd = STDOUT_FILENO;
+
+    struct cmdlineInfo cmdline;
+    
+    /* In case you're wondering why we do direct file descriptor I/O
+       instead of stream (FILE *), it's because Jochen originally 
+       wrote this code for an embedded system with diet-libc.  Without
+       the stream library, the statically linked binary was only about
+       5K big.
+    */
+    pnm_init(&argc, 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);
+
+    return 0;
+}
diff --git a/converter/other/pnmtoplainpnm b/converter/other/pnmtoplainpnm
new file mode 100755
index 00000000..87c58597
--- /dev/null
+++ b/converter/other/pnmtoplainpnm
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+pnmtopnm -plain $@
diff --git a/converter/other/pnmtopng.README b/converter/other/pnmtopng.README
new file mode 100644
index 00000000..bfa524dc
--- /dev/null
+++ b/converter/other/pnmtopng.README
@@ -0,0 +1,101 @@
+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 "<var> 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 <lehmann@usa.net>
+Willem van Schaik <willem@schaik.com>
+Greg Roelofs <newt@pobox.com>
diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c
new file mode 100644
index 00000000..9287d0ee
--- /dev/null
+++ b/converter/other/pnmtopng.c
@@ -0,0 +1,2745 @@
+/*
+** pnmtopng.c -
+** read a portable anymap 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 <wijkstra@fwi.uva.nl>
+**
+** Copyright (C) 1995-1998 by Alexander Lehmann <alex@hal.rhein-main.de>
+**                        and Willem van Schaik <willem@schaik.com>
+** Copyright (C) 1999,2001 by Greg Roelofs <newt@pobox.com>
+**
+** 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 version of Pnmtopng was derived from the independently
+   distributed program of the same name, Version 2.37.6 (21 July 2001).
+*/
+
+/* A performance note: This program reads one row at a time because
+   the whole image won't fit in memory always.  When you realize that
+   in a Netpbm xel array a one bit pixel can take 96 bits of memory,
+   it's easy to see that an ordinary fax could deplete your virtual
+   memory and even if it didn't, it might deplete your real memory and
+   iterating through the array would cause thrashing.  This program
+   iterates through the image multiple times.  
+
+   So instead, we read the image into memory one row at a time, into a
+   single row buffer.  We use Netpbm's pm_openr_seekable() facility to
+   access the file.  That facility copies the file into a temporary
+   file if it isn't seekable, so we always end up with a file that we
+   can rewind and reread multiple times.
+
+   This shouldn't cause I/O delays because the entire image ought to fit
+   in the system's I/O cache (remember that the file is a lot smaller than
+   the xel array you'd get by doing a pnm_readpnm() of it).
+
+   However, it does introduce some delay because of all the system calls 
+   required to read the file.  A future enhancement might read the entire
+   file into an xel array in some cases, and read one row at a time in 
+   others, depending on the needs of the particular use.
+
+   We do still read the entire alpha mask (if there is one) into a
+   'gray' array, rather than access it one row at a time.  
+
+   Before May 2001, we did in fact read the whole image into an xel array,
+   and we got complaints.  Before April 2000, it wasn't as big a problem
+   because xels were only 24 bits.  Now they're 96.
+*/
+   
+#define GRR_GRAY_PALETTE_FIX
+
+#ifndef PNMTOPNG_WARNING_LEVEL
+#  define PNMTOPNG_WARNING_LEVEL 0   /* use 0 for backward compatibility, */
+#endif                               /*  2 for warnings (1 == error) */
+
+#include <assert.h>
+#include <string.h> /* strcat() */
+#include <limits.h>
+#include <png.h>    /* includes zlib.h and setjmp.h */
+#include "pnm.h"
+#include "pngtxt.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "version.h"
+
+struct zlibCompression {
+    /* These are parameters that describe a form of zlib compression.
+       Values have the same meaning as the similarly named arguments to
+       zlib's deflateInit2().  See zlib.h.
+    */
+    unsigned int levelSpec;
+    unsigned int level;
+    unsigned int memLevelSpec;
+    unsigned int mem_level;
+    unsigned int strategySpec;
+    unsigned int strategy;
+    unsigned int windowBitsSpec;
+    unsigned int window_bits;
+    unsigned int methodSpec;
+    unsigned int method;
+    unsigned int bufferSizeSpec;
+    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;
+    int value;
+    struct cahitem * next;
+} cahitem;
+
+typedef cahitem ** coloralphahash_table;
+
+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 *  alpha;
+    unsigned int  verbose;
+    unsigned int  downscale;
+    unsigned int  interlace;
+    const char *  transparent;  /* NULL if none */
+    const char *  background;   /* NULL if none */
+    unsigned int  gammaSpec;
+    float         gamma;        /* Meaningless if !gammaSpec */
+    unsigned int  hist;
+    unsigned int  rgbSpec;
+    struct chroma rgb;          /* Meaningless if !rgbSpec */
+    unsigned int  sizeSpec;
+    struct phys   size;         /* Meaningless if !sizeSpec */
+    const char *  text;         /* NULL if none */
+    const char *  ztxt;         /* NULL if none */
+    unsigned int  modtimeSpec;
+    time_t        modtime;      /* Meaningless if !modtimeSpec */
+    const char *  palette;      /* NULL if none */
+    int           filterSet;
+    unsigned int  force;
+    unsigned int  libversion;
+    unsigned int  compressionSpec;
+    struct zlibCompression zlibCompression;
+};
+
+
+
+typedef struct _jmpbuf_wrapper {
+  jmp_buf jmpbuf;
+} jmpbuf_wrapper;
+
+#ifndef TRUE
+#  define TRUE 1
+#endif
+#ifndef FALSE
+#  define FALSE 0
+#endif
+#ifndef NONE
+#  define NONE 0
+#endif
+#define MAXCOLORS 256
+#define MAXPALETTEENTRIES 256
+
+/* PALETTEMAXVAL is the maxval used in a PNG palette */
+#define PALETTEMAXVAL 255
+
+#define PALETTEOPAQUE 255
+#define PALETTETRANSPARENT 0
+
+static bool verbose;
+
+static jmpbuf_wrapper pnmtopng_jmpbuf_struct;
+static int errorlevel;
+
+
+
+static void
+parseSizeOpt(const char *  const sizeOpt,
+             struct phys * const sizeP) {
+
+    int count;
+    
+    count = sscanf(sizeOpt, "%d %d %d", &sizeP->x, &sizeP->y, &sizeP->unit);
+
+    if (count != 3)
+        pm_error("Invalid syntax for the -size option value '%s'.  "
+                 "Should be 3 integers: x, y, and unit code", sizeOpt);
+}
+
+
+
+static void
+parseRgbOpt(const char *    const rgbOpt,
+            struct chroma * const rgbP) {
+
+    int count;
+    
+    count = sscanf(rgbOpt, "%f %f %f %f %f %f %f %f",
+                   &rgbP->wx, &rgbP->wy,
+                   &rgbP->rx, &rgbP->ry,
+                   &rgbP->gx, &rgbP->gy,
+                   &rgbP->bx, &rgbP->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",
+                 rgbOpt);
+}
+
+
+
+static void
+parseModtimeOpt(const char * const modtimeOpt,
+                time_t *     const modtimeP) {
+
+    struct tm brokenTime;
+    int year;
+    int month;
+    int count;
+
+    count = sscanf(modtimeOpt, "%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 -modtime '%s'.   It should have "
+                 "the form [yy]yy-mm-dd hh:mm:ss.", modtimeOpt);
+    
+    if (year < 0)
+        pm_error("Year is negative in -modtime value '%s'", modtimeOpt);
+    if (year > 9999)
+        pm_error("Year is more than 4 digits in -modtime value '%s'",
+                 modtimeOpt);
+    if (month < 0)
+        pm_error("Month is negative in -modtime value '%s'", modtimeOpt);
+    if (month > 12)
+        pm_error("Month is >12 in -modtime value '%s'", modtimeOpt);
+    if (brokenTime.tm_mday < 0)
+        pm_error("Day of month is negative in -modtime value '%s'",
+                 modtimeOpt);
+    if (brokenTime.tm_mday > 31)
+        pm_error("Day of month is >31 in -modtime value '%s'", modtimeOpt);
+    if (brokenTime.tm_hour < 0)
+        pm_error("Hour is negative in -modtime value '%s'", modtimeOpt);
+    if (brokenTime.tm_hour > 23)
+        pm_error("Hour is >23 in -modtime value '%s'", modtimeOpt);
+    if (brokenTime.tm_min < 0)
+        pm_error("Minute is negative in -modtime value '%s'", modtimeOpt);
+    if (brokenTime.tm_min > 59)
+        pm_error("Minute is >59 in -modtime value '%s'", modtimeOpt);
+    if (brokenTime.tm_sec < 0)
+        pm_error("Second is negative in -modtime value '%s'", modtimeOpt);
+    if (brokenTime.tm_sec > 59)
+        pm_error("Second is >59 in -modtime value '%s'", modtimeOpt);
+
+    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.
+    */
+    *modtimeP = mktime(&brokenTime);
+}
+
+
+
+static void
+parseCommandLine(int argc, 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 optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    unsigned int alphaSpec, transparentSpec, backgroundSpec;
+    unsigned int textSpec, ztxtSpec, paletteSpec;
+    unsigned int filterSpec;
+
+    unsigned int nofilter, sub, up, avg, paeth, filter;
+    unsigned int chroma, phys, time;
+    const char * size;
+    const char * rgb;
+    const char * modtime;
+    const char * compMethod;
+    const char * compStrategy;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "alpha",            OPT_STRING,    &cmdlineP->alpha,
+            &alphaSpec,            0);
+    OPTENT3(0, "transparent",      OPT_STRING,    &cmdlineP->transparent,
+            &transparentSpec,      0);
+    OPTENT3(0, "background",       OPT_STRING,    &cmdlineP->background,
+            &backgroundSpec,       0);
+    OPTENT3(0, "rgb",              OPT_STRING,    &rgb,
+            &cmdlineP->rgbSpec,    0);
+    OPTENT3(0, "size",             OPT_STRING,    &size,
+            &cmdlineP->sizeSpec,   0);
+    OPTENT3(0, "text",             OPT_STRING,    &cmdlineP->text,
+            &textSpec,             0);
+    OPTENT3(0, "ztxt",             OPT_STRING,    &cmdlineP->ztxt,
+            &ztxtSpec,             0);
+    OPTENT3(0, "modtime",          OPT_STRING,    &modtime,
+            &cmdlineP->modtimeSpec,0);
+    OPTENT3(0, "palette",          OPT_STRING,    &cmdlineP->palette,
+            &paletteSpec,          0);
+    OPTENT3(0, "compression",      OPT_UINT,
+            &cmdlineP->zlibCompression.level,
+            &cmdlineP->zlibCompression.levelSpec,            0);
+    OPTENT3(0, "comp_mem_level",   OPT_UINT,
+            &cmdlineP->zlibCompression.mem_level,
+            &cmdlineP->zlibCompression.memLevelSpec,         0);
+    OPTENT3(0, "comp_strategy",    OPT_STRING,    &compStrategy,
+            &cmdlineP->zlibCompression.strategySpec,         0);
+    OPTENT3(0, "comp_window_bits", OPT_UINT,
+            &cmdlineP->zlibCompression.window_bits,
+            &cmdlineP->zlibCompression.windowBitsSpec,       0);
+    OPTENT3(0, "comp_method",      OPT_STRING,    &compMethod,
+            &cmdlineP->zlibCompression.methodSpec,           0);
+    OPTENT3(0, "comp_buffer_size", OPT_UINT,
+            &cmdlineP->zlibCompression.buffer_size,
+            &cmdlineP->zlibCompression.bufferSizeSpec,       0);
+    OPTENT3(0, "gamma",            OPT_FLOAT,     &cmdlineP->gamma,
+            &cmdlineP->gammaSpec,  0);
+    OPTENT3(0, "hist",             OPT_FLAG,      NULL,
+            &cmdlineP->hist,       0);
+    OPTENT3(0, "downscale",        OPT_FLAG,      NULL,
+            &cmdlineP->downscale,  0);
+    OPTENT3(0, "interlace",        OPT_FLAG,      NULL,
+            &cmdlineP->interlace,  0);
+    OPTENT3(0, "force",            OPT_FLAG,      NULL,
+            &cmdlineP->force,      0);
+    OPTENT3(0, "libversion",       OPT_FLAG,      NULL,
+            &cmdlineP->libversion, 0);
+    OPTENT3(0, "verbose",          OPT_FLAG,      NULL,
+            &cmdlineP->verbose,    0);
+    OPTENT3(0, "nofilter",         OPT_FLAG,      NULL,
+            &nofilter,             0);
+    OPTENT3(0, "sub",              OPT_FLAG,      NULL,
+            &sub,                  0);
+    OPTENT3(0, "up",               OPT_FLAG,      NULL,
+            &up,                   0);
+    OPTENT3(0, "avg",              OPT_FLAG,      NULL,
+            &avg,                  0);
+    OPTENT3(0, "paeth",            OPT_FLAG,      NULL,
+            &paeth,                0);
+    OPTENT3(0, "filter",           OPT_INT,       &filter,
+            &filterSpec,           0);
+    OPTENT3(0, "verbose",          OPT_FLAG,      NULL,
+            &cmdlineP->verbose,    0);
+    OPTENT3(0, "chroma",           OPT_FLAG,      NULL,
+            &chroma,               0);
+    OPTENT3(0, "phys",             OPT_FLAG,      NULL,
+            &phys,                 0);
+    OPTENT3(0, "time",             OPT_FLAG,      NULL,
+            &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, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+
+    if (chroma)
+        pm_error("The -chroma option no longer exists.  Use -rgb instead.");
+    if (phys)
+        pm_error("The -phys option no longer exists.  Use -size instead.");
+    if (time)
+        pm_error("The -time option no longer exists.  Use -modtime instead.");
+
+    if (alphaSpec + transparentSpec > 1)
+        pm_error("You may not specify both -alpha and -transparent");
+    if (!alphaSpec)
+        cmdlineP->alpha = NULL;
+    if (!transparentSpec)
+        cmdlineP->transparent = NULL;
+    if (!backgroundSpec)
+        cmdlineP->background = NULL;
+    if (!textSpec)
+        cmdlineP->text = NULL;
+    if (!ztxtSpec)
+        cmdlineP->ztxt = NULL;
+    if (!paletteSpec)
+        cmdlineP->palette = NULL;
+    
+    if (filterSpec + nofilter + sub + up + avg + paeth > 1)
+        pm_error("You may specify at most one of "
+                 "-nofilter, -sub, -up, -avg, -paeth, and -filter");
+    
+    if (filterSpec) {
+        if (filter < 0 || filter > 4)
+            pm_error("-filter is obsolete.  Use -nofilter, -sub, -up, -avg, "
+                     "and -paeth options instead.");
+        else
+            switch (filter) {
+            case 0: cmdlineP->filterSet = PNG_FILTER_NONE;  break;
+            case 1: cmdlineP->filterSet = PNG_FILTER_SUB;   break;
+            case 2: cmdlineP->filterSet = PNG_FILTER_UP;    break;
+            case 3: cmdlineP->filterSet = PNG_FILTER_AVG;   break;
+            case 4: cmdlineP->filterSet = PNG_FILTER_PAETH; break;
+            }
+    } else {
+        if (nofilter)
+            cmdlineP->filterSet = PNG_FILTER_NONE;
+        else if (sub)
+            cmdlineP->filterSet = PNG_FILTER_SUB;
+        else if (up)
+            cmdlineP->filterSet = PNG_FILTER_UP;
+        else if (avg)
+            cmdlineP->filterSet = PNG_FILTER_AVG;
+        else if (paeth)
+            cmdlineP->filterSet = PNG_FILTER_PAETH;
+        else
+            cmdlineP->filterSet = PNG_FILTER_NONE;
+    }
+    
+    if (cmdlineP->sizeSpec)
+        parseSizeOpt(size, &cmdlineP->size);
+
+    if (cmdlineP->rgbSpec)
+        parseRgbOpt(rgb, &cmdlineP->rgb);
+    
+    if (cmdlineP->modtimeSpec)
+        parseModtimeOpt(modtime, &cmdlineP->modtime);
+
+    if (cmdlineP->zlibCompression.levelSpec &&
+        cmdlineP->zlibCompression.level > 9)
+        pm_error("-compression value must be from 0 (no compression) "
+                 "to 9 (maximum compression).  You specified %u",
+                 cmdlineP->zlibCompression.level);
+
+    if (cmdlineP->zlibCompression.memLevelSpec) {
+        if (cmdlineP->zlibCompression.mem_level  < 1 ||
+            cmdlineP->zlibCompression.mem_level > 9)
+        pm_error("-comp_mem_level value must be from 1 (minimum memory usage) "
+                 "to 9 (maximum memory usage).  You specified %u",
+                 cmdlineP->zlibCompression.mem_level);
+    }
+
+    if (cmdlineP->zlibCompression.methodSpec) {
+        if (STREQ(compMethod, "deflated"))
+            cmdlineP->zlibCompression.method = Z_DEFLATED;
+        else
+            pm_error("The only valid value for -method is 'deflated'.  "
+                     "You specified '%s'", compMethod);
+    }
+
+    if (cmdlineP->zlibCompression.strategySpec) {
+        if (STREQ(compStrategy, "huffman_only"))
+            cmdlineP->zlibCompression.strategy = Z_HUFFMAN_ONLY;
+        else if (STREQ(compStrategy, "filtered"))
+            cmdlineP->zlibCompression.strategy = Z_FILTERED;
+        else
+            pm_error("Valid values for -strategy are 'huffman_only' and "
+                     "filtered.  You specified '%s'", compStrategy);
+    }
+
+
+    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 png_color_16
+xelToPngColor_16(xel const input, 
+                 xelval const maxval, 
+                 xelval const pngMaxval) {
+    png_color_16 retval;
+
+    xel scaled;
+    
+    PPM_DEPTH(scaled, input, maxval, pngMaxval);
+
+    retval.red   = PPM_GETR(scaled);
+    retval.green = PPM_GETG(scaled);
+    retval.blue  = PPM_GETB(scaled);
+    retval.gray  = PNM_GET1(scaled);
+
+    return retval;
+}
+
+
+
+static void
+closestColorInPalette(pixel          const targetColor, 
+                      pixel                palette_pnm[],
+                      unsigned int   const paletteSize,
+                      unsigned int * const bestIndexP,
+                      unsigned int * const bestMatchP) {
+    
+    unsigned int paletteIndex;
+    unsigned int bestIndex;
+    unsigned int bestMatch;
+
+    assert(paletteSize > 0);
+
+    bestMatch = UINT_MAX;
+    for (paletteIndex = 0; paletteIndex < paletteSize; ++paletteIndex) {
+        unsigned int const dist = 
+            PPM_DISTANCE(palette_pnm[paletteIndex], targetColor);
+
+        if (dist < bestMatch) {
+            bestMatch = dist;
+            bestIndex = paletteIndex;
+        }
+    }
+    if (bestIndexP != NULL)
+        *bestIndexP = bestIndex;
+    if (bestMatchP != NULL)
+        *bestMatchP = bestMatch;
+}
+
+
+
+/* We really ought to make this hash function actually depend upon
+   the "a" argument; we just don't know a decent prime number off-hand.
+*/
+#define HASH_SIZE 20023
+#define hashpixelalpha(p,a) ((((long) PPM_GETR(p) * 33023 + \
+                               (long) PPM_GETG(p) * 30013 + \
+                               (long) PPM_GETB(p) * 27011 ) \
+                              & 0x7fffffff ) % HASH_SIZE )
+
+static coloralphahash_table
+alloccoloralphahash(void)  {
+    coloralphahash_table caht;
+    int i;
+
+    MALLOCARRAY(caht,HASH_SIZE);
+    if (caht == NULL)
+        pm_error( "out of memory allocating hash table" );
+
+    for (i = 0; i < HASH_SIZE; ++i)
+        caht[i] = NULL;
+
+    return caht;
+}
+
+
+static void
+freecoloralphahash(coloralphahash_table const caht) {
+    int i;
+
+    for (i = 0; i < HASH_SIZE; ++i) {
+        cahitem * p;
+        cahitem * next;
+        for (p = caht[i]; p; p = next) {
+            next = p->next;
+            free(p);
+        }
+    }
+    free(caht);
+}
+
+
+
+static void
+addtocoloralphahash(coloralphahash_table const caht,
+                    pixel *              const colorP,
+                    gray *               const alphaP,
+                    int                  const value) {
+
+    int hash;
+    cahitem * itemP;
+
+    MALLOCVAR(itemP);
+    if (itemP == NULL)
+        pm_error("Out of memory building hash table");
+    hash = hashpixelalpha(*colorP, *alphaP);
+    itemP->color = *colorP;
+    itemP->alpha = *alphaP;
+    itemP->value = value;
+    itemP->next = caht[hash];
+    caht[hash] = itemP;
+}
+
+
+
+static int
+lookupColorAlpha(coloralphahash_table const caht,
+                 const pixel *        const colorP,
+                 const gray *         const alphaP) {
+
+    int hash;
+    cahitem * p;
+
+    hash = hashpixelalpha(*colorP, *alphaP);
+    for (p = caht[hash]; p; p = p->next)
+        if (PPM_EQUAL(p->color, *colorP) && p->alpha == *alphaP)
+            return p->value;
+
+    return -1;
+}
+
+
+
+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;
+
+
+
+static void
+getChv(FILE *             const ifP, 
+       pm_filepos         const rasterPos,
+       int                const cols, 
+       int                const rows, 
+       xelval             const maxval,
+       int                const format, 
+       int                const maxColors, 
+       colorhist_vector * const chvP,
+       unsigned int *     const colorsP) {
+/*----------------------------------------------------------------------------
+   Return a list of all the colors in a libnetpbm image and the number of
+   times they occur.  The image is in the seekable file 'ifP', whose
+   raster starts at position 'rasterPos' of the file.  The image's properties
+   are 'cols', 'rows', 'maxval', and 'format'.
+
+   Return the number of colors as *colorsP.  Return the details of the 
+   colors in newly malloc'ed storage, and its address as *chvP.  If
+   there are more than 'maxColors' colors, though, just return NULL as
+   *chvP and leave *colorsP undefined.
+
+   Don't spend the time to read the file if this subroutine has been called
+   before.  In that case, just assume the inputs are all the same and return
+   the previously computed information.  Ick.
+
+   *chvP is in static program storage.
+-----------------------------------------------------------------------------*/
+    static unsigned int getChv_colors;
+
+    if (!getChv_computed) {
+        int colorCount;
+        if (verbose) 
+            pm_message ("Finding colors in input image...");
+
+        pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
+        getChv_chv = ppm_computecolorhist2(ifP, cols, rows, maxval, format, 
+                                           maxColors, &colorCount);
+        
+        getChv_colors = colorCount;
+
+        if (verbose) {
+            if (getChv_chv)
+                pm_message("%u colors found", getChv_colors);
+            else
+                pm_message("Too many colors (more than %u) found", maxColors);
+        }
+        getChv_computed = TRUE;
+    }
+    *chvP = getChv_chv;
+    *colorsP = getChv_colors;
+}
+
+
+
+static void freeChv(void) {
+
+    if (getChv_computed)
+        if (getChv_chv)
+            ppm_freecolorhist(getChv_chv);
+
+    getChv_computed = FALSE;
+}
+
+
+
+static bool
+pgmBitsAreRepeated(unsigned int const repeatedSize,
+                   FILE *       const ifP,
+                   pm_filepos   const rasterPos, 
+                   int          const cols,
+                   int          const rows,
+                   xelval       const maxval,
+                   int          const format) {
+/*----------------------------------------------------------------------------
+   Return TRUE iff all the samples in the image in file 'ifP',
+   described by 'cols', 'rows', 'maxval', and 'format', consist in the
+   rightmost 'repeatedSize' * 2 bits of two identical sets of
+   'repeatedSize' bits.
+
+   The file has arbitrary position, but the raster is at file position
+   'rasterPos'.
+
+   E.g. for repeatedSize = 2, a sample value of 0xaa would qualify.
+   So would 0x0a.
+
+   Leave the file positioned where we found it.
+-----------------------------------------------------------------------------*/
+    unsigned int const mask2 = (1 << repeatedSize*2) - 1;
+    unsigned int const mask1 = (1 << repeatedSize) - 1;
+
+    bool mayscale;
+    unsigned int row;
+    xel * xelrow;
+
+    xelrow = pnm_allocrow(cols);
+    
+    pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
+
+    mayscale = TRUE;  /* initial assumption */
+
+    for (row = 0; row < rows && mayscale; ++row) {
+        unsigned int col;
+        pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
+        for (col = 0; col < cols && mayscale; ++col) {
+            xelval const testbits2 = PNM_GET1(xelrow[col]) & mask2;
+                /* The bits of interest in the sample */
+            xelval const testbits1 = testbits2 & mask1;
+                /* The lower half of the bits of interest in the sample */
+            if (((testbits1 << repeatedSize) | testbits1) != testbits2)
+                mayscale = FALSE;
+        }
+    }
+    pnm_freerow(xelrow);
+
+    return mayscale;
+}
+
+
+
+static void
+meaningful_bits_pgm(FILE *         const ifP, 
+                    pm_filepos     const rasterPos, 
+                    int            const cols,
+                    int            const rows,
+                    xelval         const maxval,
+                    int            const format,
+                    unsigned int * const retvalP) {
+/*----------------------------------------------------------------------------
+   In the PGM raster with maxval 'maxval' at file offset 'rasterPos'
+   in file 'ifp', the samples may be composed of groups of 1, 2, 4, or 8
+   bits repeated.  This would be the case if the image were converted
+   at some point from a 2 bits-per-pixel image to an 8-bits-per-pixel
+   image, for example.
+
+   If this is the case, we find out and find out how small these repeated
+   groups of bits are and return the number of bits.
+-----------------------------------------------------------------------------*/
+    unsigned int maxMeaningfulBits;
+        /* progressive estimate of the maximum number of meaningful
+           (nonrepeated) bits in the samples.
+        */
+
+    maxMeaningfulBits = pm_maxvaltobits(maxval);  /* initial value */
+
+    if (maxval == 0xffff || maxval == 0xff || maxval == 0xf || maxval == 0x3) {
+        if (maxMeaningfulBits == 16) {
+            if (pgmBitsAreRepeated(8,
+                                   ifP, rasterPos, cols, rows, maxval, format))
+                maxMeaningfulBits = 8;
+        }
+        if (maxMeaningfulBits == 8) {
+            if (pgmBitsAreRepeated(4,
+                                   ifP, rasterPos, cols, rows, maxval, format))
+                maxMeaningfulBits = 4;
+        }
+        if (maxMeaningfulBits == 4) {
+            if (pgmBitsAreRepeated(2,
+                                   ifP, rasterPos, cols, rows, maxval, format))
+                maxMeaningfulBits = 2;
+        }
+        if (maxMeaningfulBits == 2) {
+            if (pgmBitsAreRepeated(1,
+                                   ifP, rasterPos, cols, rows, maxval, format))
+                maxMeaningfulBits = 1;
+        }
+    }
+    *retvalP = maxMeaningfulBits;
+}
+
+
+
+static void
+meaningful_bits_ppm(FILE *         const ifp, 
+                    pm_filepos     const rasterPos, 
+                    int            const cols,
+                    int            const rows,
+                    xelval         const maxval,
+                    int            const format,
+                    unsigned int * const retvalP) {
+/*----------------------------------------------------------------------------
+   In the PPM raster with maxval 'maxval' at file offset 'rasterPos'
+   in file 'ifp', the samples may be composed of groups of 8
+   bits repeated twice.  This would be the case if the image were converted
+   at some point from a 8 bits-per-pixel image to an 16-bits-per-pixel
+   image, for example.
+
+   We return the smallest number of bits we can take from the right of
+   a sample without losing information (8 or all).
+-----------------------------------------------------------------------------*/
+    int mayscale;
+    unsigned int row;
+    xel * xelrow;
+    unsigned int maxMeaningfulBits;
+        /* progressive estimate of the maximum number of meaningful
+           (nonrepeated) bits in the samples.
+        */
+
+    xelrow = pnm_allocrow(cols);
+
+    maxMeaningfulBits = pm_maxvaltobits(maxval);
+
+    if (maxval == 65535) {
+        mayscale = TRUE;   /* initial assumption */
+        pm_seek2(ifp, &rasterPos, sizeof(rasterPos));
+        for (row = 0; row < rows && mayscale; ++row) {
+            unsigned int col;
+            pnm_readpnmrow(ifp, xelrow, cols, maxval, format);
+            for (col = 0; col < cols && mayscale; ++col) {
+                xel const p = xelrow[col];
+                if ((PPM_GETR(p) & 0xff) * 0x101 != PPM_GETR(p) ||
+                    (PPM_GETG(p) & 0xff) * 0x101 != PPM_GETG(p) ||
+                    (PPM_GETB(p) & 0xff) * 0x101 != PPM_GETB(p))
+                    mayscale = FALSE;
+            }
+        }
+        if (mayscale)
+            maxMeaningfulBits = 8;
+    }
+    pnm_freerow(xelrow);
+
+    *retvalP = maxMeaningfulBits;
+}
+
+
+
+static void
+tryTransparentColor(FILE *     const ifp, 
+                    pm_filepos const rasterPos, 
+                    int        const cols, 
+                    int        const rows, 
+                    xelval     const maxval,
+                    int        const format, 
+                    gray **    const alphaMask,
+                    gray       const alphaMaxval,
+                    pixel      const transcolor,
+                    bool *     const singleColorIsTransP) {
+
+    int const pnm_type = PNM_FORMAT_TYPE(format);
+
+    xel * xelrow;
+    bool singleColorIsTrans;
+        /* So far, it looks like a single color is uniquely transparent */
+    int row;
+
+    xelrow = pnm_allocrow(cols);
+
+    pm_seek2(ifp, &rasterPos, sizeof(rasterPos));
+
+    singleColorIsTrans = TRUE;  /* initial assumption */
+        
+    for (row = 0; row < rows && singleColorIsTrans; ++row) {
+        int col;
+        pnm_readpnmrow(ifp, xelrow, cols, maxval, format);
+        for (col = 0 ; col < cols && singleColorIsTrans; ++col) {
+            if (alphaMask[row][col] == 0) { /* transparent */
+                /* If we have a second transparent color, we're
+                   disqualified
+                */
+                if (pnm_type == PPM_TYPE) {
+                    if (!PPM_EQUAL(xelrow[col], transcolor))
+                        singleColorIsTrans = FALSE;
+                } else {
+                    if (PNM_GET1(xelrow[col]) != PNM_GET1(transcolor))
+                        singleColorIsTrans = FALSE;
+                }
+            } else if (alphaMask[row][col] != alphaMaxval) {
+                /* Here's an area of the mask that is translucent.  That
+                   disqualified us.
+                */
+                singleColorIsTrans = FALSE;
+            } else {
+                /* Here's an area of the mask that is opaque.  If it's
+                   the same color as our candidate transparent color,
+                   that disqualifies us.
+                */
+                if (pnm_type == PPM_TYPE) {
+                    if (PPM_EQUAL(xelrow[col], transcolor))
+                        singleColorIsTrans = FALSE;
+                } else {
+                    if (PNM_GET1(xelrow[col]) == PNM_GET1(transcolor))
+                        singleColorIsTrans = FALSE;
+                }
+            }
+        }
+    }  
+    pnm_freerow(xelrow);
+}
+
+
+
+static void
+analyzeAlpha(FILE *     const ifp, 
+             pm_filepos const rasterPos, 
+             int        const cols, 
+             int        const rows, 
+             xelval     const maxval,
+             int        const format, 
+             gray **    const alphaMask,
+             gray       const alphaMaxval,
+             bool *     const allOpaqueP,
+             bool *     const singleColorIsTransP, 
+             pixel*     const alphaTranscolorP) {
+/*----------------------------------------------------------------------------
+  Get information about the alpha mask, in combination with the masked
+  image, that Caller can use to choose the most efficient way to
+  represent the information in the alpha mask in a PNG.  Simply
+  putting the alpha mask in the PNG is a last resort.  But if the mask
+  says all opaque, we can simply omit any mention of transparency
+  instead -- default is opaque.  And if the mask makes all the pixels
+  of a certain color fully transparent and every other pixel opaque,
+  we can simply identify that color in the PNG.
+
+  We have to do this before any scaling occurs, since alpha is only
+  possible with 8 and 16-bit.
+-----------------------------------------------------------------------------*/
+    xel * xelrow;
+    bool foundTransparentPixel;
+        /* We found a pixel in the image where the alpha mask says it is
+           transparent.
+        */
+    pixel transcolor;
+        /* Color of the transparent pixel mentioned above. */
+    
+    xelrow = pnm_allocrow(cols);
+
+    {
+        int row;
+        /* Find a candidate transparent color -- the color of any pixel in the
+           image that the alpha mask says should be transparent.
+        */
+        foundTransparentPixel = FALSE;  /* initial assumption */
+        pm_seek2(ifp, &rasterPos, sizeof(rasterPos));
+        for (row = 0 ; row < rows && !foundTransparentPixel ; ++row) {
+            int col;
+            pnm_readpnmrow(ifp, xelrow, cols, maxval, format);
+            for (col = 0; col < cols && !foundTransparentPixel; ++col) {
+                if (alphaMask[row][col] == 0) {
+                    foundTransparentPixel = TRUE;
+                    transcolor = xeltopixel(xelrow[col]);
+                }
+            }
+        }
+    }
+
+    pnm_freerow(xelrow);
+
+    if (foundTransparentPixel) {
+        *allOpaqueP = FALSE;
+        tryTransparentColor(ifp, rasterPos, cols, rows, maxval, format,
+                            alphaMask, alphaMaxval, transcolor,
+                            singleColorIsTransP);
+        *alphaTranscolorP = transcolor;
+    } else {
+        *allOpaqueP   = TRUE;
+        *singleColorIsTransP = FALSE;
+    }
+}
+
+
+
+static void
+findRedundantBits(FILE *         const ifp, 
+                  int            const rasterPos, 
+                  int            const cols,
+                  int            const rows,
+                  xelval         const maxval,
+                  int            const format,
+                  bool           const alpha,
+                  bool           const force,
+                  unsigned int * const meaningfulBitsP) {
+/*----------------------------------------------------------------------------
+   Find out if we can use just a subset of the bits from each input
+   sample.  Often, people create an image with e.g. 8 bit samples from
+   one that has e.g. only 4 bit samples by scaling by 256/16, which is
+   the same as repeating the bits.  E.g.  1011 becomes 10111011.  We
+   detect this case.  We return as *meaningfulBitsP the minimum number
+   of bits, starting from the least significant end, that contain
+   original information.
+-----------------------------------------------------------------------------*/
+  if (!alpha && PNM_FORMAT_TYPE(format) == PGM_TYPE && !force) 
+      meaningful_bits_pgm(ifp, rasterPos, cols, rows, maxval, format,
+                          meaningfulBitsP);
+  else if (PNM_FORMAT_TYPE(format) == PPM_TYPE && !force)
+      meaningful_bits_ppm(ifp, rasterPos, cols, rows, maxval, format,
+                          meaningfulBitsP);
+  else 
+      *meaningfulBitsP = pm_maxvaltobits(maxval);
+
+  if (verbose && *meaningfulBitsP != pm_maxvaltobits(maxval))
+      pm_message("Using only %d rightmost bits of input samples.  The "
+                 "rest are redundant.", *meaningfulBitsP);
+}
+
+
+
+static void
+readOrderedPalette(FILE *         const pfp,
+                   xel                  ordered_palette[], 
+                   unsigned int * const ordered_palette_size_p) {
+
+    xel ** xels;
+    int cols, rows;
+    xelval maxval;
+    int format;
+    
+    if (verbose)
+        pm_message("reading ordered palette (colormap)...");
+
+    xels = pnm_readpnm(pfp, &cols, &rows, &maxval, &format);
+    
+    if (PNM_FORMAT_TYPE(format) != PPM_TYPE) 
+        pm_error("ordered palette must be a PPM file, not type %d", format);
+
+    *ordered_palette_size_p = rows * cols;
+    if (*ordered_palette_size_p > MAXCOLORS) 
+        pm_error("ordered-palette image contains %d pixels.  Maximum is %d",
+                 *ordered_palette_size_p, MAXCOLORS);
+    if (verbose)
+        pm_message("%u colors found", *ordered_palette_size_p);
+
+    {
+        unsigned int j;
+        unsigned int row;
+        j = 0;  /* initial value */
+        for (row = 0; row < rows; ++row) {
+            int col;
+            for (col = 0; col < cols; ++col) 
+                ordered_palette[j++] = xels[row][col];
+        }
+    }
+    pnm_freearray(xels, rows);
+}        
+
+
+
+static void
+compute_nonalpha_palette(colorhist_vector const chv,
+                         int              const colors,
+                         pixval           const maxval,
+                         FILE *           const pfp,
+                         pixel                  palette_pnm[],
+                         unsigned int *   const paletteSizeP,
+                         gray                   trans_pnm[],
+                         unsigned int *   const transSizeP) {
+/*----------------------------------------------------------------------------
+   Compute the palette corresponding to the color set 'chv'
+   (consisting of 'colors' distinct colors) assuming a pure-color (no
+   transparency) palette.
+
+   If 'pfp' is non-null, assume it's a PPM file and read the palette
+   from that.  Make sure it contains the same colors as the palette
+   we computed ourself would have.  Caller supplied the file because he
+   wants the colors in a particular order in the palette.
+-----------------------------------------------------------------------------*/
+    unsigned int colorIndex;
+    
+    xel ordered_palette[MAXCOLORS];
+    unsigned int ordered_palette_size;
+
+    if (pfp) {
+        readOrderedPalette(pfp, ordered_palette, &ordered_palette_size);
+
+        if (colors != ordered_palette_size) 
+            pm_error("sizes of ordered palette (%d) "
+                     "and existing palette (%d) differ",
+                     ordered_palette_size, colors);
+        
+        /* Make sure the ordered palette contains all the colors in
+           the image 
+        */
+        for (colorIndex = 0; colorIndex < colors; colorIndex++) {
+            int j;
+            bool found;
+            
+            found = FALSE;
+            for (j = 0; j < ordered_palette_size && !found; ++j) {
+                if (PNM_EQUAL(ordered_palette[j], chv[colorIndex].color)) 
+                    found = TRUE;
+            }
+            if (!found) 
+                pm_error("failed to find color (%d, %d, %d), which is in the "
+                         "input image, in the ordered palette",
+                         PPM_GETR(chv[colorIndex].color),
+                         PPM_GETG(chv[colorIndex].color),
+                         PPM_GETB(chv[colorIndex].color));
+        }
+        /* OK, the ordered palette passes muster as a palette; go ahead
+           and return it as the palette.
+        */
+        for (colorIndex = 0; colorIndex < colors; ++colorIndex)
+            palette_pnm[colorIndex] = ordered_palette[colorIndex];
+    } else {
+        for (colorIndex = 0; colorIndex < colors; ++colorIndex) 
+            palette_pnm[colorIndex] = chv[colorIndex].color;
+    }
+    *paletteSizeP = colors;
+    *transSizeP = 0;
+}
+
+
+
+static void
+computeUnsortedAlphaPalette(FILE *           const ifP,
+                            int              const cols,
+                            int              const rows,
+                            xelval           const maxval,
+                            int              const format,
+                            pm_filepos       const rasterPos,
+                            gray **          const alpha_mask,
+                            unsigned int     const maxPaletteEntries,
+                            colorhist_vector const chv,
+                            int              const colors,
+                            gray *                 alphas_of_color[],
+                            unsigned int           alphas_first_index[],
+                            unsigned int           alphas_of_color_cnt[]) {
+/*----------------------------------------------------------------------------
+   Read the image at position 'rasterPos' in file *ifP, which is a PNM
+   described by 'cols', 'rows', 'maxval', and 'format'.
+
+   Using the alpha mask 'alpha_mask' and color map 'chv' (of size 'colors')
+   for the image, construct a palette of (color index, alpha) ordered pairs 
+   for the image, as follows.
+
+   The alpha/color palette is the set of all ordered pairs of
+   (color,alpha) in the PNG, including the background color.  The
+   actual palette is an array with up to 'maxPaletteEntries elements.  Each
+   array element contains a color index from the color palette and
+   an alpha value.  All the elements with the same color index are
+   contiguous.  alphas_first_index[x] is the index in the
+   alpha/color palette of the first element that has color index x.
+   alphas_of_color_cnt[x] is the number of elements that have color
+   index x.  alphas_of_color[x][y] is the yth alpha value that
+   appears with color index x (in order of appearance).
+   alpha_color_pair_count is the total number of elements, i.e. the
+   total number of combinations color and alpha.
+-----------------------------------------------------------------------------*/
+    colorhash_table cht;
+    int color_index;
+    int row;
+    xel * xelrow;
+
+    cht = ppm_colorhisttocolorhash (chv, colors);
+
+    for (color_index = 0 ; color_index < colors + 1 ; ++color_index) {
+        /* TODO: It sure would be nice if we didn't have to allocate
+           256 words here for what is normally only 0 or 1 different
+           alpha values!  Maybe we should do some sophisticated reallocation.
+        */
+        MALLOCARRAY(alphas_of_color[color_index], maxPaletteEntries);
+        if (alphas_of_color[color_index] == NULL)
+            pm_error ("out of memory allocating alpha/palette entries");
+        alphas_of_color_cnt[color_index] = 0;
+    }
+ 
+    pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
+
+    xelrow = pnm_allocrow(cols);
+
+    for (row = 0 ; row < rows ; ++row) {
+        int col;
+        pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
+        pnm_promoteformatrow(xelrow, cols, maxval, format, maxval, PPM_TYPE);
+        for (col = 0 ; col < cols ; ++col) {
+            int i;
+            int const color = ppm_lookupcolor(cht, &xelrow[col]);
+            for (i = 0 ; i < alphas_of_color_cnt[color] ; ++i) {
+                if (alpha_mask[row][col] == alphas_of_color[color][i])
+                    break;
+            }
+            if (i == alphas_of_color_cnt[color]) {
+                alphas_of_color[color][i] = alpha_mask[row][col];
+                alphas_of_color_cnt[color]++;
+            }
+        }
+    }
+    {
+        int i;
+        alphas_first_index[0] = 0;
+        for (i = 1 ; i < colors ; i++)
+            alphas_first_index[i] = alphas_first_index[i-1] +
+                alphas_of_color_cnt[i-1];
+    }
+    pnm_freerow(xelrow);
+    ppm_freecolorhash(cht);
+}
+
+
+
+static void
+sortAlphaPalette(gray *alphas_of_color[],
+                 unsigned int alphas_first_index[],
+                 unsigned int alphas_of_color_cnt[],
+                 unsigned int const colors,
+                 unsigned int mapping[],
+                 unsigned int * const transSizeP) {
+/*----------------------------------------------------------------------------
+   Remap the palette indices so opaque entries are last.
+
+   alphas_of_color[], alphas_first_index[], and alphas_of_color_cnt[]
+   describe an unsorted PNG (alpha/color) palette.  We generate
+   mapping[] such that mapping[x] is the index into the sorted PNG
+   palette of the alpha/color pair whose index is x in the unsorted
+   PNG palette.  This mapping sorts the palette so that opaque entries
+   are last.
+-----------------------------------------------------------------------------*/
+    unsigned int bot_idx;
+    unsigned int top_idx;
+    unsigned int colorIndex;
+    
+    /* We start one index at the bottom of the palette index range
+       and another at the top.  We run through the unsorted palette,
+       and when we see an opaque entry, we map it to the current top
+       cursor and bump it down.  When we see a non-opaque entry, we map 
+       it to the current bottom cursor and bump it up.  Because the input
+       and output palettes are the same size, the two cursors should meet
+       right when we process the last entry of the unsorted palette.
+    */    
+    bot_idx = 0;
+    top_idx = alphas_first_index[colors-1] + alphas_of_color_cnt[colors-1] - 1;
+    
+    for (colorIndex = 0;  colorIndex < colors;  ++colorIndex) {
+        unsigned int j;
+        for (j = 0; j < alphas_of_color_cnt[colorIndex]; ++j) {
+            unsigned int const paletteIndex = 
+                alphas_first_index[colorIndex] + j;
+            if (alphas_of_color[colorIndex][j] == PALETTEOPAQUE)
+                mapping[paletteIndex] = top_idx--;
+                else
+                    mapping[paletteIndex] = bot_idx++;
+        }
+    }
+    /* indices should have just crossed paths */
+    if (bot_idx != top_idx + 1) {
+        pm_error ("internal inconsistency: "
+                  "remapped bot_idx = %u, top_idx = %u",
+                  bot_idx, top_idx);
+    }
+    *transSizeP = bot_idx;
+}
+
+
+
+static void
+compute_alpha_palette(FILE *         const ifP, 
+                      int            const cols,
+                      int            const rows,
+                      xelval         const maxval,
+                      int            const format,
+                      pm_filepos     const rasterPos,
+                      gray **        const alpha_mask,
+                      pixel                palette_pnm[],
+                      gray                 trans_pnm[],
+                      unsigned int * const paletteSizeP,
+                      unsigned int * const transSizeP,
+                      bool *         const tooBigP) {
+/*----------------------------------------------------------------------------
+   Return the palette of color/alpha pairs for the image indicated by
+   'ifP', 'cols', 'rows', 'maxval', 'format', and 'rasterPos'.
+   alpha_mask[] is the Netpbm-style alpha mask for the image.
+
+   Return the palette as the arrays palette_pnm[] and trans_pnm[].
+   The ith entry in the palette is the combination of palette[i],
+   which defines the color, and trans[i], which defines the
+   transparency.
+
+   Return the number of entries in the palette as *paletteSizeP.
+
+   The palette is sorted so that the opaque entries are last, and we return
+   *transSizeP as the number of non-opaque entries.
+
+   palette[] and trans[] are allocated by the caller to at least 
+   MAXPALETTEENTRIES elements.
+
+   If there are more than MAXPALETTEENTRIES color/alpha pairs in the image, 
+   don't return any palette information -- just return *tooBigP == TRUE.
+-----------------------------------------------------------------------------*/
+    colorhist_vector chv;
+    unsigned int colors;
+
+    gray *alphas_of_color[MAXPALETTEENTRIES];
+    unsigned int alphas_first_index[MAXPALETTEENTRIES];
+    unsigned int alphas_of_color_cnt[MAXPALETTEENTRIES];
+ 
+    getChv(ifP, rasterPos, cols, rows, maxval, format, MAXCOLORS, 
+           &chv, &colors);
+
+    computeUnsortedAlphaPalette(ifP, cols, rows, maxval, format, rasterPos,
+                                alpha_mask, MAXPALETTEENTRIES, chv, colors,
+                                alphas_of_color,
+                                alphas_first_index,
+                                alphas_of_color_cnt);
+
+    *paletteSizeP = 
+        alphas_first_index[colors-1] + alphas_of_color_cnt[colors-1];
+    if (*paletteSizeP > MAXPALETTEENTRIES) {
+        *tooBigP = TRUE;
+    } else {
+        unsigned int mapping[MAXPALETTEENTRIES];
+            /* Sorting of the alpha/color palette.  mapping[x] is the
+               index into the sorted PNG palette of the alpha/color
+               pair whose index is x in the unsorted PNG palette.
+               This mapping sorts the palette so that opaque entries
+               are last.  
+            */
+
+        *tooBigP = FALSE;
+
+        /* Make the opaque palette entries last */
+        sortAlphaPalette(alphas_of_color, alphas_first_index,
+                         alphas_of_color_cnt, colors,
+                         mapping, transSizeP);
+
+        {
+            unsigned int colorIndex;
+
+            for (colorIndex = 0; colorIndex < colors; ++colorIndex) {
+                unsigned int j;
+                for (j = 0; j < alphas_of_color_cnt[colorIndex]; ++j) {
+                    unsigned int const paletteIndex = 
+                        alphas_first_index[colorIndex] + j;
+                    palette_pnm[mapping[paletteIndex]] = chv[colorIndex].color;
+                    trans_pnm[mapping[paletteIndex]] = 
+                    alphas_of_color[colorIndex][j];
+                }
+            }
+        }
+    }
+    { 
+        unsigned int colorIndex;
+        for (colorIndex = 0; colorIndex < colors + 1; ++colorIndex)
+            free(alphas_of_color[colorIndex]);
+    }
+} 
+
+
+
+static void
+makeOneColorTransparentInPalette(xel            const transColor, 
+                                 bool           const exact,
+                                 pixel                palette_pnm[],
+                                 unsigned int   const paletteSize,
+                                 gray                 trans_pnm[],
+                                 unsigned int * const transSizeP) {
+/*----------------------------------------------------------------------------
+   Find the color 'transColor' in the color/alpha palette defined by
+   palette_pnm[], paletteSize, trans_pnm[] and *transSizeP.  
+
+   Make that entry fully transparent.
+
+   Rearrange the palette so that that entry is first.  (The PNG compressor
+   can do a better job when the opaque entries are all last in the 
+   color/alpha palette).
+
+   If the specified color is not there and exact == TRUE, return
+   without changing anything, but issue a warning message.  If it's
+   not there and exact == FALSE, just find the closest color.
+
+   We assume every entry in the palette is opaque upon entry.
+
+   A valid palette has at least one color.
+-----------------------------------------------------------------------------*/
+    unsigned int transparentIndex;
+    unsigned int distance;
+
+    assert(paletteSize > 0);
+    
+    if (*transSizeP != 0)
+        pm_error("Internal error: trying to make a color in the palette "
+                 "transparent where there already is one.");
+
+    closestColorInPalette(transColor, palette_pnm, paletteSize, 
+                          &transparentIndex, &distance);
+
+    if (distance != 0 && exact) {
+        pm_message("specified transparent color not present in palette; "
+                   "ignoring -transparent");
+        errorlevel = PNMTOPNG_WARNING_LEVEL;
+    } else {        
+        /* Swap this with the first entry in the palette */
+        pixel tmp;
+    
+        tmp = palette_pnm[transparentIndex];
+        palette_pnm[transparentIndex] = palette_pnm[0];
+        palette_pnm[0] = tmp;
+        
+        /* Make it transparent */
+        trans_pnm[0] = PGM_TRANSPARENT;
+        *transSizeP = 1;
+        if (verbose) {
+            pixel const p = palette_pnm[0];
+            pm_message("Making all occurences of color (%u, %u, %u) "
+                       "transparent.",
+                       PPM_GETR(p), PPM_GETG(p), PPM_GETB(p));
+        }
+    }
+}
+
+
+
+static void
+findOrAddBackgroundInPalette(pixel          const backColor, 
+                             pixel                palette_pnm[], 
+                             unsigned int * const paletteSizeP,
+                             unsigned int * const backgroundIndexP) {
+/*----------------------------------------------------------------------------
+  Add the background color 'backColor' to the palette, unless
+  it's already in there.  If it's not present and there's no room to
+  add it, choose a background color that's already in the palette,
+  as close to 'backColor' as possible.
+
+  If we add an entry to the palette, make it opaque.  But in searching the 
+  existing palette, ignore transparency.
+
+  Note that PNG specs say that transparency of the background is meaningless;
+  i.e. a viewer must ignore the transparency of the palette entry when 
+  using the background color.
+
+  Return the palette index of the background color as *backgroundIndexP.
+-----------------------------------------------------------------------------*/
+    int backgroundIndex;  /* negative means not found */
+    unsigned int paletteIndex;
+
+    backgroundIndex = -1;
+    for (paletteIndex = 0; 
+         paletteIndex < *paletteSizeP; 
+         ++paletteIndex) 
+        if (PPM_EQUAL(palette_pnm[paletteIndex], backColor))
+            backgroundIndex = paletteIndex;
+
+    if (backgroundIndex >= 0) {
+        /* The background color is already in the palette. */
+        *backgroundIndexP = backgroundIndex;
+        if (verbose) {
+            pixel const p = palette_pnm[*backgroundIndexP];
+            pm_message("background color (%u, %u, %u) appears in image.",
+                       PPM_GETR(p), PPM_GETG(p), PPM_GETB(p));
+        }
+    } else {
+        /* Try to add the background color, opaque, to the palette. */
+        if (*paletteSizeP < MAXCOLORS) {
+            /* There's room, so just add it to the end of the palette */
+
+            /* Because we're not expanding the transparency palette, this
+               entry is not in it, and is thus opaque.
+            */
+            *backgroundIndexP = (*paletteSizeP)++;
+            palette_pnm[*backgroundIndexP] = backColor;
+            if (verbose) {
+                pixel const p = palette_pnm[*backgroundIndexP];
+                pm_message("added background color (%u, %u, %u) to palette.",
+                           PPM_GETR(p), PPM_GETG(p), PPM_GETB(p));
+            }
+        } else {
+            closestColorInPalette(backColor, palette_pnm, *paletteSizeP,
+                                  backgroundIndexP, NULL);
+            errorlevel = PNMTOPNG_WARNING_LEVEL;
+            {
+                pixel const p = palette_pnm[*backgroundIndexP];
+                pm_message("no room in palette for background color; "
+                           "using closest match (%u, %u, %u) instead",
+                           PPM_GETR(p), PPM_GETG(p), PPM_GETB(p));
+            }
+        }
+    }
+}
+
+
+
+static void 
+buildColorLookup(pixel                   palette_pnm[], 
+                 unsigned int      const paletteSize,
+                 colorhash_table * const chtP) {
+/*----------------------------------------------------------------------------
+   Create a colorhash_table out of the palette described by
+   palette_pnm[] (which has 'paletteSize' entries) so one can look up
+   the palette index of a given color.
+
+   Where the same color appears twice in the palette, the lookup table
+   finds an arbitrary one of them.  We don't consider transparency of
+   palette entries, so if the same color appears in the palette once
+   transparent and once opaque, the lookup table finds an arbitrary one
+   of those two.
+-----------------------------------------------------------------------------*/
+    colorhash_table const cht = ppm_alloccolorhash();
+    unsigned int paletteIndex;
+
+    for (paletteIndex = 0; paletteIndex < paletteSize; ++paletteIndex) {
+        ppm_addtocolorhash(cht, &palette_pnm[paletteIndex], paletteIndex);
+    }
+    *chtP = cht;
+}
+
+
+static void 
+buildColorAlphaLookup(pixel              palette_pnm[], 
+                      unsigned int const paletteSize,
+                      gray               trans_pnm[], 
+                      unsigned int const transSize,
+                      gray         const alphaMaxval,
+                      coloralphahash_table * const cahtP) {
+    
+    coloralphahash_table const caht = alloccoloralphahash();
+
+    unsigned int paletteIndex;
+
+    for (paletteIndex = 0; paletteIndex < paletteSize; ++paletteIndex) {
+        gray paletteTrans;
+
+        if (paletteIndex < transSize)
+            paletteTrans = alphaMaxval;
+        else
+            paletteTrans = trans_pnm[paletteIndex];
+
+
+        addtocoloralphahash(caht, &palette_pnm[paletteIndex],
+                            &trans_pnm[paletteIndex], paletteIndex);
+    }
+    *cahtP = caht;
+}
+
+
+
+static void
+tryAlphaPalette(FILE *         const ifP,
+                int            const cols,
+                int            const rows,
+                xelval         const maxval,
+                int            const format,
+                pm_filepos     const rasterPos,
+                gray **        const alpha_mask,
+                FILE *         const pfP,
+                pixel *        const palette_pnm,
+                unsigned int * const paletteSizeP,
+                gray *         const trans_pnm,
+                unsigned int * const transSizeP,
+                const char **  const impossibleReasonP) {
+/*----------------------------------------------------------------------------
+   Try to make an alpha palette as 'trans_pnm', size *transSizeP.
+
+   If it's impossible, return as *impossibleReasonP newly malloced storage
+   containing text that tells why.  But if we succeed, return
+   *impossibleReasonP == NULL.
+-----------------------------------------------------------------------------*/
+    bool tooBig;
+    if (pfP)
+        pm_error("This program is not capable of generating "
+                 "a PNG with transparency when you specify "
+                 "the palette with -palette.");
+
+    compute_alpha_palette(ifP, cols, rows, maxval, format, 
+                          rasterPos,  alpha_mask, palette_pnm, trans_pnm, 
+                          paletteSizeP, transSizeP, &tooBig);
+    if (tooBig) {
+        asprintfN(impossibleReasonP,
+                  "too many color/transparency pairs "
+                  "(more than the PNG maximum of %u", 
+                  MAXPALETTEENTRIES);
+    } else
+        *impossibleReasonP = NULL;
+} 
+
+
+
+static void
+computePixelWidth(int            const pnm_type,
+                  unsigned int   const pnm_meaningful_bits,
+                  bool           const alpha,
+                  unsigned int * const bitsPerSampleP,
+                  unsigned int * const bitsPerPixelP) {
+
+    unsigned int bitsPerSample, bitsPerPixel;
+
+    if (pnm_type == PPM_TYPE || 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)
+            bitsPerSample = 16;
+        else 
+            bitsPerSample = 8;
+    } else {
+        /* A grayscale, non-colormapped, no-alpha PNG may have any 
+             bit depth from 1 to 16
+          */
+        if (pnm_meaningful_bits > 8)
+            bitsPerSample = 16;
+        else if (pnm_meaningful_bits > 4)
+            bitsPerSample = 8;
+        else if (pnm_meaningful_bits > 2)
+            bitsPerSample = 4;
+        else if (pnm_meaningful_bits > 1)
+            bitsPerSample = 2;
+        else
+            bitsPerSample = 1;
+    }
+    if (alpha) {
+        if (pnm_type == PPM_TYPE)
+            bitsPerPixel = 4 * bitsPerSample;
+        else
+            bitsPerPixel = 2 * bitsPerSample;
+    } else {
+        if (pnm_type == PPM_TYPE)
+            bitsPerPixel = 3 * bitsPerSample;
+        else
+            bitsPerPixel = bitsPerSample;
+    }
+    if (bitsPerPixelP)
+        *bitsPerPixelP = bitsPerPixel;
+    if (bitsPerSampleP)
+        *bitsPerSampleP = bitsPerSample;
+}
+
+
+
+static unsigned int
+paletteIndexBits(unsigned int const nColors) {
+/*----------------------------------------------------------------------------
+  Return the number of bits that a palette index in the PNG will
+  occupy given that the palette has 'nColors' colors in it.  It is 1,
+  2, 4, or 8 bits.
+  
+  If 'nColors' is not a valid PNG palette size, return 0.
+-----------------------------------------------------------------------------*/
+    unsigned int retval;
+
+    if (nColors < 1)
+        retval = 0;
+    else if (nColors <= 2)
+        retval = 1;
+    else if (nColors <= 4)
+        retval = 2;
+    else if (nColors <= 16)
+        retval = 4;
+    else if (nColors <= 256)
+        retval = 8;
+    else
+        retval = 0;
+
+    return retval;
+}
+
+
+
+static void
+computeColorMap(FILE *         const ifP,
+                pm_filepos     const rasterPos,
+                int            const cols,
+                int            const rows,
+                xelval         const maxval,
+                int            const format,
+                bool           const force,
+                FILE *         const pfP,
+                bool           const alpha,
+                bool           const transparent,
+                pixel          const transcolor,
+                bool           const transexact,
+                bool           const background,
+                pixel          const backcolor,
+                gray **        const alpha_mask,
+                unsigned int   const pnm_meaningful_bits,
+                /* Outputs */
+                pixel *        const palette_pnm,
+                unsigned int * const paletteSizeP,
+                gray *         const trans_pnm,
+                unsigned int * const transSizeP,
+                unsigned int * const backgroundIndexP,
+                const char **  const noColormapReasonP) {
+/*---------------------------------------------------------------------------
+  Determine whether to do a colormapped or truecolor PNG and if
+  colormapped, compute the full PNG palette -- both color and
+  transparency.
+
+  If we decide to do truecolor, we return as *noColormapReasonP a text
+  description of why, in newly malloced memory.  If we decide to go
+  with colormapped, we return *noColormapReasonP == NULL.
+
+  In the colormapped case, we return the palette as arrays
+  palette_pnm[] and trans_pnm[], allocated by Caller, with sizes
+  *paletteSizeP and *transSizeP.
+
+  '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.
+-------------------------------------------------------------------------- */
+    if (force)
+        asprintfN(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);
+    else {
+        unsigned int bitsPerPixel;
+        computePixelWidth(PNM_FORMAT_TYPE(format), 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");
+        else {
+            /* We'll have to count the colors ('colors') to know if a
+               palette is possible and desirable.  Along the way, we'll
+               compute the actual set of colors (chv) too, and then create
+               the palette itself if we decide we want one.
+            */
+            colorhist_vector chv;
+            unsigned int colors;
+            
+            getChv(ifP, rasterPos, cols, rows, maxval, format, MAXCOLORS, 
+                   &chv, &colors);
+
+            if (chv == NULL) {
+                asprintfN(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);
+                else {
+                    unsigned int paletteSize;
+                    unsigned int transSize;
+                    if (alpha)
+                        tryAlphaPalette(ifP, cols, rows, maxval, format,
+                                        rasterPos, alpha_mask, pfP,
+                                        palette_pnm, &paletteSize, 
+                                        trans_pnm, &transSize,
+                                        noColormapReasonP);
+
+                    else {
+                        *noColormapReasonP = NULL;
+
+                        compute_nonalpha_palette(chv, colors, maxval, pfP,
+                                                 palette_pnm, &paletteSize, 
+                                                 trans_pnm, &transSize);
+    
+                        if (transparent)
+                            makeOneColorTransparentInPalette(
+                                transcolor, transexact, 
+                                palette_pnm, paletteSize, trans_pnm, 
+                                &transSize);
+                    }
+                    if (!*noColormapReasonP) {
+                        if (background)
+                            findOrAddBackgroundInPalette(
+                                backcolor, palette_pnm, &paletteSize,
+                                backgroundIndexP);
+                        *paletteSizeP = paletteSize;
+                        *transSizeP   = transSize;
+                    }
+                }
+            }
+            freeChv();
+        }
+    }
+}
+
+
+
+static void computeColorMapLookupTable(
+    bool                   const colorMapped,
+    pixel                        palette_pnm[],
+    unsigned int           const palette_size,
+    gray                         trans_pnm[],
+    unsigned int           const trans_size,
+    bool                   const alpha,
+    xelval                 const alpha_maxval,
+    colorhash_table *      const chtP,
+    coloralphahash_table * const cahtP) {
+/*----------------------------------------------------------------------------
+   Compute applicable lookup tables for the palette index.  If there's no
+   alpha mask, this is just a standard Netpbm colorhash_table.  If there's
+   an alpha mask, it is the slower Pnmtopng-specific 
+   coloralphahash_table.
+
+   If a lookup table is not applicable to the image, return NULL as
+   its address.  (If the image is not colormapped, both will be NULL).
+-----------------------------------------------------------------------------*/
+    if (colorMapped) {
+        if (alpha) {
+            buildColorAlphaLookup(palette_pnm, palette_size, 
+                                  trans_pnm, trans_size, alpha_maxval, cahtP);
+            *chtP = NULL;
+        } else { 
+            buildColorLookup(palette_pnm, palette_size, chtP);
+            *cahtP = NULL;
+        }
+        if (verbose)
+            pm_message("PNG palette has %u entries, %u of them non-opaque",
+                       palette_size, trans_size);
+    } else {
+        *chtP = NULL;
+        *cahtP = NULL;
+    }
+}
+
+
+
+static void
+computeRasterWidth(bool           const colorMapped,
+                   unsigned int   const palette_size,
+                   int            const pnm_type,
+                   unsigned int   const pnm_meaningful_bits,
+                   bool           const alpha,
+                   unsigned int * const bitsPerSampleP,
+                   unsigned int * const bitsPerPixelP) {
+/*----------------------------------------------------------------------------
+   Compute the number of bits per raster sample and per raster pixel:
+   *bitsPerSampleP and *bitsPerPixelP.  Note that a raster element may be a
+   palette index, or a gray value or color with or without alpha mask.
+-----------------------------------------------------------------------------*/
+    if (colorMapped) {
+        /* The raster element is a palette index */
+        if (palette_size <= 2)
+            *bitsPerSampleP = 1;
+        else if (palette_size <= 4)
+            *bitsPerSampleP = 2;
+        else if (palette_size <= 16)
+            *bitsPerSampleP = 4;
+        else
+            *bitsPerSampleP = 8;
+        *bitsPerPixelP = *bitsPerSampleP;
+        if (verbose)
+            pm_message("Writing %d-bit color indexes", *bitsPerSampleP);
+    } else {
+        /* The raster element is an explicit pixel -- color and transparency */
+        computePixelWidth(pnm_type, pnm_meaningful_bits, alpha,
+                          bitsPerSampleP, bitsPerPixelP);
+
+        if (verbose)
+            pm_message("Writing %d bits per component per pixel", 
+                       *bitsPerSampleP);
+    }
+}
+
+
+static void
+createPngPalette(pixel              palette_pnm[], 
+                 unsigned int const paletteSize, 
+                 pixval       const maxval,
+                 gray               trans_pnm[],
+                 unsigned int const transSize,
+                 gray               alpha_maxval,
+                 png_color          palette[],
+                 png_byte           trans[]) {
+/*----------------------------------------------------------------------------
+   Create the data structure to be passed to the PNG compressor to represent
+   the palette -- the whole palette, color + transparency.
+
+   This is basically just a maxval conversion from the Netpbm-format
+   equivalents we get as input.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+
+    for (i = 0; i < paletteSize; ++i) {
+        pixel p;
+        PPM_DEPTH(p, palette_pnm[i], maxval, PALETTEMAXVAL);
+        palette[i].red   = PPM_GETR(p);
+        palette[i].green = PPM_GETG(p);
+        palette[i].blue  = PPM_GETB(p);
+    }
+
+    for (i = 0; i < transSize; ++i) {
+        unsigned int const newmv = PALETTEMAXVAL;
+        unsigned int const oldmv = alpha_maxval;
+        trans[i] = (trans_pnm[i] * newmv + (oldmv/2)) / oldmv;
+    }
+}
+
+
+
+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,
+                   struct zlibCompression const zlibCompression) {
+
+    if (zlibCompression.levelSpec)
+        png_set_compression_level(png_ptr, zlibCompression.level);
+
+    if (zlibCompression.memLevelSpec)
+        png_set_compression_mem_level(png_ptr, zlibCompression.mem_level);
+
+    if (zlibCompression.strategySpec)
+        png_set_compression_strategy(png_ptr, zlibCompression.strategy);
+
+    if (zlibCompression.windowBitsSpec)
+        png_set_compression_window_bits(png_ptr, zlibCompression.window_bits);
+
+    if (zlibCompression.methodSpec)
+        png_set_compression_method(png_ptr, zlibCompression.method);
+
+    if (zlibCompression.bufferSizeSpec) {
+        setCompressionSize(png_ptr, zlibCompression.buffer_size);
+    }
+}
+                  
+
+
+static void
+makePngLine(png_byte *           const line,
+            const xel *          const xelrow,
+            unsigned int         const cols,
+            xelval               const maxval,
+            bool                 const alpha,
+            gray *               const alpha_mask,
+            colorhash_table      const cht,
+            coloralphahash_table const caht,
+            png_info *           const info_ptr,
+            xelval               const png_maxval,
+            unsigned int         const depth) {
+            
+    unsigned int col;
+    png_byte *pp;
+
+    pp = line;  /* start at beginning of line */
+    for (col = 0; col < cols; ++col) {
+        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 (depth == 16)
+                *pp++ = PNM_GET1(p_png) >> 8;
+            *pp++ = PNM_GET1(p_png) & 0xff;
+        } else if (info_ptr->color_type == 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) {
+            if (depth == 16)
+                *pp++ = PPM_GETR(p_png) >> 8;
+            *pp++ = PPM_GETR(p_png) & 0xff;
+            if (depth == 16)
+                *pp++ = PPM_GETG(p_png) >> 8;
+            *pp++ = PPM_GETG(p_png) & 0xff;
+            if (depth == 16)
+                *pp++ = PPM_GETB(p_png) >> 8;
+            *pp++ = PPM_GETB(p_png) & 0xff;
+        } else
+            pm_error("INTERNAL ERROR: undefined color_type");
+                
+        if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) {
+            int const png_alphaval = (int)
+                alpha_mask[col] * (float) png_maxval / maxval + 0.5;
+            if (depth == 16)
+                *pp++ = png_alphaval >> 8;
+            *pp++ = png_alphaval & 0xff;
+        }
+    }
+}
+
+
+
+static void
+writeRaster(png_struct *         const png_ptr,
+            png_info *           const info_ptr,
+            FILE *               const ifP,
+            pm_filepos           const rasterPos,
+            unsigned int         const cols,
+            unsigned int         const rows,
+            xelval               const maxval,
+            int                  const format,
+            xelval               const png_maxval,
+            unsigned             const int 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
+   from file *ifP, position 'rasterPos'.
+
+   The PNG raster consists of IDAT chunks.
+
+   'alpha_mask' is defined only if 'alpha' is true.
+-----------------------------------------------------------------------------*/
+    xel * xelrow;
+    png_byte * line;
+    unsigned int pass;
+
+    xelrow = pnm_allocrow(cols);
+
+    /* max: 3 color channels, one alpha channel, 16-bit */
+    MALLOCARRAY(line, cols * 8);
+    if (line == NULL)
+        pm_error("out of memory allocating PNG row buffer");
+
+    for (pass = 0; pass < png_set_interlace_handling(png_ptr); ++pass) {
+        unsigned int row;
+        pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
+        for (row = 0; row < rows; ++row) {
+            pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
+            pnm_promoteformatrow(xelrow, cols, maxval, format, maxval,
+                                 PPM_TYPE);
+            
+            makePngLine(line, xelrow, cols, maxval,
+                        alpha, alpha ? alpha_mask[row] : NULL,
+                        cht, caht, info_ptr, png_maxval, depth);
+
+            png_write_row(png_ptr, line);
+        }
+    }
+    pnm_freerow(xelrow);
+}
+
+
+
+static void
+doGamaChunk(struct cmdlineInfo const cmdline,
+            png_info *         const info_ptr) {
+            
+    if (cmdline.gammaSpec) {
+        /* gAMA chunk */
+        info_ptr->valid |= PNG_INFO_gAMA;
+        info_ptr->gamma = 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;
+    }
+}
+
+
+
+static void
+doPhysChunk(struct cmdlineInfo const cmdline,
+            png_info *         const info_ptr) {
+
+    if (cmdline.sizeSpec) {
+        /* pHYS chunk */
+        info_ptr->valid |= PNG_INFO_pHYs;
+
+        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,
+            png_info *         const info_ptr) {
+
+    if (cmdline.modtimeSpec) {
+        /* tIME chunk */
+        info_ptr->valid |= PNG_INFO_tIME;
+
+        png_convert_from_time_t(&info_ptr->mod_time, cmdline.modtime);
+    }
+}
+
+
+
+static void
+doSbitChunk(png_info * const pngInfoP,
+            xelval     const pngMaxval,
+            xelval     const maxval,
+            bool       const alpha,
+            xelval     const alphaMaxval) {
+
+    if (pngInfoP->color_type != PNG_COLOR_TYPE_PALETTE &&
+        (pngMaxval > maxval || (alpha && pngMaxval > alphaMaxval))) {
+
+        /* We're writing in a bit depth that doesn't match the maxval
+           of the input image and the alpha mask.  So we write an sBIT
+           chunk to tell what the original image's maxval was.  The
+           sBit chunk doesn't let us specify any maxval -- only powers
+           of two minus one.  So we pick the power of two minus one
+           which is greater than or equal to the actual input maxval.
+           
+           PNG also doesn't let an sBIT chunk indicate a maxval
+           _greater_ than the the PNG maxval.  The designers probably
+           did not conceive of the case where that would happen.  The
+           case is this: We detected redundancy in the bits so were
+           able to store fewer bits than the user provided.  But since
+           PNG doesn't allow it, we don't attempt to create such an
+           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;
+            } else
+                pngInfoP->sig_bit.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);
+        }
+    }
+}
+
+
+
+static void 
+convertpnm(struct cmdlineInfo const cmdline,
+           FILE *             const ifp,
+           FILE *             const afp,
+           FILE *             const pfp,
+           FILE *             const tfp,
+           int *              const errorLevelP
+    ) {
+/*----------------------------------------------------------------------------
+   Design note:  It's is really a modularity violation that we have
+   all the command line parameters as an argument.  We do it because we're
+   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;
+
+    if (verbose)
+      pm_message ("reading alpha-channel image...");
+    alpha_mask = pgm_readpgm (afp, &alpha_cols, &alpha_rows, &alpha_maxval);
+
+    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");
+    }
+    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;
+    }
+  } 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);
+  
+  computeColorMap(ifp, rasterPos, cols, rows, maxval, format,
+                  cmdline.force, pfp,
+                  alpha, transparent >= 0, transcolor, transexact, 
+                  !!cmdline.background, backcolor,
+                  alpha_mask, 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;
+  
+  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 = 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);
+
+        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;
+            }
+        }
+
+        ppm_freecolorhash(cht);
+
+        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.
+        */
+    }
+    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");
+    }
+  }
+
+  /* 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
+
+  pnm_freerow(xelrow);
+
+  if (cht)
+      ppm_freecolorhash(cht);
+  if (caht)
+      freecoloralphahash(caht);
+
+  *errorLevelP = errorlevel;
+}
+
+
+
+static void
+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.
+    */
+    fprintf(stderr, "   Compiled with libpng %s.\n",
+            PNG_LIBPNG_VER_STRING);
+    fprintf(stderr, "   Compiled with zlib %s; using zlib %s.\n",
+            ZLIB_VERSION, zlib_version);
+    fprintf(stderr, "\n");
+}
+
+
+
+int 
+main(int argc, char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    FILE * afP;
+    FILE * pfP;
+    FILE * tfP;
+
+    int errorlevel;
+    
+    pnm_init (&argc, argv);
+    
+    parseCommandLine(argc, argv, &cmdline);
+    
+    if (cmdline.libversion) {
+        displayVersion();
+        return 0;
+    }
+    verbose = cmdline.verbose;
+    
+    ifP = pm_openr_seekable(cmdline.inputFilename);
+    
+    if (cmdline.alpha)
+        afP = pm_openr(cmdline.alpha);
+    else
+        afP = NULL;
+    
+    if (cmdline.palette)
+        pfP = pm_openr(cmdline.palette);
+    else
+        pfP = NULL;
+    
+    if (cmdline.text)
+        tfP = pm_openr(cmdline.text);
+    else if (cmdline.ztxt)
+        tfP = pm_openr(cmdline.ztxt);
+    else
+        tfP = NULL;
+
+    convertpnm(cmdline, ifP, afP, pfP, tfP, &errorlevel);
+    
+    if (afP)
+        pm_close(afP);
+    if (pfP)
+        pm_close(pfP);
+    if (tfP)
+        pm_close(tfP);
+
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return errorlevel;
+}
diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c
new file mode 100644
index 00000000..9f6de526
--- /dev/null
+++ b/converter/other/pnmtops.c
@@ -0,0 +1,1323 @@
+/* pnmtops.c - read a PNM image and produce a PostScript program.
+
+   Copyright information is at end of file.
+
+   We produce two main kinds of Postscript program:
+
+      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.
+
+      2) Use our own filters and redefine /readstring .  This is aboriginal
+         Netpbm code, from when Postscript was young.
+
+   (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.
+
+   We also do a few other bold new things only when the user specifies
+   -psfilter, because we're not sure they work for everyone.
+
+   (I actually don't know Postscript, so some of this description, not to
+   mention the code, may be totally bogus.)
+
+   NOTE: it is possible to put transparency information in an
+   encapsulated Postscript program.  Bmeps does this.  We don't.  It
+   might be hard to do, because in Postscript, the transparency information
+   goes in separate from the rest of the raster.
+*/
+
+#define _BSD_SOURCE  /* Make sure string.h contains strdup() */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include <string.h>
+#include <assert.h>
+#include "pam.h"
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "nstring.h"
+#include "bmepsoe.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;  /* Filespecs of input file */
+    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 */
+    unsigned int height;             /* in 1/72 inch */
+    unsigned int mustturn;
+    bool         canturn;
+    unsigned int rle;
+    bool         center;
+    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 setpage;
+    bool         showpage;
+    unsigned int level;
+    unsigned int levelSpec;
+    unsigned int psfilter;
+    unsigned int flate;
+    unsigned int ascii85;
+    unsigned int dict;
+    unsigned int vmreclaim;
+    unsigned int verbose;
+};
+
+
+static bool verbose;
+
+
+static void
+parseDpi(const char *   const dpiOpt, 
+         unsigned int * const dpiXP, 
+         unsigned int * const dpiYP) {
+
+    char *dpistr2;
+    unsigned int dpiX, dpiY;
+
+    dpiX = strtol(dpiOpt, &dpistr2, 10);
+    if (dpistr2 == dpiOpt) 
+        pm_error("Invalid value for -dpi: '%s'.  Must be either number "
+                 "or NxN ", dpiOpt);
+    else {
+        if (*dpistr2 == '\0') {
+            *dpiXP = dpiX;
+            *dpiYP = dpiX;
+        } else if (*dpistr2 == 'x') {
+            char * dpistr3;
+
+            dpistr2++;  /* Move past 'x' */
+            dpiY = strtol(dpistr2, &dpistr3, 10);        
+            if (dpistr3 != dpistr2 && *dpistr3 == '\0') {
+                *dpiXP = dpiX;
+                *dpiYP = dpiY;
+            } else {
+                pm_error("Invalid value for -dpi: '%s'.  Must be either "
+                         "number or NxN", dpiOpt);
+            }
+        }
+    }
+}
+
+
+
+static void
+parseCommandLine(int argc, char ** argv,
+                 struct cmdlineInfo * const cmdlineP) {
+
+    unsigned int imagewidthSpec, imageheightSpec;
+    float imagewidth, imageheight;
+    unsigned int center, nocenter;
+    unsigned int nosetpage;
+    float width, height;
+    unsigned int noturn;
+    unsigned int showpage, noshowpage;
+    const char *dpiOpt;
+    unsigned int dpiSpec;
+
+    optStruct3 opt;
+    unsigned int option_def_index = 0;
+    optEntry *option_def;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    OPTENT3(0, "scale",       OPT_FLOAT, &cmdlineP->scale, NULL,         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, "psfilter",    OPT_FLAG,  NULL, &cmdlineP->psfilter,      0);
+    OPTENT3(0, "turn",        OPT_FLAG,  NULL, &cmdlineP->mustturn,      0);
+    OPTENT3(0, "noturn",      OPT_FLAG,  NULL, &noturn,                  0);
+    OPTENT3(0, "rle",         OPT_FLAG,  NULL, &cmdlineP->rle,           0);
+    OPTENT3(0, "runlength",   OPT_FLAG,  NULL, &cmdlineP->rle,           0);
+    OPTENT3(0, "ascii85",     OPT_FLAG,  NULL, &cmdlineP->ascii85,       0);
+    OPTENT3(0, "center",      OPT_FLAG,  NULL, &center,                  0);
+    OPTENT3(0, "nocenter",    OPT_FLAG,  NULL, &nocenter,                0);
+    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, "nosetpage",   OPT_FLAG,  NULL, &nosetpage,               0);
+    OPTENT3(0, "setpage",     OPT_FLAG,  NULL, &cmdlineP->setpage,       0);
+    OPTENT3(0, "noshowpage",  OPT_FLAG,  NULL, &noshowpage,              0);
+    OPTENT3(0, "flate",       OPT_FLAG,  NULL, &cmdlineP->flate,         0);
+    OPTENT3(0, "dict",        OPT_FLAG,  NULL, &cmdlineP->dict,          0);
+    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, "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);
+
+    if (cmdlineP->mustturn && noturn)
+        pm_error("You cannot specify both -turn and -noturn");
+    if (center && nocenter)
+        pm_error("You cannot specify both -center and -nocenter");
+    if (showpage && noshowpage)
+        pm_error("You cannot specify both -showpage and -noshowpage");
+    if (cmdlineP->setpage && nosetpage)
+        pm_error("You cannot specify both -setpage and -nosetpage");
+
+    if (dpiSpec)
+        parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY);
+    else {
+        cmdlineP->dpiX = 300;
+        cmdlineP->dpiY = 300;
+    }
+
+    cmdlineP->center  =  !nocenter;
+    cmdlineP->canturn =  !noturn;
+    cmdlineP->showpage = !noshowpage;
+    
+    cmdlineP->width  = width * 72;
+    cmdlineP->height = height * 72;
+
+    if (imagewidthSpec)
+        cmdlineP->imagewidth = imagewidth * 72;
+    else
+        cmdlineP->imagewidth = 0;
+    if (imageheightSpec)
+        cmdlineP->imageheight = imageheight * 72;
+    else
+        cmdlineP->imageheight = 0;
+
+    if (!cmdlineP->psfilter &&
+        (cmdlineP->flate || cmdlineP->ascii85))
+        pm_error("You must specify -psfilter in order to specify "
+                 "-flate or -ascii85");
+
+    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->inputFileName = argv[1];
+
+}
+
+
+/*===========================================================================
+  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.
+===========================================================================*/
+
+/*----------------------------------------------------------------------------
+   The following global variables are the native output encoder state.
+-----------------------------------------------------------------------------*/
+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;
+
+
+
+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().
+
+   We initialize the item putter state variables, which are the
+   global variable defined above.
+-----------------------------------------------------------------------------*/
+    itemsinline = 0;
+    items = 0;
+
+    if (rle) {
+        rleitem = 0;
+        rlebitsinitem = 0;
+        rlebitshift = 8 - bitspersample;
+        repeat = 1;
+        count = 0;
+    } else {
+        item = 0;
+        bitsinitem = 0;
+        bitshift = 8 - bitspersample;
+    }
+
+}
+
+
+
+static void
+putitem(void) {
+    const char* const hexits = "0123456789abcdef";
+
+    if (itemsinline == 30) {
+        putchar('\n');
+        itemsinline = 0;
+    }
+    putchar(hexits[item >> 4]);
+    putchar(hexits[item & 15]);
+    ++itemsinline;
+    ++items;
+    item = 0;
+    bitsinitem = 0;
+    bitshift = 8 - bitspersample;
+}
+
+
+
+static void
+flushitem() {
+    if (bitsinitem > 0)
+        putitem();
+}
+
+
+
+static void 
+putxelval(xelval const xv) {
+    if (bitsinitem == 8)
+        putitem();
+    item += xv << bitshift;
+    bitsinitem += bitspersample;
+    bitshift -= bitspersample;
+}
+
+
+
+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();
+        }
+    }
+    repeat = 1;
+    count = 0;
+}
+
+
+
+static void
+rleputitem() {
+    int i;
+
+    if ( count == 128 )
+        rleputbuffer();
+
+    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;
+            }
+        }
+    }
+    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;
+            }
+            else
+            { /* Not long enough yet - continue as non-repeat buf. */
+                itembuf[count] = rleitem;
+                ++count;
+            }
+        }
+        else
+        { /* Broken run. */
+            itembuf[count] = repeatitem = rleitem;
+            ++count;
+            repeatcount = 1;
+        }
+    }
+
+    rleitem = 0;
+    rlebitsinitem = 0;
+    rlebitshift = 8 - bitspersample;
+}
+
+
+
+static void 
+rleputxelval(xelval const xv) {
+    if (rlebitsinitem == 8)
+        rleputitem();
+    rleitem += xv << rlebitshift;
+    rlebitsinitem += bitspersample;
+    rlebitshift -= bitspersample;
+}
+
+
+
+static void
+rleflush() {
+    if (rlebitsinitem > 0)
+        rleputitem();
+    if (count > 0)
+        rleputbuffer();
+}
+
+
+static void
+flushNativeOutput(bool const rle) {
+    if (rle)
+        rleflush();
+    else
+        flushitem();
+    printf("\n");
+}
+        
+/*===========================================================================
+  The BMEPS output encoder.
+===========================================================================*/
+
+/* This code is just a wrapper around the output encoder that is part of
+   Bmeps, to give it better modularity.
+*/
+
+struct bmepsoe {
+    Output_Encoder * oeP;
+    int * rleBuffer;
+    Byte * flateInBuffer;
+    Byte * flateOutBuffer;
+};
+
+
+
+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;
+
+    oe_init(bmepsoeP->oeP, ofP, mode, 9, 
+            bmepsoeP->rleBuffer, 
+            bmepsoeP->flateInBuffer, FLATE_IN_SIZE,
+            bmepsoeP->flateOutBuffer, FLATE_OUT_SIZE);
+
+    *bmepsoePP = bmepsoeP;
+}
+
+
+
+static void
+destroyBmepsOutputEncoder(struct bmepsoe * const bmepsoeP) {
+    
+    free(bmepsoeP->rleBuffer);
+    free(bmepsoeP->flateInBuffer);
+    free(bmepsoeP->flateOutBuffer);
+    
+    free(bmepsoeP);
+}
+
+
+
+static void
+outputBmepsSample(struct bmepsoe * const bmepsoeP,
+                  unsigned int     const sampleValue,
+          unsigned int     const bitsPerSample) {
+
+    if (bitsPerSample == 8)
+        oe_byte_add(bmepsoeP->oeP, sampleValue);
+    else {
+        unsigned int m;
+
+        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); 
+    }
+}
+
+
+
+static void
+flushBmepsOutput(struct bmepsoe * const bmepsoeP) {
+    oe_byte_flush(bmepsoeP->oeP);
+}
+
+
+/*============================================================================
+   END OF OUTPUT ENCODERS
+============================================================================*/
+
+
+static void
+computeImagePosition(int     const dpiX, 
+                     int     const dpiY, 
+                     int     const icols, 
+                     int     const irows,
+                     bool    const mustturn,
+                     bool    const canturn,
+                     bool    const center,
+                     int     const pagewid, 
+                     int     const pagehgt, 
+                     float   const requestedScale,
+                     float   const imagewidth,
+                     float   const imageheight,
+                     bool    const equalpixels,
+                     float * const scolsP,
+                     float * const srowsP,
+                     float * const llxP, 
+                     float * const llyP,
+                     bool *  const turnedP ) {
+/*----------------------------------------------------------------------------
+   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.
+
+   '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.
+
+   *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.
+
+   *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.
+
+   '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.
+-----------------------------------------------------------------------------*/
+    int cols, rows;
+        /* 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)
+        shouldturn = TRUE;
+    else if (irows > icols && pagewid > pagehgt)
+        shouldturn = TRUE;
+    else
+        shouldturn = FALSE;
+
+    if (mustturn || (canturn && shouldturn)) {
+        *turnedP = TRUE;
+        cols = irows;
+        rows = icols;
+    } else {
+        *turnedP = FALSE;
+        cols = icols;
+        rows = irows;
+    }
+    if (equalpixels) {
+        *scolsP = (72.0/dpiX)*cols;
+        *srowsP = (72.0/dpiY)*rows;
+    } else if (imagewidth > 0 || imageheight > 0) {
+        float scale;
+
+        if (imagewidth == 0)
+            scale = (float) imageheight/rows;
+        else if (imageheight == 0)
+            scale = (float) imagewidth/cols;
+        else
+            scale = MIN((float)imagewidth/cols, (float)imageheight/rows);
+        
+        *scolsP = cols*scale;
+        *srowsP = rows*scale;
+    } else {
+        /* He didn't give us a bounding box for the image so figure
+           out output image size from other inputs.
+        */
+        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 */
+        const float pixfacX = 72.0 / dpiX * devpixX;  /* 1, approx. */
+        const float pixfacY = 72.0 / dpiY * devpixY;  /* 1, approx. */
+        float scale;
+
+        scale = MIN(requestedScale, 
+                    MIN((float)pagewid/cols, (float)pagehgt/rows));
+
+        *scolsP = scale * cols * pixfacX;
+        *srowsP = scale * rows * pixfacY;
+        
+        if (scale != requestedScale)
+            pm_message("warning, image too large for page, rescaling to %g", 
+                       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
+           scale it down.  But people have images that are exactly the size
+           of a page, e.g. because they created them with Sane's 'scanimage'
+           program from a full page of input.  So we removed the gratuitous
+           5% margin.  -Bryan.
+        */
+    }
+    *llxP = (center) ? ( pagewid - *scolsP ) / 2 : 0;
+    *llyP = (center) ? ( pagehgt - *srowsP ) / 2 : 0;
+
+
+    if (verbose)
+        pm_message("Image will be %3.2f points wide by %3.2f points high, "
+                   "left edge %3.2f points from left edge of page, "
+                   "bottom edge %3.2f points from top of page; "
+                   "%sturned to landscape orientation",
+                   *scolsP, *srowsP, *llxP, *llyP, *turnedP ? "" : "NOT ");
+}
+
+
+
+static void
+determineDictionaryRequirement(bool           const userWantsDict,
+                               bool           const psFilter,
+                               unsigned int * const dictSizeP) {
+
+    if (userWantsDict) {
+        if (psFilter) {
+            /* The Postscript this program generates to use built-in
+               Postscript filters does not define any variables.
+            */
+            *dictSizeP = 0;
+        } else
+            *dictSizeP = 8;
+    } else
+        *dictSizeP = 0;
+}
+
+
+
+static void
+defineReadstring(bool const rle) {
+/*----------------------------------------------------------------------------
+   Write to Standard Output Postscript statements to define /readstring.
+-----------------------------------------------------------------------------*/
+    if (rle) {
+        printf("/rlestr1 1 string def\n");
+        printf("/readrlestring {\n");             /* s -- nr */
+        printf("  /rlestr exch def\n");           /* - */
+        printf("  currentfile rlestr1 readhexstring pop\n");  /* s1 */
+        printf("  0 get\n");                  /* c */
+        printf("  dup 127 le {\n");               /* c */
+        printf("    currentfile rlestr 0\n");         /* c f s 0 */
+        printf("    4 3 roll\n");             /* f s 0 c */
+        printf("    1 add  getinterval\n");           /* f s */
+        printf("    readhexstring pop\n");            /* s */
+        printf("    length\n");               /* nr */
+        printf("  } {\n");                    /* c */
+        printf("    256 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*/
+        printf("      rlestr exch 2 index put\n");
+        printf("    } for\n");                /* n c */
+        printf("    pop\n");                  /* nr */
+        printf("  } ifelse\n");               /* nr */
+        printf("} bind def\n");
+        printf("/readstring {\n");                /* s -- s */
+        printf("  dup length 0 {\n");             /* s l 0 */
+        printf("    3 copy exch\n");              /* s l n s n l*/
+        printf("    1 index sub\n");              /* s l n s n r*/
+        printf("    getinterval\n");              /* s l n ss */
+        printf("    readrlestring\n");            /* s l n nr */
+        printf("    add\n");                  /* s l n */
+        printf("    2 copy le { exit } if\n");        /* s l n */
+        printf("  } loop\n");                 /* s l l */
+        printf("  pop pop\n");                /* s */
+        printf("} bind def\n");
+    } else {
+        printf("/readstring {\n");                /* s -- s */
+        printf("  currentfile exch readhexstring pop\n");
+        printf("} bind def\n");
+    }
+}
+
+
+
+static void
+setupReadstringNative(bool         const rle,
+                      bool         const color,
+                      unsigned int const icols, 
+                      unsigned int const padright, 
+                      unsigned int const bps) {
+/*----------------------------------------------------------------------------
+   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;
+
+    defineReadstring(rle);
+    
+    if (color) {
+        printf("/rpicstr %d string def\n", bytesPerRow);
+        printf("/gpicstr %d string def\n", bytesPerRow);
+        printf("/bpicstr %d string def\n", bytesPerRow);
+    } else
+        printf("/picstr %d string def\n", bytesPerRow);
+}
+
+
+
+static void
+putFilters(unsigned int const postscriptLevel,
+           bool         const rle,
+           bool         const flate,
+           bool         const ascii85,
+           bool         const color) {
+
+    assert(postscriptLevel > 1);
+    
+    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! */
+        printf("/RunLengthDecode filter ");
+}
+
+
+
+static void
+putReadstringNative(bool const color) {
+
+    if (color) {
+        printf("{ rpicstr readstring }\n");
+        printf("{ gpicstr readstring }\n");
+        printf("{ bpicstr readstring }\n");
+    } else
+        printf("{ picstr readstring }\n");
+}
+
+
+
+static void
+putSetup(unsigned int const dictSize,
+         bool         const psFilter,
+         bool         const rle,
+         bool         const color,
+         unsigned int const icols,
+         unsigned int const padright,
+         unsigned int const bps) {
+/*----------------------------------------------------------------------------
+   Put the setup section in the Postscript program on Standard Output.
+-----------------------------------------------------------------------------*/
+    printf("%%%%BeginSetup\n");
+
+    if (dictSize > 0)
+        /* inputf {r,g,b,}pictsr readstring readrlestring rlestring */
+        printf("%u dict begin\n", dictSize);
+    
+    if (!psFilter)
+        setupReadstringNative(rle, color, icols, padright, bps);
+
+    printf("%%%%EndSetup\n");
+}
+
+
+
+static void
+putImage(bool const psFilter,
+         bool const color) {
+/*----------------------------------------------------------------------------
+   Put the image/colorimage statement in the Postscript program on
+   Standard Output.
+-----------------------------------------------------------------------------*/
+    if (color) {
+        if (psFilter)
+            printf("false 3\n");
+        else
+            printf("true 3\n");
+        printf("colorimage");
+    } else
+        printf("image");
+}
+
+
+
+static void
+putInitPsFilter(unsigned int const postscriptLevel,
+                bool         const rle,
+                bool         const flate,
+                bool         const ascii85,
+                bool         const color) {
+
+    bool const filterTrue = TRUE;
+
+    printf("{ currentfile ");
+
+    putFilters(postscriptLevel, rle, flate, ascii85, color);
+
+    putImage(filterTrue, color);
+    
+    printf(" } exec");
+}
+
+
+
+static void
+putInitReadstringNative(bool const color) {
+
+    bool const filterFalse = FALSE;
+
+    putReadstringNative(color);
+    
+    putImage(filterFalse, color);
+}
+
+
+
+static void
+putInit(unsigned int const postscriptLevel,
+        char         const name[], 
+        int          const icols, 
+        int          const irows, 
+        float        const scols, 
+        float        const srows,
+        float        const llx, 
+        float        const lly,
+        int          const padright, 
+        int          const bps,
+        int          const pagewid, 
+        int          const pagehgt,
+        bool         const color, 
+        bool         const turned, 
+        bool         const rle,
+        bool         const flate,
+        bool         const ascii85,
+        bool         const setpage,
+        bool         const psFilter,
+        unsigned int const dictSize) {
+/*----------------------------------------------------------------------------
+   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
+       spec being adhered to, the second is the level of the EPSF spec being
+       adhered to.  It is *incorrect* to claim EPSF compliance if the file
+       contains a setpagedevice.
+    */
+    printf("%%!PS-Adobe-3.0%s\n", setpage ? "" : " EPSF-3.0");
+    printf("%%%%LanguageLevel: %u\n", postscriptLevel);
+    printf("%%%%Creator: pnmtops\n");
+    printf("%%%%Title: %s.ps\n", name);
+    printf("%%%%Pages: 1\n");
+    printf(
+        "%%%%BoundingBox: %d %d %d %d\n",
+        (int) llx, (int) lly,
+        (int) (llx + scols + 0.5), (int) (lly + srows + 0.5));
+    printf("%%%%EndComments\n");
+
+    putSetup(dictSize, psFilter, rle, color, icols, padright, bps);
+
+    printf("%%%%Page: 1 1\n");
+    if (setpage)
+        printf("<< /PageSize [ %d %d ] /ImagingBBox null >> setpagedevice\n",
+               pagewid, pagehgt);
+    printf("gsave\n");
+    printf("%g %g translate\n", llx, lly);
+    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 0 0 -%d 0 %d ]\n", icols, irows, irows);
+
+    if (psFilter)
+        putInitPsFilter(postscriptLevel, rle, flate, ascii85, color);
+    else
+        putInitReadstringNative(color);
+
+    printf("\n");
+}
+
+
+
+static void
+putEnd(bool         const showpage, 
+       bool         const psFilter,
+       bool         const ascii85,
+       unsigned int const dictSize,
+       bool         const vmreclaim) {
+
+    if (psFilter) {
+        if (ascii85)
+            printf("%s\n", "~>");
+        else
+            printf("%s\n", ">");
+    } else {
+        printf("currentdict /inputf undef\n");
+        printf("currentdict /picstr undef\n");
+        printf("currentdict /rpicstr undef\n");
+        printf("currentdict /gpicstr undef\n");
+        printf("currentdict /bpicstr undef\n");
+    }
+
+    if (dictSize > 0)
+        printf("end\n");
+
+    if (vmreclaim)
+        printf("1 vmreclaim\n");
+
+    printf("grestore\n");
+
+    if (showpage)
+        printf("showpage\n");
+    printf("%%%%Trailer\n");
+}
+
+
+
+static void
+computeDepth(xelval         const inputMaxval,
+             unsigned int   const postscriptLevel, 
+             unsigned int * const bitspersampleP,
+             unsigned int * const psMaxvalP) {
+/*----------------------------------------------------------------------------
+   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.
+-----------------------------------------------------------------------------*/
+    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 || postscriptLevel < 2)
+        *bitspersampleP = 8;
+    else
+        *bitspersampleP = 12;
+
+    if (*bitspersampleP < bitsRequiredByMaxval)
+        pm_message("Maxval of input requires %u bit samples for full "
+                   "resolution, but we are using the Postscript level %u "
+                   "maximum of %u",
+                   bitsRequiredByMaxval, postscriptLevel, *bitspersampleP);
+
+    *psMaxvalP = pm_bitstomaxval(*bitspersampleP);
+
+    if (verbose)
+        pm_message("Input maxval is %u.  Postscript raster will have "
+                   "%u bits per sample, so maxval = %u",
+                   inputMaxval, *bitspersampleP, *psMaxvalP);
+}    
+
+
+
+static void
+convertRowNative(struct pam * const pamP, 
+                 tuple *      const tuplerow, 
+                 unsigned int const psMaxval, 
+                 bool         const rle, 
+                 unsigned int const padright) {
+
+    unsigned int plane;
+
+    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);
+
+            if (rle)
+                rleputxelval(scaledSample);
+            else
+                putxelval(scaledSample);
+        }
+        for (col = 0; col < padright; ++col)
+            if (rle)
+                rleputxelval(0);
+        else
+            putxelval(0);
+        if (rle)
+            rleflush();
+    }
+}
+
+
+
+static void
+convertRowPsFilter(struct pam *     const pamP,
+                   tuple *          const tuplerow,
+                   struct bmepsoe * const bmepsoeP,
+                   unsigned int     const psMaxval) {
+
+    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 col;
+    tuple scaledTuple;
+    
+    scaledTuple = pnm_allocpamtuple(pamP);
+
+    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);
+    }
+    pnm_freepamtuple(scaledTuple);
+}
+
+
+
+static void
+selectPostscriptLevel(bool           const levelIsGiven,
+                      unsigned int   const levelGiven,
+                      bool           const color,
+                      bool           const dict,
+                      bool           const flate,
+                      bool           const ascii85,
+                      bool           const psFilter,
+                      unsigned int * const postscriptLevelP) {
+
+    unsigned int const maxPermittedLevel = 
+        levelIsGiven ? levelGiven : UINT_MAX;
+    unsigned int minPossibleLevel;
+
+    /* Until we know, later in this function, that we needs certain
+       features, we assume we can get by with classic Postscript Level 1:
+    */
+    minPossibleLevel = 1;
+
+    /* Now we increase 'minPossibleLevel' as we notice that each of
+       various features are required:
+    */
+    if (color) {
+        minPossibleLevel = MAX(minPossibleLevel, 2);
+        if (2 > maxPermittedLevel)
+            pm_error("Color requires at least Postscript level 2");
+    }
+    if (flate) {
+        minPossibleLevel = MAX(minPossibleLevel, 3);
+        if (2 > maxPermittedLevel)
+            pm_error("flate compression requires at least Postscript level 3");
+    }
+    if (ascii85) {
+        minPossibleLevel = MAX(minPossibleLevel, 2);
+        if (2 > maxPermittedLevel)
+            pm_error("ascii85 encoding requires at least Postscript level 2");
+    }
+    if (psFilter) {
+        minPossibleLevel = MAX(minPossibleLevel, 2);
+        if (2 > maxPermittedLevel)
+            pm_error("-psfilter requires at least Postscript level 2");
+    }
+    if (levelIsGiven)
+        *postscriptLevelP = levelGiven;
+    else
+        *postscriptLevelP = minPossibleLevel;
+}
+
+
+
+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,
+            bool   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;
+        /* Size of Postscript dictionary we should define */
+
+    pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
+    
+    if (!STRSEQ(inpam.tuple_type, PAM_PBM_TUPLETYPE) &&
+        !STRSEQ(inpam.tuple_type, PAM_PGM_TUPLETYPE) &&
+        !STRSEQ(inpam.tuple_type, PAM_PPM_TUPLETYPE))
+        pm_error("Unrecognized tuple type %s.  This program accepts only "
+                 "PBM, PGM, PPM, and equivalent PAM input images", 
+                 inpam.tuple_type);
+
+    color = STRSEQ(inpam.tuple_type, PAM_PPM_TUPLETYPE);
+    
+    selectPostscriptLevel(levelIsGiven, levelGiven, color, 
+                          dict, flate, ascii85, psFilter, &postscriptLevel);
+    
+    if (color)
+        pm_message("generating color Postscript program.");
+
+    computeDepth(inpam.maxval, postscriptLevel, &bitspersample, &psMaxval);
+    {
+        unsigned int const realBitsPerLine = inpam.width * bitspersample;
+        unsigned int const paddedBitsPerLine = ((realBitsPerLine + 7) / 8) * 8;
+        padright = (paddedBitsPerLine - realBitsPerLine) / bitspersample;
+    }
+    /* In positioning/scaling the image, we treat the input image as if
+       it has a density of 72 pixels per inch.
+    */
+    computeImagePosition(dpiX, dpiY, inpam.width, inpam.height, 
+                         turnflag, turnokflag, center,
+                         pagewid, pagehgt, scale, imagewidth, imageheight,
+                         equalpixels,
+                         &scols, &srows, &llx, &lly, &turned);
+
+    determineDictionaryRequirement(dict, psFilter, &dictSize);
+    
+    putInit(postscriptLevel, name, inpam.width, inpam.height, 
+            scols, srows, llx, lly, padright, bitspersample, 
+            pagewid, pagehgt, color,
+            turned, rle, flate, ascii85, setpage, psFilter, dictSize);
+
+    createBmepsOutputEncoder(&bmepsoeP, stdout, rle, flate, ascii85);
+    initNativeOutputEncoder(rle, bitspersample);
+
+    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);
+    }
+
+    pnm_freepamrow(tuplerow);
+
+    if (psFilter)
+        flushBmepsOutput(bmepsoeP);
+    else
+        flushNativeOutput(rle);
+
+    destroyBmepsOutputEncoder(bmepsoeP);
+
+    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[]) {
+
+    FILE* ifp;
+    const char *name;  /* malloc'ed */
+    struct cmdlineInfo cmdline;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    verbose = cmdline.verbose;
+
+    ifp = pm_openr(cmdline.inputFileName);
+
+    if (STREQ(cmdline.inputFileName, "-"))
+        name = strdup("noname");
+    else
+        name = basebasename(cmdline.inputFileName);
+    {
+        int eof;  /* There are no more images in the input file */
+        unsigned int imageSeq;
+
+        /* I don't know if this works at all for multi-image PNM input.
+           Before July 2000, it ignored everything after the first image,
+           so this probably is at least as good -- it should be identical
+           for a single-image file, which is the only kind which was legal
+           before July 2000.
+
+           Maybe there needs to be some per-file header and trailers stuff
+           in the Postscript program, with some per-page header and trailer
+           stuff inside.  I don't know Postscript.  - Bryan 2000.06.19.
+        */
+
+        eof = FALSE;  /* There is always at least one image */
+        for (imageSeq = 0; !eof; ++imageSeq) {
+            convertPage(ifp, cmdline.mustturn, cmdline.canturn, 
+                        cmdline.psfilter,
+                        cmdline.rle, cmdline.flate, cmdline.ascii85, 
+                        cmdline.setpage, cmdline.showpage,
+                        cmdline.center, cmdline.scale,
+                        cmdline.dpiX, cmdline.dpiY,
+                        cmdline.width, cmdline.height, 
+                        cmdline.imagewidth, cmdline.imageheight, 
+                        cmdline.equalpixels, name, 
+                        cmdline.dict, cmdline.vmreclaim,
+                        cmdline.levelSpec, cmdline.level);
+            pnm_nextimage(ifp, &eof);
+        }
+    }
+    strfree(name);
+
+    pm_close(ifp);
+    
+    return 0;
+}
+
+
+
+/*
+** Copyright (C) 1989 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.
+**
+**
+** -nocenter option added November 1993 by Wolfgang Stuerzlinger,
+**  wrzl@gup.uni-linz.ac.at.
+**
+*/
diff --git a/converter/other/pnmtorast.c b/converter/other/pnmtorast.c
new file mode 100644
index 00000000..7d1ae05a
--- /dev/null
+++ b/converter/other/pnmtorast.c
@@ -0,0 +1,310 @@
+/* pnmtorast.c - read a portable anymap and produce a Sun rasterfile
+**
+** Copyright (C) 1989, 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.
+*/
+
+#include "pnm.h"
+#include "rast.h"
+#include "mallocvar.h"
+
+#define MAXCOLORS 256
+static colormap_t* make_pr_colormap ARGS(( colorhist_vector chv, int colors ));
+static colormap_t* make_gray_pr_colormap ARGS(( void ));
+static colormap_t* alloc_pr_colormap ARGS(( void ));
+
+int
+main( argc, argv )
+    int argc;
+    char* argv[];
+{
+    FILE* ifp;
+    xel** xels;
+    xel* xelrow;
+    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;
+    xelval maxval;
+    struct pixrect* pr;
+    unsigned char* data;
+    register unsigned char* byteP;
+    const char* const usage = "[-standard|-rle] [pnmfile]";
+
+    pnm_init( &argc, argv );
+
+    argn = 1;
+    pr_type = RT_BYTE_ENCODED;
+
+    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
+    {
+        if ( pm_keymatch( argv[argn], "-standard", 2 ) )
+            pr_type = RT_STANDARD;
+        else if ( pm_keymatch( argv[argn], "-rle", 2 ) )
+            pr_type = RT_BYTE_ENCODED;
+        else
+            pm_usage( usage );
+        ++argn;
+    }
+
+    if ( argn != argc )
+    {
+        ifp = pm_openr( argv[argn] );
+        ++argn;
+    }
+    else
+        ifp = stdin;
+
+    if ( argn != argc )
+        pm_usage( usage );
+
+    xels = pnm_readpnm( ifp, &cols, &rows, &maxval, &format );
+
+    pm_close( ifp );
+
+    /* Figure out the proper depth and colormap. */
+    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(
+                "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 );
+            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 );
+
+            /* 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. */
+                depth = 1;
+                pr_colormapP = (colormap_t*) 0;
+            }
+            else
+            {
+                /* Turn the ppm colormap into the appropriate Sun colormap. */
+                depth = 8;
+                pr_colormapP = make_pr_colormap( chv, colors );
+            }
+            cht = ppm_colorhisttocolorhash( chv, colors );
+            ppm_freecolorhist( chv );
+        }
+
+        break;
+
+    case PGM_TYPE:
+        depth = 8;
+        pr_colormapP = make_gray_pr_colormap( );
+        break;
+
+    default:
+        depth = 1;
+        pr_colormapP = (colormap_t*) 0;
+        break;
+    }
+
+    if ( maxval > 255 && depth != 1 )
+        pm_message(
+            "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;
+
+        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;
+
+        default:
+            pm_error( "can't happen" );
+        }
+        data += linesize;
+    }
+    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" );
+
+    exit( 0 );
+}
+
+static colormap_t*
+make_pr_colormap( chv, colors )
+    colorhist_vector chv;
+    int colors;
+{
+    colormap_t* pr_colormapP;
+    int i;
+
+    pr_colormapP = alloc_pr_colormap( );
+
+    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 < MAXCOLORS; ++i )
+        pr_colormapP->map[0][i] = pr_colormapP->map[1][i] =
+            pr_colormapP->map[2][i] = 0;
+
+    return pr_colormapP;
+}
+
+static colormap_t*
+make_gray_pr_colormap( )
+{
+    colormap_t* pr_colormapP;
+    int i;
+
+    pr_colormapP = alloc_pr_colormap( );
+
+    for ( i = 0; i < MAXCOLORS; ++i )
+    {
+        pr_colormapP->map[0][i] = i;
+        pr_colormapP->map[1][i] = i;
+        pr_colormapP->map[2][i] = i;
+    }
+
+    return pr_colormapP;
+}
+
+static colormap_t*
+alloc_pr_colormap( )
+{
+    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;
+}
diff --git a/converter/other/pnmtorle.c b/converter/other/pnmtorle.c
new file mode 100644
index 00000000..8c6dc589
--- /dev/null
+++ b/converter/other/pnmtorle.c
@@ -0,0 +1,267 @@
+/*
+ * This is derived from the file of the same name dated June 5, 1995,
+ * copied from the Army High Performance Computing Research Center's
+ * media-tools.tar.gz package, received from 
+ * http://www.arc.umn.edu/gvl-software/media-tools.tar.gz on 2000.04.13.
+ *
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is
+ * preserved on all copies.
+ *
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/*
+ * pnmtorle - A program which will convert pbmplus (ppm or pgm) images
+ *            to Utah's "rle" image format.
+ *
+ * Author:      Wes Barris (wes@msc.edu)
+ *              AHPCRC
+ *              Minnesota Supercomputer Center, Inc.
+ * Date:        March 30, 1994
+ * Copyright (c) Minnesota Supercomputer Center, Inc.
+ * 
+ * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler 
+ *            warnings.
+ *
+ */
+/*-----------------------------------------------------
+ * System includes.
+ */
+#include <string.h>
+#include <stdio.h>
+#include "pnm.h"
+#include "mallocvar.h"
+#include "rle.h"
+
+#define VPRINTF if (verbose || header) fprintf
+
+typedef unsigned char U_CHAR;
+/*
+ * Global variables.
+ */
+static FILE    *fp;
+static rle_hdr hdr;
+static int  format;
+static int width, height;
+static int verbose = 0, header = 0, do_alpha = 0;
+static gray    maxval;
+/*-----------------------------------------------------------------------------
+ *                                        Read the pnm image file header.
+ */
+static void 
+read_pnm_header()
+{
+    pnm_readpnminit(fp, &width, &height, &maxval, &format);
+    switch (format) {
+    case PBM_FORMAT:
+        VPRINTF(stderr, "Image type: plain pbm format\n");
+        break;
+    case RPBM_FORMAT:
+        VPRINTF(stderr, "Image type: raw pbm format\n");
+        break;
+    case PGM_FORMAT:
+        VPRINTF(stderr, "Image type: plain pgm format\n");
+        break;
+    case RPGM_FORMAT:
+        VPRINTF(stderr, "Image type: raw pgm format\n");
+        break;
+    case PPM_FORMAT:
+        VPRINTF(stderr, "Image type: plain ppm format\n");
+        break;
+    case RPPM_FORMAT:
+        VPRINTF(stderr, "Image type: raw ppm format\n");
+        break;
+    }
+    VPRINTF(stderr, "Full image: %dx%d\n", width, height);
+    VPRINTF(stderr, "Maxval:     %d\n", maxval);
+    if (do_alpha)
+        VPRINTF(stderr, "Computing alpha channel...\n");
+}
+/*-----------------------------------------------------------------------------
+ *                                             Write the rle image file header.
+ */
+static void 
+write_rle_header()
+{
+    hdr.xmin    = 0;
+    hdr.xmax    = width-1;
+    hdr.ymin    = 0;
+    hdr.ymax    = height-1;
+    hdr.background = 0;
+    switch (format) {
+    case PBM_FORMAT:
+    case RPBM_FORMAT:
+    case PGM_FORMAT:
+    case RPGM_FORMAT:
+        hdr.ncolors = 1;
+        RLE_SET_BIT(hdr, RLE_RED);
+        break;
+    case PPM_FORMAT:
+    case RPPM_FORMAT:
+        hdr.ncolors = 3;
+        RLE_SET_BIT(hdr, RLE_RED);
+        RLE_SET_BIT(hdr, RLE_GREEN);
+        RLE_SET_BIT(hdr, RLE_BLUE);
+        break;
+    }
+    if (do_alpha) {
+        hdr.alpha = 1;
+        RLE_SET_BIT(hdr, RLE_ALPHA);
+    }
+    rle_put_setup(&hdr);
+}
+/*-----------------------------------------------------------------------------
+ *                                      Write the rle data portion of the file.
+ */
+static void 
+write_rle_data()
+{
+    register int     x;
+    register int     scan;
+    register xel     *xelrow, *pP;
+    rle_pixel        ***scanlines, **scanline;
+/*
+ * Allocate some memory.
+ */
+    /*xelrow = pnm_allowcrow(width);*/
+    xelrow = (xel*) pm_allocrow( width, sizeof(xel) );
+    MALLOCARRAY(scanlines, height);
+    RLE_CHECK_ALLOC( hdr.cmd, scanlines, "scanline pointers" );
+
+    for ( scan = 0; scan < height; scan++ )
+        RLE_CHECK_ALLOC( hdr.cmd, (rle_row_alloc(&hdr, &scanlines[scan]) >= 0),
+                         "pixel memory" );
+/*
+ * Loop through the pnm files image window, read data and flip vertically.
+ */
+    switch (format) {
+    case PBM_FORMAT:
+    case RPBM_FORMAT:
+        for (scan = 0; scan < height; scan++) {
+            scanline = scanlines[height - scan - 1];
+            pnm_readpnmrow(fp, xelrow, width, maxval, format);
+            for (x = 0, pP = xelrow; x < width; x++, pP++) {
+                scanline[RLE_RED][x]   = (PNM_GET1(*pP) ? 255 : 0);
+                if (do_alpha) {
+                    scanline[RLE_ALPHA][x] = scanline[RLE_RED][x];
+                }
+            }
+        }
+        break;
+    case PGM_FORMAT:
+    case RPGM_FORMAT:
+        for (scan = 0; scan < height; scan++) {
+            scanline = scanlines[height - scan - 1];
+            pnm_readpnmrow(fp, xelrow, width, maxval, format);
+            for (x = 0, pP = xelrow; x < width; x++, pP++) {
+                scanline[RLE_RED][x]   = PNM_GET1(*pP);
+                if (do_alpha) {
+                    scanline[RLE_ALPHA][x] = (scanline[RLE_RED][x] ? 255 : 0);
+                }
+            }
+        }
+        break;
+    case PPM_FORMAT:
+    case RPPM_FORMAT:
+        for (scan = 0; scan < height; scan++) {
+            scanline = scanlines[height - scan - 1];
+            pnm_readpnmrow(fp, xelrow, width, maxval, format);
+            for (x = 0, pP = xelrow; x < width; x++, pP++) {
+                scanline[RLE_RED][x]   = PPM_GETR(*pP);
+                scanline[RLE_GREEN][x] = PPM_GETG(*pP);
+                scanline[RLE_BLUE][x]  = PPM_GETB(*pP);
+                if (do_alpha) {
+                    scanline[RLE_ALPHA][x] = (scanline[RLE_RED][x] ||
+                                              scanline[RLE_GREEN][x] ||
+                                              scanline[RLE_BLUE][x] ? 255 : 0);
+                }
+            }
+        }
+        break;
+    }
+/*
+ * Write out data in URT order (bottom to top).
+ */
+    for ( scan = 0; scan < height; scan++ ) {
+        rle_putrow(scanlines[scan], width, &hdr);
+        rle_row_free( &hdr, scanlines[scan] );
+    }
+    free( scanlines );
+
+    VPRINTF(stderr, "Done -- write eof to RLE data.\n");
+    rle_puteof(&hdr);
+}
+
+int
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+    char     *pnmname = NULL, *outname = NULL;
+    static char  filename[BUFSIZ];
+    int      oflag, c;
+
+    pnm_init(&argc, argv);
+
+/*
+ * Get those options.
+ */
+    if (!scanargs(argc,argv,
+                  "% v%- h%- a%- o%-outfile!s pnmfile%s\n(\
+\tConvert a PNM file to URT RLE format.\n\
+\t-a\tFake an alpha channel.  Alpha=0 when input=0, 255 otherwise.\n\
+\t-h\tPrint header of PNM file and exit.\n\
+\t-v\tVerbose mode.)",
+                  &verbose,
+                  &header,
+                  &do_alpha,
+                  &oflag, &outname,
+                  &pnmname))
+        exit(-1);
+
+    hdr = *rle_hdr_init( (rle_hdr *)NULL );
+    rle_names( &hdr, cmd_name( argv ), outname, 0 );
+/*
+ * Open the file.
+ */
+    if (pnmname == NULL) {
+        strcpy(filename, "stdin");
+        fp = stdin;
+    }
+    else {
+        strcpy(filename, pnmname);
+        fp = pm_openr(filename);
+    }
+
+    hdr.rle_file = rle_open_f( hdr.cmd, outname, "wb" );
+    while ( (c = getc( fp )) != EOF ) {
+        ungetc( c, fp );
+/*
+ * Read the PPM file header.
+ */
+        read_pnm_header();
+        if (header)
+            break;
+/*
+ * Write the rle file header.
+ */
+        rle_addhist(argv, (rle_hdr *)NULL, &hdr);
+        write_rle_header();
+/*
+ * Write the rle file data.
+ */
+        write_rle_data();
+    }
+    fclose(fp);
+    return 0;
+}
diff --git a/converter/other/pnmtosgi.c b/converter/other/pnmtosgi.c
new file mode 100644
index 00000000..472b5197
--- /dev/null
+++ b/converter/other/pnmtosgi.c
@@ -0,0 +1,354 @@
+/* pnmtosgi.c - convert portable anymap to SGI image
+**
+** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
+**
+** Based on the SGI image description v0.9 by Paul Haeberli (paul@sgi.comp)
+** Available via ftp from sgi.com:graphics/SGIIMAGESPEC
+**
+** 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.
+**
+** 29Jan94: first version
+*/
+#include "pnm.h"
+#include "sgi.h"
+#include "mallocvar.h"
+
+/*#define DEBUG*/
+
+typedef short       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
+
+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);
+}
+
+
+
+int
+main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    FILE *ifp;
+    int argn;
+    const char * const usage = "[-verbatim|-rle] [-imagename <name>] [pnmfile]";
+    int cols, rows, format;
+    xelval maxval, newmaxval;
+    const char *imagename = "no name";
+    int bpc, dimensions, channels;
+    long *table = NULL;
+
+    pnm_init(&argc, argv);
+
+    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);
+    pnmrow = pnm_allocrow(cols);
+
+    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);
+
+    exit(0);
+}
+
+
+static void
+write_table(table, tabsize)
+    long *table;
+    int tabsize;
+{
+    int i;
+    long offset;
+
+#ifdef DEBUG
+    pm_message("writing table");
+#endif
+
+    offset = HeaderSize + tabsize * 8;
+    for( i = 0; i < tabsize; i++ ) {
+        put_big_long(offset);
+        offset += table[i];
+    }
+    for( i = 0; i < tabsize; i++ )
+        put_big_long(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++ ) {
+                (*put)(channel[i][row].data[col]);
+            }
+        }
+    }
+}
+
+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 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 ) {
+        MALLOCARRAY_NOFAIL(table, channels * rows);
+        MALLOCARRAY_NOFAIL(rletemp, WORSTCOMPR(cols));
+    }
+    MALLOCARRAY_NOFAIL(temp, cols);
+
+    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++ )
+                temp[col] = (ScanElem)PNM_GET1(pnmrow[col]);
+            temp = compress(temp, sgirow, rows, cols, 0, table, bpc);
+        }
+        else {
+            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++ )
+                temp[col] = (ScanElem)PPM_GETG(pnmrow[col]);
+            temp = compress(temp, sgirow, rows, cols, 1, table, bpc);
+            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);
+            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;
+            break;
+        default:
+            pm_error("unknown storage type - can\'t happen");
+    }
+    return temp;
+}
+
+
+/*
+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 ) {
+        if( (in<size-1) && (inbuf[in]==inbuf[in+1]) ) {     /*Begin replicate run*/
+            for( count=0,hold=in; in<size && inbuf[in]==inbuf[hold] && count<127; in++,count++)
+                ;
+            outbuf[out++]=(ScanElem)(count);
+            outbuf[out++]=inbuf[hold];
+        }
+        else {  /*Do a literal run*/
+            hold=out; out++; count=0;
+            while( ((in>=size-2)&&(in<size)) || ((in<size-2) && ((inbuf[in]!=inbuf[in+1])||(inbuf[in]!=inbuf[in+2]))) ) {
+                outbuf[out++]=inbuf[in++];
+                if( ++count>=127 )
+                    break;
+            }
+            outbuf[hold]=(ScanElem)(count | 0x80);
+        }
+    }
+    outbuf[out++] = (ScanElem)0;     /* terminator */
+    return(out);
+}
+
diff --git a/converter/other/pnmtosir.c b/converter/other/pnmtosir.c
new file mode 100644
index 00000000..c8dec5b6
--- /dev/null
+++ b/converter/other/pnmtosir.c
@@ -0,0 +1,146 @@
+/* pnmtosir.c - read a portable anymap and produce a Solitaire Image Recorder
+**		file (MGI TYPE 11 or MGI TYPE 17)
+**
+** Copyright (C) 1991 by Marvin Landis
+**
+** 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 "pnm.h"
+
+#define MAXCOLORS 256
+
+int main(int argc, char * argv[]) {
+    FILE* ifp;
+    xel** xels;
+    register xel* xP;
+    const char* dumpname;
+    int rows, cols, format, row, col;
+    int m, n;
+    int grayscale;
+    xelval maxval;
+    const char* const usage = "[pnmfile]";
+    unsigned char ub;
+    unsigned short Header[16];
+    unsigned short LutHeader[16];
+    unsigned short Lut[2048];
+
+    pnm_init( &argc, argv );
+
+    if ( argc > 2 )
+        pm_usage( usage );
+
+    if ( argc == 2 )
+	{
+        dumpname = argv[1];
+        ifp = pm_openr( argv[1] );
+	}
+    else
+	{
+        dumpname = "Standard Input";
+        ifp = stdin;
+	}
+    
+    xels = pnm_readpnm( ifp, &cols, &rows, &maxval, &format );
+    pm_close( ifp );
+    
+    /* Figure out the colormap. */
+    switch ( PNM_FORMAT_TYPE(format) )
+	{
+	case PPM_TYPE:
+        grayscale = 0;
+        pm_message( "Writing a 24-bit SIR format (MGI TYPE 11)" );
+        break;
+
+    case PGM_TYPE:
+        grayscale = 1;
+        pm_message( "Writing a grayscale SIR format (MGI TYPE 17)" );
+        break;
+
+	default:
+        grayscale = 1;
+        pm_message( "Writing a monochrome SIR format (MGI TYPE 17)" );
+        break;
+	}
+
+    /* Set up the header. */
+    Header[0] = 0x3a4f;
+    Header[1] = 0;
+    if (grayscale)
+        Header[2] = 17;
+    else
+        Header[2] = 11;
+    Header[3] = cols;
+    Header[4] = rows;
+    Header[5] = 0;
+    Header[6] = 1;
+    Header[7] = 6;
+    Header[8] = 0;
+    Header[9] = 0;
+    for (n = 0; n < 10; n++)
+        pm_writelittleshort(stdout,Header[n]);
+    for (n = 10; n < 256; n++)
+        pm_writelittleshort(stdout,0);
+
+    /* Create color map */
+    LutHeader[0] = 0x1524;
+    LutHeader[1] = 0;
+    LutHeader[2] = 5;
+    LutHeader[3] = 256;
+    LutHeader[4] = 256;
+    for (n = 0; n < 5; n++)
+        pm_writelittleshort(stdout,LutHeader[n]);
+    for (n = 5; n < 256; n++)
+        pm_writelittleshort(stdout,0);
+ 
+    for(n = 0; n < 3; n ++)
+        for (m = 0; m < 256; m++)
+            Lut[m * 4 + n] = m << 8;
+    for (n = 0; n < 1024; n++)
+        pm_writelittleshort(stdout,Lut[n]);
+ 
+    /* Finally, write out the data. */
+    switch ( PNM_FORMAT_TYPE(format) )
+    {
+	case PPM_TYPE:
+	    for ( row = 0; row < rows; ++row )
+            for ( col = 0, xP = xels[row]; col < cols; ++col, ++xP )
+            {
+                ub = (char) ( PPM_GETR( *xP ) * ( 255 / maxval ) ); 
+                fputc( ub, stdout );
+            }
+        for ( row = 0; row < rows; ++row )
+            for ( col = 0, xP = xels[row]; col < cols; ++col, ++xP )
+            {  
+                ub = (char) ( PPM_GETG( *xP ) * ( 255 / maxval ) );
+                fputc( ub, stdout );
+            }
+        for ( row = 0; row < rows; ++row )
+            for ( col = 0, xP = xels[row]; col < cols; ++col, ++xP )
+            {  
+                ub = (char) ( PPM_GETB( *xP ) * ( 255 / maxval ) );
+                fputc( ub, stdout );
+            }
+	    break;
+
+    default:
+        for ( row = 0; row < rows; ++row )
+            for ( col = 0, xP = xels[row]; col < cols; ++col, ++xP )
+            {
+                register unsigned long val;
+
+                val = PNM_GET1( *xP );
+                ub = (char) ( val * ( 255 / maxval ) );
+                fputc( ub, stdout );
+            }
+        break;
+    }
+
+    exit( 0 );
+}
+
diff --git a/converter/other/pnmtotiffcmyk.c b/converter/other/pnmtotiffcmyk.c
new file mode 100644
index 00000000..0fda6b08
--- /dev/null
+++ b/converter/other/pnmtotiffcmyk.c
@@ -0,0 +1,1000 @@
+/*
+
+CMYKTiff - pnmtotiffcmyk - conversion from a pnm file to a CMYK
+encoded tiff file.
+
+Copyright (C) 1999 Andrew Cooke  (Jara Software)
+
+Comments to jara@andrewcooke.free-online.co.uk
+
+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
+
+These conditions also apply to any other files distributed with the
+program that describe / document the CMYKTiff package.
+
+
+Much of the code uses ideas from other pnm programs, written by Jef
+Poskanzer (thanks go to him and libtiff maintainer Sam Leffler).  A
+small section of the code - some of the tiff tag settings - is derived
+directly from pnmtotiff, by Jef Poskanzer, which, in turn,
+acknowledges Patrick Naughton with the following text:
+
+** Derived by Jef Poskanzer from ras2tif.c, which is:
+**
+** Copyright (c) 1990 by Sun Microsystems, Inc.
+**
+** Author: Patrick J. Naughton
+** naughton@wind.sun.com
+**
+** 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 file is provided AS IS with no warranties of any kind.  The author
+** shall have no liability with respect to the infringement of copyrights,
+** trade secrets or any patents by this file or any part thereof.  In no
+** event will the author be liable for any lost revenue or profits or
+** other special, indirect and consequential damages.
+
+Software copyrights will soon need family trees... :-)
+
+*/
+
+#define _XOPEN_SOURCE
+
+#include <string.h>
+#include <math.h>
+/* float.h used to be included only if __osf__ was defined.  On some
+   platforms, float.h is also included automatically by math.h.  But at
+   least on Solaris, it isn't.  00.04.25.
+*/
+#include <float.h>
+#include <limits.h>
+#include <fcntl.h>
+/* See warning about tiffio.h in pamtotiff.c */
+#include <tiffio.h>
+
+#include "pm_c_util.h"
+#include "nstring.h"
+#include "pnm.h"
+
+/* first release after testing */
+/* second release after testing - small mods to netpbm package */
+#define VERSION 1.01
+
+/* only support 8 bit values */
+#define MAXTIFFBITS 8
+#define MAXTIFFVAL 255 
+
+
+/* definitions for error values */
+
+typedef int Err ;
+
+#define ERR_OK       0  /* no error */
+#define ERR_PNM      1  /* thrown by pnm library */
+#define ERR_MEMORY   2  /* could not allocate memory */
+#define ERR_ARG      3  /* unexpected argument */
+#define ERR_TIFF     4  /* failure in tiff library */
+#define ERR_HELP     5  /* terminate with -help */
+
+/* definitions for command line options */
+
+#define UNSET 2 /* Simple->remove value when gammap not set */
+#define K_NORMAL 0
+#define K_REMOVE 1
+#define K_ONLY 2
+
+
+/* definitions for conversion calculations */
+
+/* catch rounding errors to outside 0-1 range */
+#define LIMIT01(x) MAX( 0.0, MIN( 1.0, (x) ) )
+/* convert from 0-1 to 0-maxOut */
+#define TOMAX(x) MAX( 0, MIN( rt->maxOut, (int)(rt->maxOut * (x)) ) )
+#define TINY FLT_EPSILON
+#ifndef PI
+#define PI 3.1415926
+#endif
+#define ONETWENTY ( 2.0 * PI / 3.0 ) 
+#define TWOFORTY ( 4.0 * PI / 3.0 )
+#define THREESIXTY ( 2.0 * PI ) 
+/* expand from 0-90 to 0-120 degrees */
+#define EXPAND(x) ( 4.0 * ( x ) / 3.0 )
+/* contract from 0-120 to 0-90 degrees */
+#define CONTRACT(x) ( 3.0 * ( x ) / 4.0 )
+
+
+
+/* --- main structure for the process ----------------- */
+
+struct tagIn ;
+struct tagConv ;
+struct tagOut ;
+
+typedef struct {
+  struct tagIn *in ;
+  struct tagConv *conv ;
+  struct tagOut *out ;
+  int nCols ;
+  int nRows ;
+  int maxOut ;
+  const char *name ;
+} Root ;
+
+
+
+/* --- utils ------------------------------------------ */
+
+
+/* parse an arg with a float value.  name should be the full key name,
+   preceded by '-' */
+static Err 
+floatArg( float *arg, const char *name, int size, float lo, float hi,
+          int *argn, int argc, char **argv ) {
+
+  char extra ;
+  int count ;
+
+  if ( pm_keymatch( argv[*argn], name, size ) ) {
+    if ( ++(*argn) == argc ) {
+      fprintf( stderr, "no value for %s\n", name ) ;
+      return ERR_ARG ;
+    }
+    if ( ! (count = sscanf( argv[*argn], "%f%1c", arg, &extra )) ) {
+      fprintf( stderr, "cannot parse %s for %s\n", argv[*argn], name ) ;
+      return ERR_ARG ;
+    }
+    if ( count > 1 ) {
+      fprintf( stderr, "warning: ignored %c... in value for %s\n",
+               extra, name ) ;
+    }
+    if ( *arg > hi || *arg < lo ) {
+      fprintf( stderr, "%s (%f) must be in range %f to %f\n", 
+               name, *arg, lo, hi ) ;
+      return ERR_ARG ;
+    }
+    ++(*argn) ;
+  }
+
+  return ERR_OK ;
+}
+
+
+/* parse an arg with a long value.  name should be the full key name,
+   preceded by '-' */
+static Err 
+longArg( long *arg, const char *name, int size, long lo, long hi,
+         int *argn, int argc, char **argv ) {
+
+  char extra ;
+  int count ;
+
+  if ( pm_keymatch( argv[*argn], name, size ) ) {
+    if ( ++(*argn) == argc ) {
+      fprintf( stderr, "no value for %s\n", name ) ;
+      return ERR_ARG ;
+    }
+    if ( ! (count = sscanf( argv[*argn], "%ld%1c", arg, &extra )) ) {
+      fprintf( stderr, "cannot parse %s for %s\n", argv[*argn], name ) ;
+      return ERR_ARG ;
+    }
+    if ( count > 1 ) {
+      fprintf( stderr, "warning: ignored %c... in value for %s\n",
+               extra, name ) ;
+    }
+    if ( *arg > hi || *arg < lo ) {
+      fprintf( stderr, "%s (%ld) must be in range %ld to %ld\n", 
+               name, *arg, lo, hi ) ;
+      return ERR_ARG ;
+    }
+    ++(*argn) ;
+  }
+
+  return ERR_OK ;
+}
+
+
+/* print usage.  for simplicity this routine is *not* split amongst
+   the various components - when you add a component (eg a new
+   conversion algorithm, or maybe new input or output code), you must
+   also change this routine.  by keeping all the options in one place
+   it is also easier to calculate the minimum key name length (passed
+   to pnm_keymatch) */
+static void 
+printUsage( ) {
+  fprintf( stderr, "\nusage: pnmtocmyk [Compargs] [Tiffargs] [Convargs] [pnmfile]\n" ) ;
+  fprintf( stderr, " Compargs: [-none|-packbits|-lzw [-predictor 1|-predictor 2]]\n" ) ;
+  fprintf( stderr, " Tiffargs: [-msb2lsb|-lsb2msb] [-rowsperstrip n]\n" ) ;
+  fprintf( stderr, "           [-lowdotrange lo] [-highdotrange hi] [-knormal|-konly|-kremove]\n" ) ;
+  fprintf( stderr, " Convargs: [[-default] [Defargs]|-negative]\n" ) ;
+  fprintf( stderr, " Defargs:  [-theta deg] [-gamma g] [-gammap -1|-gammap g]\n" ) ;
+  fprintf( stderr, "where 0 <= lo < hi <= 255; -360 < deg < 360; 0.1 < g < 10; 0 < n < INT_MAX\n\n" ) ;
+  fprintf( stderr, "returns: 0 OK; 1 pnm library error ; 2 memory error ; 3 unexpected arg ;\n" ) ;
+  fprintf( stderr, "         4 tiff library error ; 5 -help key used\n\n" ) ;
+  fprintf( stderr, "Convert a pnm file to a CMYK tiff file.  Version %5.2f\n", VERSION ) ;
+  fprintf( stderr, "CMY under K will be removed unless -gammap -1 is used.\n" ) ;
+  fprintf( stderr, "(c) 1999 Andrew Cooke - Beta version, not for public use.\n" ) ;
+  fprintf( stderr, "No warranty.\n\n" ) ;
+}
+
+/* list of key args and number of significant letters required
+-default      2
+-gamma        6
+-gammap       7
+-highdotrange 2
+-knormal      3
+-konly        3
+-kremove      3
+-lowdotrange  3
+-lsb2msb      3
+-lzw          3
+-msb2lsb      2
+-negative     3
+-none         3
+-packbits     3
+-predictor    3
+-rowsperstrip 2
+-theta        2
+*/
+
+
+
+/* --- reading the input ------------------------------ */
+
+
+/* encapsulate the file reader - uses pnm library at the moment, but
+   could be changed if we move to libtiff */
+
+typedef Err OptIn( struct tagIn *conv, Root *r, 
+                   int *argn, int argc, char **argv ) ;
+typedef int HasMore( struct tagIn *in ) ;
+typedef Err Next( struct tagIn *in, float *r, float *g, float *b ) ;
+typedef Err OpenIn( struct tagIn *in, Root *r ) ; 
+typedef void CloseIn( struct tagIn *in ) ;
+
+typedef struct tagIn {
+  OptIn *opt ;
+  HasMore *hasMore ;
+  Next *next ;
+  OpenIn *open ;
+  CloseIn *close ;
+  void *private ;
+} In ;
+
+
+/* implementation for pnm files */
+
+typedef struct {
+  FILE *in ;
+  int type ;
+  xelval maxVal ;
+  int maxPix ;
+  int iPix ;
+  xel *row ;
+  int maxRow ;
+  int iRow ;
+} PnmIn ;
+
+
+/* the only output option is the filename, which will be the last
+   argument, if it doesn't start with '-' */
+static Err 
+pnmOpt( In *in, Root *r, int *argn, int argc, char **argv ) {
+  PnmIn *p = (PnmIn*)in->private ;
+  if ( *argn + 1 == argc && argv[*argn][0] != '\0' &&
+       argv[*argn][0] != '-' ) {
+    r->name = argv[(*argn)++] ;
+    p->in = pm_openr( r->name ) ;
+  }
+  return ERR_OK ;
+}
+
+
+/* free the row buffer when closing the input */
+static void 
+pnmClose( In *in ) {
+  if ( in ) {
+    PnmIn *p = (PnmIn*)in->private ;
+    if ( p ) {
+      if ( p->row ) pnm_freerow( p->row ) ;
+      if ( p->in ) pm_close( p->in ) ;
+      free( p ) ;
+    }
+  }
+}
+
+
+/* open the file, storing dimensions both locally and in the global
+   root structure */
+static Err 
+pnmOpen( In *in, Root *r ) {
+
+  PnmIn *p = (PnmIn*)in->private ;
+
+  if ( ! p->in ) p->in = stdin ;
+
+  pnm_readpnminit( p->in, &(r->nCols), &(r->nRows), &(p->maxVal), 
+                   &(p->type) ) ;
+  p->maxPix = r->nCols * r->nRows ;
+  p->iPix = 0 ;
+  p->maxRow = r->nCols ;
+  p->iRow = 0 ;
+  p->row = pnm_allocrow( p->maxRow ) ;
+
+  return ERR_OK ;
+}
+
+
+/* more data available? */
+static int 
+pnmHasMore( In *in ) {
+  PnmIn *p = (PnmIn*)in->private ;
+  return p->iPix < p->maxPix ;
+}
+
+
+/* read next pixel - buffered by row.  return values in range 0 to 1 */
+static Err 
+pnmNext( In *in, float *r, float *g, float *b ) {
+
+  PnmIn *p = (PnmIn*)in->private ;
+  float m = (float)p->maxVal ;
+
+  if ( p->iPix == 0 || p->iRow == p->maxRow ) {
+    p->iRow = 0 ;
+    pnm_readpnmrow( p->in, p->row, p->maxRow, p->maxVal, p->type ) ;
+  }
+  if ( PNM_FORMAT_TYPE( p->type ) == PPM_TYPE ) {
+    *r = (float)PPM_GETR( p->row[p->iRow] ) / m ;
+    *g = (float)PPM_GETG( p->row[p->iRow] ) / m ;
+    *b = (float)PPM_GETB( p->row[p->iRow] ) / m ;
+  } else {
+    *r = *g = *b = (float)PNM_GET1( p->row[p->iRow] ) / m ;
+  }
+  ++(p->iRow) ;
+  ++(p->iPix) ;
+
+  return ERR_OK ;
+}
+
+
+/* build the input struct */
+static Err 
+newPnmInput( In **in ) {
+  if ( ! (*in = (In*)calloc( 1, sizeof( In ) )) ) {
+    fprintf( stderr, "cannot allocate memory\n" ) ;
+    return ERR_MEMORY ;
+  }
+  (*in)->private = calloc( 1, sizeof( PnmIn ) ) ;
+  (*in)->opt = pnmOpt ;
+  (*in)->open = pnmOpen ;
+  (*in)->hasMore = pnmHasMore ;
+  (*in)->next = pnmNext ;
+  (*in)->close = pnmClose ;
+  return ERR_OK ;
+}
+
+
+
+/* --- writing the output ----------------------------- */
+
+
+/* encapsulate file writing (will probably always use libtiff, but may
+   as well be consistent) */
+
+typedef Err OptOut( struct tagOut *conv, Root *r,
+                    int *argn, int argc, char **argv ) ;
+typedef Err Write( struct tagOut *out, int c, int m, int y, int k ) ;
+typedef Err OpenOut( struct tagOut *out, Root *r ) ;
+typedef void CloseOut( struct tagOut *out ) ;
+
+typedef struct tagOut {
+  OptOut *opt ;
+  Write *write ;
+  OpenOut *open ;
+  CloseOut *close ;
+  void *private ;
+} Out ;
+
+
+/* implementation for tiff files */
+
+typedef struct {
+  tdata_t buffer ;
+  tsize_t maxBuffer ;
+  tsize_t iBuffer ;
+  uint32 iRow ;
+  TIFF *tiff ;
+  uint32 rowsperstrip ;
+  uint16 compression ;
+  uint16 fillorder ;
+  uint16 predictor ;
+  uint16 lowdotrange ;
+  uint16 highdotrange ;
+  int kFlag ;
+} TiffOut ;
+
+
+/* these options come from either the tiff 6.0 spec or the pnmtotiff
+   code */
+static Err 
+tiffOpt( Out *out, Root* rt, int *argn, int argc, char **argv ) {
+
+  Err err ;
+  int oldn ;
+  long lVal ;
+  TiffOut *t = (TiffOut*)out->private ;
+
+  if ( pm_keymatch( argv[*argn], "-none", 3 ) ) {
+    t->compression = COMPRESSION_NONE ;
+    ++(*argn) ;
+  } else if ( pm_keymatch( argv[*argn], "-packbits", 3 ) ) {
+    t->compression = COMPRESSION_PACKBITS ;
+    ++(*argn) ;
+  } else if ( pm_keymatch( argv[*argn], "-lzw", 3 ) ) {
+    t->compression = COMPRESSION_LZW ;
+    ++(*argn) ;
+  } else if ( pm_keymatch( argv[*argn], "-msb2lsb", 2 ) ) {
+    t->fillorder = FILLORDER_MSB2LSB ;
+    ++(*argn) ;
+  } else if ( pm_keymatch( argv[*argn], "-lsb2msb", 3 ) ) {
+    t->fillorder = FILLORDER_LSB2MSB ;
+    ++(*argn) ;
+  } else if ( pm_keymatch( argv[*argn], "-knormal", 3 ) ) {
+    t->kFlag = K_NORMAL ;
+    ++(*argn) ;
+  } else if ( pm_keymatch( argv[*argn], "-kremove", 3 ) ) {
+    t->kFlag = K_REMOVE ;
+    ++(*argn) ;
+  } else if ( pm_keymatch( argv[*argn], "-konly", 3 ) ) {
+    t->kFlag = K_ONLY ;
+    ++(*argn) ;
+  } else {
+    oldn = *argn ;
+    if ( (err = longArg( &lVal, "-predictor", 3, 1, 2,
+                         argn, argc, argv )) ) return err ;
+    if ( oldn != *argn ) {
+      t->predictor = (uint16)lVal ;
+    } else {
+      if ( (err = longArg( &lVal, "-rowsperstrip", 2, 1, INT_MAX,
+                           argn, argc, argv )) ) return err ;
+    }
+    if ( oldn != *argn ) {
+      t->rowsperstrip = (uint32)lVal ;
+    } else {
+      if ( (err = longArg( &lVal, "-lowdotrange", 3, 0, 
+                           (int)(t->highdotrange - 1),
+                           argn, argc, argv )) ) return err ;
+    }
+    if ( oldn != *argn ) {
+      t->lowdotrange = (uint16)lVal ;
+    } else {
+      if ( (err = longArg( &lVal, "-highdotrange", 2, 
+                           (int)(t->lowdotrange + 1), MAXTIFFVAL,
+                           argn, argc, argv )) ) return err ;
+    }
+    if ( oldn != *argn ) {
+      t->highdotrange = (uint16)lVal ;
+    }
+  }
+
+  return ERR_OK ;
+}
+
+
+/* helper routine - writes individual bytes */
+static Err 
+tiffWriteByte( TiffOut *t, int b ) {
+  ((unsigned char*)(t->buffer))[t->iBuffer] = (unsigned char)b ;
+  if ( ++(t->iBuffer) == t->maxBuffer ) {
+    if ( TIFFWriteScanline( t->tiff, t->buffer, t->iRow, 0 ) == -1 ) {
+      return ERR_TIFF ;
+    }
+    ++(t->iRow) ;
+    t->iBuffer = 0 ;
+  }
+  return ERR_OK ;
+}
+
+
+/* write the pixel to the tiff file */
+static Err 
+tiffWrite( Out *out, int c, int m, int y, int k ) {
+  Err err ;
+  TiffOut *t = (TiffOut*)out->private ;
+  if ( t->kFlag == K_ONLY ) {
+    c = m = y = k ;
+  } else if ( t->kFlag == K_REMOVE ) {
+    k = 0 ;
+  }
+  if ( (err = tiffWriteByte( t, c )) ) return err ;
+  if ( (err = tiffWriteByte( t, m )) ) return err ;
+  if ( (err = tiffWriteByte( t, y )) ) return err ;
+  if ( (err = tiffWriteByte( t, k )) ) return err ;
+  return ERR_OK ;
+}
+
+
+/* open output to stdout - see warning below */
+static Err 
+tiffOpen( Out* out, Root *r ) {
+
+  TiffOut *t = (TiffOut*)out->private ;
+
+  short samplesperpixel = 4 ; /* cmyk has four values */
+  uint16 bitspersample = MAXTIFFBITS ;
+  short photometric = PHOTOMETRIC_SEPARATED ; /* ie cmyk */
+  int bytesperrow = r->nCols ;
+
+  /* if i don't set stdout non-blocking on my machine then the read
+     that is called inside TIFFFdOpen hangs until the users types ^D.
+     this is also true for pnmtotiff */
+  fcntl( 1, F_SETFL, O_NONBLOCK ) ;
+  t->tiff = TIFFFdOpen( 1, "Standard Output", "w" ) ;
+  if ( ! t->tiff ) {
+    fprintf( stderr, "cannot open tiff stream to standard output\n" ) ;
+    return ERR_TIFF ;
+  }
+
+  /* from pnmtotiff - default is to have 8kb strips */
+  if ( ! t->rowsperstrip ) {
+    t->rowsperstrip = ( 8 * 1024 ) / bytesperrow ;
+  }
+
+  TIFFSetField( t->tiff, TIFFTAG_DOTRANGE, t->lowdotrange, t->highdotrange ) ;
+  TIFFSetField( t->tiff, TIFFTAG_IMAGEWIDTH, (uint32)r->nCols ) ;
+  TIFFSetField( t->tiff, TIFFTAG_IMAGELENGTH, (uint32)r->nRows ) ;
+  TIFFSetField( t->tiff, TIFFTAG_BITSPERSAMPLE, bitspersample ) ;
+  TIFFSetField( t->tiff, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT ) ;
+  TIFFSetField( t->tiff, TIFFTAG_COMPRESSION, t->compression ) ;
+  if ( t->compression == COMPRESSION_LZW && t->predictor ) {
+	TIFFSetField( t->tiff, TIFFTAG_PREDICTOR, t->predictor ) ;
+  }
+  TIFFSetField( t->tiff, TIFFTAG_PHOTOMETRIC, photometric ) ;
+  TIFFSetField( t->tiff, TIFFTAG_FILLORDER, t->fillorder ) ;
+  TIFFSetField( t->tiff, TIFFTAG_DOCUMENTNAME, r->name ) ;
+  TIFFSetField( t->tiff, TIFFTAG_IMAGEDESCRIPTION, "PNM -> CMYK tiff" ) ;
+  TIFFSetField( t->tiff, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel ) ;
+  TIFFSetField( t->tiff, TIFFTAG_ROWSPERSTRIP, t->rowsperstrip ) ;
+  TIFFSetField( t->tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ) ;
+
+  t->maxBuffer = TIFFScanlineSize( t->tiff ) ;
+  t->buffer = _TIFFmalloc( t->maxBuffer ) ;
+  t->iBuffer = 0 ;
+  t->iRow = 0 ;
+  if ( ! t->buffer ) {
+    fprintf( stderr, "cannot allocate memory\n" ) ;
+    return ERR_MEMORY ;
+  }
+  
+  return ERR_OK ;
+}
+
+
+/* close file and tidy memory */
+static void 
+tiffClose( Out *out ) {
+  if ( out ) {
+    TiffOut *t = (TiffOut*)out->private ;
+    if ( t ) {
+      if ( t->buffer ) _TIFFfree( t->buffer ) ;
+      if ( t->tiff ) TIFFClose( t->tiff ) ;
+      free( t ) ;
+    }
+    free( out ) ;
+  }
+}
+
+
+/* assemble the routines above into a single struct/object */
+static Err 
+newTiffOutput( Out **out ) {
+
+  TiffOut *t ;
+
+  if ( ! (*out = (Out*)calloc( 1, sizeof( Out ) )) ) goto error ;
+  if ( ! (t = (TiffOut*)calloc( 1, sizeof( TiffOut ) )) ) goto error ;
+  t->compression = COMPRESSION_LZW ;
+  t->fillorder = FILLORDER_MSB2LSB ;
+  t->predictor = 0 ;
+  t->rowsperstrip = 0 ;
+  t->lowdotrange = 0 ;
+  t->highdotrange = MAXTIFFVAL ;
+  t->kFlag = K_NORMAL ;
+  (*out)->private = t ;
+  (*out)->opt = tiffOpt ;
+  (*out)->open = tiffOpen ;
+  (*out)->write = tiffWrite ;
+  (*out)->close = tiffClose ;
+  return ERR_OK ;
+
+ error:
+  fprintf( stderr, "cannot allocate memory\n" ) ;
+  return ERR_MEMORY ;
+}
+
+
+
+/* --- conversion ------------------------------------- */
+
+
+/* encapsulate conversion - allow easy extension with other conversion
+   algorithms.  if selection of conversion routine is by command line
+   flag then that flag must precede conversion parameters (for
+   simplicity in argument parsing) */
+
+typedef Err Opt( struct tagConv *conv, Root *r,
+                 int *argn, int argc, char **argv ) ;
+typedef Err Convert( struct tagConv *conv, Root *rt,
+                     float r, float g, float b, 
+                     int *c, int *m, int *y, int *k ) ;
+typedef void Close( struct tagConv *conv ) ;
+
+typedef struct tagConv {
+  Opt *opt ;
+  Convert *convert ;
+  Close *close ;
+  void *private ;
+} Conv ;
+
+
+/* include two conversion routines to show how the code can be
+   extended.  first, the standard converter, as outlined in the
+   proposal, then a simple replacement that produces colour 
+   negatives */
+
+
+/* implementation with hue rotation, black gamma correction and
+   removal of cmy under k */
+
+typedef struct {
+  int initialized ;
+  float theta ;
+  float gamma ;
+  float gammap ;
+  int remove ;
+} Standard ;
+
+
+/* represent an rgb colour as a hue (angle), white level and colour
+   strength */
+static void 
+rgbToHueWhiteColour( float r, float g, float b, 
+                     double *phi, float *white, float *colour ) {
+  *white = MIN( r, MIN( g, b ) ) ;
+  r -= *white ;
+  g -= *white ;
+  b -= *white ;
+  *colour = sqrt( r * r + g * g + b * b ) ;
+  if ( r > TINY || g > TINY || b > TINY ) {
+    if ( b < r && b <= g ) { 
+      *phi = EXPAND( atan2( g, r ) ) ;
+    } else if ( r < g && r <= b ) {
+      *phi = ONETWENTY + EXPAND( atan2( b, g ) ) ;
+    } else {
+      *phi = TWOFORTY + EXPAND( atan2( r, b ) ) ;
+    }
+  } 
+}
+
+
+/* represent hue, white and colour values as rgb */
+static void 
+hueWhiteColourToRgb( double phi, float white, float colour,
+                     float *r, float *g, float *b ) {
+  while ( phi < 0 ) { phi += THREESIXTY ; }
+  while ( phi > THREESIXTY ) { phi -= THREESIXTY ; }
+  if ( phi < ONETWENTY ) {
+    phi = CONTRACT( phi ) ;
+    *r = colour * cos( phi ) ;
+    *g = colour * sin( phi ) ;
+    *b = 0.0 ;
+  } else if ( phi < TWOFORTY ) {
+    phi = CONTRACT( phi - ONETWENTY ) ;
+    *r = 0.0 ;
+    *g = colour * cos( phi ) ;
+    *b = colour * sin( phi ) ;
+  } else {
+    phi = CONTRACT( phi - TWOFORTY ) ;
+    *r = colour * sin( phi ) ;
+    *g = 0.0 ;
+    *b = colour * cos( phi ) ;
+  }
+  *r += white ;
+  *g += white ;
+  *b += white ;
+}
+
+
+/* for details, see the proposal.  it's pretty simple - a rotation
+   before conversion, with colour removal */
+static Err 
+standardConvert( Conv *conv, Root *rt, float r, float g, float b, 
+                 int *c, int *m, int *y, int *k ) {
+
+  float c0, m0, y0, k0 ; /* CMYK before colour removal */
+  float gray, white, colour ;
+  double phi ;
+
+  Standard *s ; /* private conversion data */
+
+  s = (Standard*)(conv->private) ;
+
+  if ( ! s->initialized ) {
+    s->theta *= 2.0 * PI / 360.0 ; /* to radians */
+    /* if gammap never specified in options, set to gamma now */
+    if ( s->remove == UNSET ) {
+      s->remove = 1 ;
+      s->gammap = s->gamma ;
+    }
+    s->initialized = 1 ;
+  }
+
+  /* rotate in rgb */
+  if ( fabs( s->theta ) > TINY ) {
+    rgbToHueWhiteColour( r, g, b, &phi, &white, &colour ) ;
+    hueWhiteColourToRgb( phi + s->theta, white, colour, &r, &g, &b ) ;
+  }
+
+  c0 = LIMIT01( 1.0 - r ) ;
+  m0 = LIMIT01( 1.0 - g ) ;
+  y0 = LIMIT01( 1.0 - b ) ;
+  k0 = MIN( c0, MIN( y0, m0 ) ) ;
+
+  /* apply gamma corrections to modify black levels */
+  *k = TOMAX( pow( k0, s->gamma ) ) ;
+
+  /* remove colour under black and convert to integer range 0 - rt->maxOut */
+  if ( s->remove ) {
+    gray = pow( k0, s->gammap ) ;
+  } else {
+    gray = 0.0 ;
+  }
+  *c = TOMAX( c0 - gray ) ;
+  *m = TOMAX( m0 - gray ) ;
+  *y = TOMAX( y0 - gray ) ;
+
+  return ERR_OK ;
+}
+
+
+/* parse options for this conversion - note the ugly use of -1 for
+   gammap to indicate no removal of cmy under k */
+static Err 
+standardOpt( Conv *conv, Root *r, int *argn, int argc, char **argv ) {
+
+  Err err ;
+  int oldn ;
+  Standard *p = (Standard*)conv->private ;
+
+  oldn = *argn ;
+  if ( (err = floatArg( &(p->theta), "-theta", 2, -360.0, 360.0,
+                        argn, argc, argv )) ) return err ;
+  if ( oldn == *argn ) {
+    if ( (err = floatArg( &(p->gamma), "-gamma", 6, 0.1, 10.0,
+                          argn, argc, argv )) ) return err ;
+    /* gammap traces gamma unless set separately */
+    if ( oldn != *argn && p->remove == UNSET ) p->gammap = p->gamma ;
+  }
+  /* handle the special case of -1 (no removal) */
+  if ( oldn == *argn && pm_keymatch( argv[*argn], "-gammap", 7 ) &&
+       *argn + 1 < argc && STREQ(argv[*argn + 1], "-1") ) {
+    p->remove = 0 ;
+    *argn = (*argn) + 2 ;
+  } 
+  if ( oldn == *argn ) {
+    if ( (err = floatArg( &(p->gammap), "-gammap", 7, 0.1, 10.0,
+                               argn, argc, argv )) ) return err ;
+    if ( oldn != *argn ) p->remove = 1 ;
+  }
+
+  return ERR_OK ;
+}
+
+
+/* free conversion structure */
+static void 
+standardClose( Conv *conv ) {
+  if ( conv ) {
+    if ( conv->private ) { free( conv->private ) ; }
+    free( conv ) ; 
+  }
+}
+
+
+/* build new conversion structure */
+static Err 
+newStandardMap( Conv **conv ) {
+
+  Standard *s ;
+
+  if ( ! (*conv = (Conv*)calloc( 1, sizeof( Conv ) )) ) goto error ;
+  if ( ! (s = (Standard*)calloc( 1, sizeof( Standard ) )) ) goto error ;
+  s->initialized = 0 ;
+  s->remove = UNSET ; /* gammap unset */
+  s->gamma = 1.0 ;
+  (*conv)->private = s ;
+  (*conv)->opt = standardOpt ;
+  (*conv)->convert = standardConvert ;
+  (*conv)->close = standardClose ;
+
+  return ERR_OK ;
+
+ error:
+  fprintf( stderr, "cannot allocate memory\n" ) ;
+  return ERR_MEMORY ;
+}
+
+
+
+/* next a simple demonstration of how to implement other conversion
+   algorithms - in this case, something that produces a "colour
+   negative" (just to be different) */
+
+
+/* the conversion routine must match the Convert typedef */
+static Err 
+negativeConvert( Conv *conv, Root *rt, float r, float g, float b,
+                 int *c, int *m, int *y, int *k ) {
+
+  /* the simple conversion is c=1-r, but for negatives we will use
+     c=r, so only need to convert from rgb 0-1 floats to cmyk
+     0-MAXTIFFVAL ints */
+  *c = TOMAX( r ) ;
+  *m = TOMAX( g ) ;
+  *y = TOMAX( b ) ;
+  *k = MIN( *c, MIN( *m, *y ) ) ;
+
+  return ERR_OK ;
+}
+
+
+/* since this simple conversion takes no parameters, we don't need to
+   parse them - this routine must match the Opt typedef */
+static Err 
+negativeOpt( Conv *conv, Root *r, int *argn, int argc, char **argv ) {
+  return ERR_OK ;
+}
+
+
+/* with no parameters we haven't needed the private data structure, so
+   closing is trivial - this routine must match the Close typedef */
+static void 
+negativeClose( Conv *conv ) { }
+
+
+/* and that's it, apart from assembling the routines above into a
+   single struct/object (and adding code in parseOpts to select the
+   algorithm and printUsage to help the user) */
+static Err 
+newNegativeMap( Conv **conv ) {
+
+  if ( ! (*conv = (Conv*)calloc( 1, sizeof( Conv ) )) ) goto error ;
+  (*conv)->opt = negativeOpt ;
+  (*conv)->convert = negativeConvert ;
+  (*conv)->close = negativeClose ;
+
+  return ERR_OK ;
+
+ error:
+  fprintf( stderr, "cannot allocate memory\n" ) ;
+  return ERR_MEMORY ;
+}
+
+
+
+/* --- general routines ------------------------------- */
+
+
+/* run through args, passing to sub components */
+static Err 
+parseOpts( int argc, char **argv, Root *r ) {
+
+  int argn = 1 ;
+  int oldn ;
+  Err err ;
+
+  /* set default reader, writer and converter */
+  if ( (err = newPnmInput( &(r->in) )) ) return err ;
+  if ( (err = newTiffOutput( &(r->out) )) ) return err ;
+  if ( (err = newStandardMap( &(r->conv) )) ) return err ;
+
+  /* minimum number of chars from inspection - this is standard netpbm
+     approach - so must check when adding more options */
+  while ( argn < argc ) {
+
+    /* first, high-level options that select components - currently
+       just the default or negative converter */
+    if ( pm_keymatch( argv[argn], "-default", 2 ) ) {
+      if ( r->conv ) { r->conv->close( r->conv ) ; }
+      if ( (err = newStandardMap( &(r->conv) )) ) return err ;
+      ++argn ;
+    } else if ( pm_keymatch( argv[argn], "-negative", 3 ) ) {
+      if ( r->conv ) { r->conv->close( r->conv ) ; }
+      if ( (err = newNegativeMap( &(r->conv) )) ) return err ;
+      ++argn ;
+    } else if ( pm_keymatch( argv[argn], "-help", 2 ) ) {
+      printUsage( ) ;
+      return ERR_HELP ;
+    } else {
+      /* next, try passing the option to each subcomponent */
+      oldn = argn ;
+      if ( (err = r->in->opt( r->in, r, &argn, argc, argv )) ) {
+        return err ;
+      } else if ( oldn == argn &&
+                  (err = r->out->opt( r->out, r, &argn, argc, argv )) ) {
+        return err ;
+      } else if ( oldn == argn &&
+                  (err = r->conv->opt( r->conv, r, &argn, argc, argv )) ) {
+        return err ;
+      } else if ( oldn == argn ) {
+        fprintf( stderr, "unexpected arg: %s\n", argv[argn] ) ;
+        return ERR_ARG ;
+      }
+    }
+  }
+
+  return ERR_OK ;
+}
+
+
+/* drive the reading, conversion, and writing */
+int main( int argc, char **argv ) {
+
+  Root *rt ;
+  float r, g, b ;
+  int c, m, y, k ;
+  Err err = ERR_OK ;
+
+  pnm_init(&argc, argv);
+
+  if ( ! (rt = (Root*)calloc( 1, sizeof( Root ) )) ) {
+    err = ERR_MEMORY ;
+    fprintf( stderr, "cannot allocate memory\n" ) ;
+    goto exit ;
+  }
+  rt->name = "Standard input" ;
+  rt->maxOut = MAXTIFFVAL ;
+
+  if ( (err = parseOpts( argc, argv, rt )) ) goto exit ;
+  
+  if ( (err = rt->in->open( rt->in, rt )) ) goto exit ;
+  if ( (err = rt->out->open( rt->out, rt )) ) goto exit ;
+
+  while ( rt->in->hasMore( rt->in ) ) {
+    if ( (err = rt->in->next( rt->in, &r, &g, &b )) ) goto exit ;
+    if ( (err = rt->conv->convert( rt->conv, rt, r, g, b, &c, &m, &y, &k )) )
+      goto exit ;
+    if ( (err = rt->out->write( rt->out, c, m, y, k )) ) goto exit ;
+  }
+
+ exit:
+
+  if ( rt && rt->out && rt->out->close ) rt->out->close( rt->out ) ;
+  if ( rt && rt->conv && rt->conv->close ) rt->conv->close( rt->conv ) ;
+  if ( rt && rt->in && rt->in->close ) rt->in->close( rt->in ) ;
+  if ( rt ) free( rt ) ;
+
+  if ( err == ERR_ARG ) printUsage( ) ;
+
+  return err ;
+}
+
+
+
diff --git a/converter/other/pnmtoxwd.c b/converter/other/pnmtoxwd.c
new file mode 100644
index 00000000..32fb8a7b
--- /dev/null
+++ b/converter/other/pnmtoxwd.c
@@ -0,0 +1,505 @@
+/* pnmtoxwd.c - read a portable anymap and produce a color X11 window dump
+**
+** Copyright (C) 1989, 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.
+*/
+
+#include <string.h>
+#include "pnm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "x11wd.h"
+
+
+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 */
+    unsigned int pseudodepth;
+    unsigned int directcolor;
+};
+
+
+
+static void 
+parseCommandLine(int argc, 
+                 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 optParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    unsigned int depthSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+  
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "directcolor", OPT_FLAG,    NULL,   &cmdlineP->directcolor,  0);
+    OPTENT3(0, "pseudodepth",    OPT_UINT,  &cmdlineP->pseudodepth,    
+            &depthSpec,          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 );
+    /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (!depthSpec)
+        cmdlineP->pseudodepth = 8;
+    else {
+        if (cmdlineP->pseudodepth < 1)
+            pm_error("-pseudodepth option value must be at least 1.  "
+                     "You specified %u", cmdlineP->pseudodepth);
+        else if (cmdlineP->pseudodepth > 16)
+            pm_error("-pseudodepth option value must be at most 16.  "
+                     "You specified %u", cmdlineP->pseudodepth);
+    }
+
+    if (argc-1 == 0) 
+        cmdlineP->inputFilespec = "-";
+    else if (argc-1 != 1)
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
+    else
+        cmdlineP->inputFilespec = argv[1];
+}
+
+
+
+static void
+setupX11Header(X11WDFileHeader * const h11P,
+               const char * const dumpname,
+               unsigned int const cols,
+               unsigned int const rows,
+               int          const format,
+               bool         const direct,
+               bool         const grayscale,
+               unsigned int const colors,
+               unsigned int const pseudodepth) {
+
+    /* Set up the header. */
+
+    h11P->header_size = sizeof(*h11P) + (xwdval) strlen(dumpname) + 1;
+    h11P->file_version = X11WD_FILE_VERSION;
+    h11P->pixmap_format = ZPixmap;
+    h11P->pixmap_width = cols;
+    h11P->pixmap_height = rows;
+    h11P->xoffset = 0;
+    h11P->byte_order = MSBFirst;
+    h11P->bitmap_bit_order = MSBFirst;
+    h11P->window_width = cols;
+    h11P->window_height = rows;
+    h11P->window_x = 0;
+    h11P->window_y = 0;
+    h11P->window_bdrwidth = 0;
+
+    if (direct) {
+        h11P->pixmap_depth = 24;
+        h11P->bitmap_unit = 32;
+        h11P->bitmap_pad = 32;
+        h11P->bits_per_pixel = 32;
+        h11P->visual_class = DirectColor;
+        h11P->colormap_entries = 256;
+        h11P->ncolors = 256;
+        h11P->red_mask = 0xff0000;
+        h11P->green_mask = 0xff00;
+        h11P->blue_mask = 0xff;
+        h11P->bytes_per_line = cols * 4;
+    } else {  /* pseudocolor -- i.e. regular paletted raster */
+        if (grayscale) {
+            if (PNM_FORMAT_TYPE(format) == PBM_TYPE) {
+                h11P->pixmap_depth = 1;
+                h11P->bits_per_pixel = 1;
+                h11P->colormap_entries = colors;
+                h11P->bytes_per_line = (cols + 7) / 8;
+            } else {
+                h11P->pixmap_depth = pseudodepth;
+                h11P->bits_per_pixel = pseudodepth;
+                h11P->colormap_entries = colors;
+                h11P->bytes_per_line = cols;
+            }
+            h11P->bitmap_unit = 8;
+            h11P->bitmap_pad = 8;
+            h11P->visual_class = StaticGray;
+            h11P->red_mask = 0;
+            h11P->green_mask = 0;
+            h11P->blue_mask = 0;
+        } else {
+            h11P->pixmap_depth = pseudodepth;
+            h11P->bits_per_pixel = pseudodepth;
+            h11P->visual_class = PseudoColor;
+            h11P->colormap_entries = 1 << pseudodepth;
+            h11P->red_mask = 0;
+            h11P->green_mask = 0;
+            h11P->blue_mask = 0;
+            h11P->bytes_per_line = cols;
+            h11P->bitmap_unit = 8;
+            h11P->bitmap_pad = 8;
+        }
+        h11P->ncolors = colors;
+    }
+    h11P->bits_per_rgb = h11P->pixmap_depth;
+}
+
+
+
+
+static void
+writeX11Header(X11WDFileHeader const h11,
+               FILE *          const ofP) {
+
+    /* Write out the header in big-endian order. */
+
+    pm_writebiglong(ofP, h11.header_size);
+    pm_writebiglong(ofP, h11.file_version);
+    pm_writebiglong(ofP, h11.pixmap_format);
+    pm_writebiglong(ofP, h11.pixmap_depth);
+    pm_writebiglong(ofP, h11.pixmap_width);
+    pm_writebiglong(ofP, h11.pixmap_height);
+    pm_writebiglong(ofP, h11.xoffset);
+    pm_writebiglong(ofP, h11.byte_order);
+    pm_writebiglong(ofP, h11.bitmap_unit);
+    pm_writebiglong(ofP, h11.bitmap_bit_order);
+    pm_writebiglong(ofP, h11.bitmap_pad);
+    pm_writebiglong(ofP, h11.bits_per_pixel);
+    pm_writebiglong(ofP, h11.bytes_per_line);
+    pm_writebiglong(ofP, h11.visual_class);
+    pm_writebiglong(ofP, h11.red_mask);
+    pm_writebiglong(ofP, h11.green_mask);
+    pm_writebiglong(ofP, h11.blue_mask);
+    pm_writebiglong(ofP, h11.bits_per_rgb);
+    pm_writebiglong(ofP, h11.colormap_entries);
+    pm_writebiglong(ofP, h11.ncolors);
+    pm_writebiglong(ofP, h11.window_width);
+    pm_writebiglong(ofP, h11.window_height);
+    pm_writebiglong(ofP, h11.window_x);
+    pm_writebiglong(ofP, h11.window_y);
+    pm_writebiglong(ofP, h11.window_bdrwidth);
+}
+
+
+
+static void
+writePseudoColormap(FILE *           const ofP,
+                    colorhist_vector const chv,
+                    unsigned int     const colors,
+                    bool             const grayscale,
+                    bool             const backwardMap,
+                    xelval           const maxval) {
+    /* Write out the colormap, big-endian order. */
+    
+    X11XColor color;
+    unsigned int i;
+
+    color.flags = 7;
+    color.pad = 0;
+    for (i = 0; i < colors; ++i) {
+        color.num = i;
+        if (grayscale) {
+            /* Stupid hack because xloadimage and xwud disagree on
+               how to interpret bitmaps. 
+            */
+            if (backwardMap)
+                color.red = (long) (colors-1-i) * 65535L / (colors - 1);
+            else
+                color.red = (long) i * 65535L / (colors - 1);
+            
+            color.green = color.red;
+            color.blue = color.red;
+        } else {
+            color.red = PPM_GETR(chv[i].color);
+            color.green = PPM_GETG(chv[i].color);
+            color.blue = PPM_GETB(chv[i].color);
+            if (maxval != 65535L) {
+                color.red = (long) color.red * 65535L / maxval;
+                color.green = (long) color.green * 65535L / maxval;
+                color.blue = (long) color.blue * 65535L / maxval;
+            }
+        }
+        pm_writebiglong( ofP, color.num);
+        pm_writebigshort(ofP, color.red);
+        pm_writebigshort(ofP, color.green);
+        pm_writebigshort(ofP, color.blue);
+        putc(color.flags, ofP);
+        putc(color.pad,   ofP);
+    }
+}
+
+
+
+static void
+writeDirectColormap(FILE * const ofP) {
+/*----------------------------------------------------------------------------
+   Write the XWD colormap.
+
+   We use a constant (independent of input) color map which simply has
+   each of the values 0-255, scaled to 16 bits, for each of the three
+   maps
+-----------------------------------------------------------------------------*/
+    X11XColor color;
+    unsigned int i;
+
+    color.flags = 7;
+    color.pad = 0;
+
+    for (i = 0; i < 256; ++i) {
+        color.red   = (short)(i << 8 | i);
+        color.green = (short)(i << 8 | i);
+        color.blue  = (short)(i << 8 | i);
+        color.num   = i << 16 | i << 8 | i;
+        
+        pm_writebiglong( ofP, color.num);
+        pm_writebigshort(ofP, color.red);
+        pm_writebigshort(ofP, color.green);
+        pm_writebigshort(ofP, color.blue);
+        putc(color.flags, ofP);
+        putc(color.pad,   ofP);
+    }
+}
+
+
+
+static void
+writeRowDirect(FILE *       const ofP,
+               xel *        const xelrow,
+               unsigned int const cols,
+               int          const format,
+               long         const xmaxval,
+               xelval       const maxval) {
+    
+    switch (PNM_FORMAT_TYPE(format)) {
+    case PPM_TYPE: {
+        unsigned int col;
+        for (col = 0; col < cols; ++col) {
+            unsigned long const ul = 
+                ((PPM_GETR(xelrow[col]) * xmaxval / maxval) << 16) |
+                ((PPM_GETG(xelrow[col]) * xmaxval / maxval) << 8) |
+                (PPM_GETB(xelrow[col]) * xmaxval / maxval);
+            pm_writebiglong(ofP, ul);
+        }
+    }
+    break;
+
+    default: {
+        unsigned int col;
+        for (col = 0; col < cols; ++col) {
+            unsigned long const val = PNM_GET1(xelrow[col]);
+            unsigned long const ul =
+                ((val * xmaxval / maxval) << 16) |
+                ((val * xmaxval / maxval) << 8) |
+                (val * xmaxval / maxval);
+            pm_writebiglong(ofP, ul);
+        }
+        break;
+    }
+    }
+}
+
+
+
+static void
+writeRowGrayscale(FILE *       const ofP,
+                  xel *        const xelrow,
+                  unsigned int const cols,
+                  xelval       const maxval,
+                  bool         const backwardMap,
+                  unsigned int const bitsPerPixel) {
+
+    xelval bigger_maxval;
+    int bitshift;
+    unsigned char byte;
+    unsigned int col;
+    
+    bigger_maxval = pm_bitstomaxval(bitsPerPixel);
+    bitshift = 8 - bitsPerPixel;
+    byte = 0;
+    for (col = 0; col < cols; ++col) {
+        xelval s;
+        s = PNM_GET1(xelrow[col]);
+        if (backwardMap)
+            s = 1 - s;
+        
+        if (maxval != bigger_maxval)
+            s = (long) s * bigger_maxval / maxval;
+        byte |= s << bitshift;
+        bitshift -= bitsPerPixel;
+        if (bitshift < 0) {
+            putc(byte, stdout);
+            bitshift = 8 - bitsPerPixel;
+            byte = 0;
+        }
+    }
+    if (bitshift < 8 - bitsPerPixel)
+        putc(byte, ofP);
+}
+
+
+
+static void
+writeRowPseudoColor(FILE *          const ofP,
+                    xel *           const xelrow,
+                    unsigned int    const cols,
+                    colorhash_table const cht) {
+                       
+    unsigned int col;
+
+    for (col = 0; col < cols; ++col)
+        putc(ppm_lookupcolor(cht, &xelrow[col]), ofP);
+}
+
+
+
+static void
+writeRaster(FILE *           const ofP,
+            xel **           const xels,
+            unsigned int     const cols,
+            unsigned int     const rows,
+            int              const format,
+            xelval           const maxval,
+            long             const xmaxval,
+            colorhist_vector const chv,
+            unsigned int     const colors,
+            bool             const direct,
+            bool             const grayscale,
+            bool             const backwardMap,
+            unsigned int     const bitsPerPixel) {
+
+    unsigned int row;
+    colorhash_table cht;
+
+    if (chv)
+        cht = ppm_colorhisttocolorhash(chv, colors);
+            
+    for (row = 0; row < rows; ++row) {
+        if (direct)
+            writeRowDirect(ofP, xels[row], cols, format, xmaxval, maxval);
+        else {
+            if (grayscale)
+                writeRowGrayscale(ofP, xels[row], cols, maxval, backwardMap,
+                                  bitsPerPixel);
+            else
+                writeRowPseudoColor(ofP, xels[row], cols, cht);
+        }
+    }
+}
+
+
+
+int
+main(int argc, char * argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE* ifP;
+    xel ** xels;
+    int rows, cols, format, colors;
+    xelval maxval;
+    long xmaxval;
+    colorhist_vector chv;
+    X11WDFileHeader h11;
+    bool direct, grayscale;
+    const char * dumpname;
+    bool backwardMap;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    xels = pnm_readpnm(ifP, &cols, &rows, &maxval, &format);
+    xmaxval = (1 << cmdline.pseudodepth) - 1;
+    pm_close(ifP);
+    
+    if (cmdline.directcolor) {
+        direct = TRUE;
+        grayscale = FALSE;
+        chv = NULL;
+    } else {
+        /* Figure out the colormap. */
+        switch (PNM_FORMAT_TYPE(format)) {
+        case PPM_TYPE:
+            pm_message("computing colormap...");
+            chv = ppm_computecolorhist(xels, cols, rows, xmaxval+1, &colors);
+            if (!chv) {
+                pm_message("Too many colors - "
+                           "proceeding to write a 24-bit DirectColor "
+                           "dump file.  If you want PseudoColor, "
+                           "try doing a 'pnmquant %ld'.",
+                           xmaxval);
+                direct = TRUE;
+            } else {
+                pm_message("%d colors found", colors);
+                direct = FALSE;
+            }
+            grayscale = FALSE;
+            break;
+
+        case PBM_TYPE:
+            chv = NULL;
+            direct = FALSE;
+            grayscale = TRUE;
+            colors = 2;
+            break;
+        case PGM_TYPE:
+            chv = NULL;
+            direct = FALSE;
+            grayscale = TRUE;
+            colors = xmaxval + 1;
+            break;
+        default:
+            pm_error("INTERNAL ERROR: impossible format type");
+        }
+    }
+
+    if (STREQ(cmdline.inputFilespec, "-"))
+        dumpname = "stdin";
+    else {
+        if (strlen(cmdline.inputFilespec) > XWDVAL_MAX - sizeof(h11) - 1)
+            pm_error("Input file name is ridiculously long.");
+        else
+            dumpname = cmdline.inputFilespec;
+    }
+
+    setupX11Header(&h11, dumpname, cols, rows, format, 
+                   direct, grayscale, colors,
+                   cmdline.pseudodepth);
+
+    writeX11Header(h11, stdout);
+
+    /* Write out the dump name. */
+    fwrite(dumpname, 1, strlen(dumpname) + 1, stdout);
+
+    backwardMap = PNM_FORMAT_TYPE(format) == PBM_TYPE;
+
+    if (direct)
+        writeDirectColormap(stdout);
+    else
+        writePseudoColormap(stdout, chv, colors, 
+                            grayscale, backwardMap, maxval);
+    
+    writeRaster(stdout, xels, cols, rows, format, maxval, xmaxval, 
+                chv, colors, direct, grayscale,
+                backwardMap, h11.bits_per_pixel);
+
+    return 0;
+}
diff --git a/converter/other/ppmtopgm.c b/converter/other/ppmtopgm.c
new file mode 100644
index 00000000..86e7ae6a
--- /dev/null
+++ b/converter/other/ppmtopgm.c
@@ -0,0 +1,95 @@
+/* ppmtopgm.c - convert a portable pixmap to a portable graymap
+**
+** Copyright (C) 1989 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 "pm_c_util.h"
+#include "ppm.h"
+#include "pgm.h"
+#include "lum.h"
+
+static void
+convertRaster(FILE *       const ifP,
+              unsigned int const cols,
+              unsigned int const rows,
+              pixval       const maxval,
+              int          const format, 
+              pixel *      const inputRow,
+              gray *       const outputRow, 
+              FILE *       const ofP) {
+
+    unsigned int row;
+
+    for (row = 0; row < rows; ++row) {
+        ppm_readppmrow( ifP, inputRow, cols, maxval, format );
+        if (maxval <= 255) {
+            /* Use fast approximation to 0.299 r + 0.587 g + 0.114 b */
+            unsigned int col;
+            for (col = 0; col < cols; ++col)
+                outputRow[col] = (gray) ppm_fastlumin(inputRow[col]);
+        } else {
+            /* Can't use fast approximation, so fall back on floats. */
+            int col;
+            for (col = 0; col < cols; ++col) 
+                outputRow[col] = (gray) (PPM_LUMIN(inputRow[col]) + 0.5);
+        }
+        pgm_writepgmrow(ofP, outputRow, cols, maxval, 0);
+    }
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+    FILE* ifP;
+    const char * inputFilespec;
+    int eof;
+    
+    ppm_init( &argc, argv );
+
+    if (argc-1 > 1)
+        pm_error("The only argument is the (optional) input filename");
+
+    if (argc == 2)
+        inputFilespec = argv[1];
+    else
+        inputFilespec = "-";
+    
+    ifP = pm_openr(inputFilespec);
+
+    eof = FALSE;  /* initial assumption */
+
+    while (!eof) {
+        ppm_nextimage(ifP, &eof);
+        if (!eof) {
+            int rows, cols, format;
+            pixval maxval;
+            pixel* inputRow;
+            gray* outputRow;
+
+            ppm_readppminit(ifP, &cols, &rows, &maxval, &format);
+            pgm_writepgminit(stdout, cols, rows, maxval, 0);
+
+            inputRow = ppm_allocrow(cols);
+            outputRow = pgm_allocrow(cols);
+
+            convertRaster(ifP, cols, rows, maxval, format, 
+                          inputRow, outputRow, stdout);
+
+            ppm_freerow(inputRow);
+            pgm_freerow(outputRow);
+        }
+    }
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
+}
diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c
new file mode 100644
index 00000000..a31c3f64
--- /dev/null
+++ b/converter/other/pstopnm.c
@@ -0,0 +1,899 @@
+/*----------------------------------------------------------------------------
+                                 pstopnm
+------------------------------------------------------------------------------
+  Use Ghostscript to convert a Postscript file into a PBM, PGM, or PNM
+  file.
+
+  Implementation note: This program feeds the input file to Ghostcript
+  directly (with possible statements preceding it), and uses
+  Ghostscript's PNM output device drivers.  As an alternative,
+  Ghostscript also comes with the Postscript program pstoppm.ps which
+  we could run and it would read the input file and produce PNM
+  output.  It isn't clear to me what pstoppm.ps adds to what you get
+  from just feeding your input directly to Ghostscript as the main program.
+
+-----------------------------------------------------------------------------*/
+
+#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  
+    /* Make sure fdopen() is in stdio.h and strdup() is in string.h */
+
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/wait.h>  
+#include <sys/stat.h>
+
+#include "pnm.h"
+#include "shhopt.h"
+#include "nstring.h"
+
+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.
+    */
+    int llx;  /* lower left X coord */
+        /* -1 for llx means whole box is undefined. */
+    int lly;  /* lower left Y coord */
+    int urx;  /* upper right X coord */
+    int ury;  /* upper right Y coord */
+};
+
+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 */
+    unsigned int forceplain;
+    struct box extract_box;
+    unsigned int nocrop;
+    unsigned int format_type;
+    unsigned int verbose;
+    float xborder;
+    unsigned int xmax;
+    unsigned int xsize;  /* zero means unspecified */
+    float yborder;
+    unsigned int ymax;
+    unsigned int ysize;  /* zero means unspecified */
+    unsigned int dpi;    /* zero means unspecified */
+    enum orientation orientation;
+    unsigned int goto_stdout;
+};
+
+
+static void
+parseCommandLine(int argc, 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 = malloc( 100*sizeof( optEntry ) );
+        /* Instructions to 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;
+    float llx, lly, urx, ury;
+    unsigned int llxSpec, llySpec, urxSpec, urySpec;
+    unsigned int xmaxSpec, ymaxSpec, xsizeSpec, ysizeSpec, dpiSpec;
+    
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "forceplain", OPT_FLAG,  NULL, &cmdlineP->forceplain,     0);
+    OPTENT3(0, "llx",        OPT_FLOAT, &llx, &llxSpec,                  0);
+    OPTENT3(0, "lly",        OPT_FLOAT, &lly, &llySpec,                  0);
+    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, "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);
+    OPTENT3(0, "xsize",      OPT_UINT,  &cmdlineP->xsize, &xsizeSpec,    0);
+    OPTENT3(0, "yborder",    OPT_FLOAT, &cmdlineP->yborder, NULL,        0);
+    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);
+
+    /* Set the defaults */
+    cmdlineP->xborder = cmdlineP->yborder = 0.1;
+
+    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);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (xmaxSpec) {
+        if (cmdlineP->xmax == 0)
+            pm_error("zero is not a valid value for -xmax");
+    } else
+        cmdlineP->xmax = 612;
+
+    if (ymaxSpec) {
+        if (cmdlineP->ymax == 0)
+            pm_error("zero is not a valid value for -ymax");
+    } else 
+        cmdlineP->ymax = 792;
+
+    if (xsizeSpec) {
+        if (cmdlineP->xsize == 0)
+            pm_error("zero is not a valid value for -xsize");
+    } else
+        cmdlineP->xsize = 0;
+
+    if (ysizeSpec) {
+        if (cmdlineP->ysize == 0)
+            pm_error("zero is not a valid value for -ysize");
+    } else 
+        cmdlineP->ysize = 0;
+
+    if (portrait_opt & !landscape_opt)
+        cmdlineP->orientation = PORTRAIT;
+    else if (!portrait_opt & landscape_opt)
+        cmdlineP->orientation = LANDSCAPE;
+    else if (!portrait_opt & !landscape_opt)
+        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;
+    else
+        cmdlineP->format_type = 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;
+    } else {
+        cmdlineP->extract_box.llx = -1;
+    }
+
+    if (dpiSpec) {
+        if (cmdlineP->dpi == 0)
+            pm_error("Zero is not a valid value for -dpi");
+    } else
+        cmdlineP->dpi = 0;
+
+    if (dpiSpec && xsizeSpec + ysizeSpec + xmaxSpec + ymaxSpec > 0)
+        pm_error("You may not specify both size options and -dpi");
+
+    if (argc-1 == 0)
+        cmdlineP->input_filespec = "-";  /* stdin */
+    else if (argc-1 == 1)
+        cmdlineP->input_filespec = argv[1];
+    else 
+        pm_error("Too many arguments (%d).  "
+                 "Only need one: the Postscript filespec", argc-1);
+}
+
+
+
+static void
+add_ps_to_filespec(const char orig_filespec[], char ** const new_filespec_p,
+                   const int verbose) {
+/*----------------------------------------------------------------------------
+   If orig_filespec[] 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[].
+
+   Return the name in newly malloc'ed storage, pointed to by
+   *new_filespec_p.
+-----------------------------------------------------------------------------*/
+    struct stat statbuf;
+    int stat_rc;
+
+    stat_rc = lstat(orig_filespec, &statbuf);
+    
+    if (stat_rc == 0)
+        *new_filespec_p = strdup(orig_filespec);
+    else {
+        const char *filespec_plus_ps;
+
+        asprintfN(&filespec_plus_ps, "%s.ps", orig_filespec);
+
+        stat_rc = lstat(filespec_plus_ps, &statbuf);
+        if (stat_rc == 0)
+            *new_filespec_p = strdup(filespec_plus_ps);
+        else
+            *new_filespec_p = strdup(orig_filespec);
+        strfree(filespec_plus_ps);
+    }
+    if (verbose)
+        pm_message("Input file is %s", *new_filespec_p);
+}
+
+
+
+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) {
+
+    if (requestedXsize) {
+        *xsizeP = requestedXsize;
+        *xresP = (unsigned int) (requestedXsize * 72 / imageWidth + 0.5);
+        if (!requestedYsize) {
+            *yresP = *xresP;
+            *ysizeP = (unsigned int) (imageHeight * (float)*yresP/72 + 0.5);
+            }
+        }
+
+    if (requestedYsize) {
+        *ysizeP = requestedYsize;
+        *yresP = (unsigned int) (requestedYsize * 72 / imageHeight + 0.5);
+        if (!requestedXsize) {
+            *xresP = *yresP;
+            *xsizeP = (unsigned int) (imageWidth * (float)*xresP/72 + 0.5);
+        }
+    } 
+}
+
+
+
+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);
+    
+    if (nocrop) {
+        *xsizeP = xmax;
+        *ysizeP = ymax;
+    } else {
+        *xsizeP = (unsigned int) (imageWidth * (float)*xresP / 72 + 0.5);
+        *ysizeP = (unsigned int) (imageHeight * (float)*yresP / 72 + 0.5);
+    }
+}
+
+
+
+static void
+compute_size_res(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) {
+/*----------------------------------------------------------------------------
+  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).
+
+  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
+  image, and a PNM image has no spatial dimension (you can't say how
+  many inches wide a PNM image is), it's kind of confusing.  
+
+  If the user doesn't select a resolution, we choose the resolution
+  that causes the image to be a certain number of pixels, knowing how
+  big (in inches) Ghostscript wants the printed picture to be.  For
+  example, the part of the Postscript image we are going to print is 2
+  inches wide.  We want the PNM image to be 1000 pixels wide.  So we
+  tell Ghostscript that our horizontal output device resolution is 500
+  pixels per inch.
+  
+  *xresP and *yresP are in dots per inch.
+-----------------------------------------------------------------------------*/
+    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;
+    }
+
+    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);
+    } else  if (cmdline.xsize || cmdline.ysize)
+        computeSizeResFromSizeSpec(cmdline.xsize, cmdline.ysize, sx, sy,
+                                   xsizeP, ysizeP, xresP, yresP);
+    else 
+        computeSizeResBlind(cmdline.xmax, cmdline.ymax, sx, sy, cmdline.nocrop,
+                            xsizeP, ysizeP, xresP, yresP);
+
+    if (cmdline.verbose) {
+        pm_message("output is %u pixels wide X %u pixels high",
+                   *xsizeP, *ysizeP);
+        pm_message("output device resolution is %u dpi horiz, %u dpi vert",
+                   *xresP, *yresP);
+    }
+}
+
+
+
+enum postscript_language {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT};
+
+static enum postscript_language
+language_declaration(const char input_filespec[], int const verbose) {
+/*----------------------------------------------------------------------------
+  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;
+
+    if (STREQ(input_filespec, "-"))
+        /* Can't read stdin, because we need it to remain positioned for the 
+           Ghostscript interpreter to read it.
+        */
+        language = COMMON_POSTSCRIPT;
+    else {
+        FILE *infile;
+        char line[80];
+
+        infile = pm_openr(input_filespec);
+
+        if (fgets(line, sizeof(line), infile) == NULL)
+            language = COMMON_POSTSCRIPT;
+        else {
+            const char eps_header[] = " EPSF-";
+
+            if (strstr(line, eps_header))
+                language = ENCAPSULATED_POSTSCRIPT;
+            else
+                language = COMMON_POSTSCRIPT;
+        }
+        fclose(infile);
+    }
+    if (verbose)
+        pm_message("language is %s",
+                   language == ENCAPSULATED_POSTSCRIPT ?
+                   "encapsulated postscript" :
+                   "not encapsulated postscript");
+    return language;
+}
+
+
+
+static struct box
+compute_box_to_extract(struct box const cmdline_extract_box,
+                       char       const input_filespec[],
+                       bool       const verbose) {
+
+    struct box retval;
+
+    if (cmdline_extract_box.llx != -1)
+        /* User told us what box to extract, so that's what we'll do */
+        retval = cmdline_extract_box;
+    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 */
+
+        if (STREQ(input_filespec, "-"))
+            /* Can't read stdin, because we need it to remain
+               positioned for the Ghostscript interpreter to read it.  
+            */
+            ps_bb.llx = -1;
+        else {
+            FILE *infile;
+            int found_BB, eof;  /* logical */
+            infile = pm_openr(input_filespec);
+            
+            found_BB = FALSE;
+            eof = FALSE;
+            while (!eof && !found_BB) {
+                char line[200];
+                
+                if (fgets(line, sizeof(line), infile) == 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);
+                    if (rc == 4) 
+                        found_BB = TRUE;
+                }
+            }
+            fclose(infile);
+
+            if (!found_BB) {
+                ps_bb.llx = -1;
+                pm_message("Warning: no %%%%BoundingBox statement "
+                           "in the input or command line.\n"
+                           "Will use defaults");
+            }
+        }
+        if (ps_bb.llx != -1) {
+            if (verbose)
+                pm_message("Using %%%%BoundingBox statement from input.");
+            retval = ps_bb;
+        } else { 
+            /* Use the center of an 8.5" x 11" page with 1" border all around*/
+            retval.llx = 72;
+            retval.lly = 72;
+            retval.urx = 540;
+            retval.ury = 720;
+        }
+    }
+    if (verbose)
+        pm_message("Extracting the box ((%d,%d),(%d,%d))",
+                   retval.llx, retval.lly, retval.urx, retval.ury);
+    return retval;
+}
+
+
+
+static enum orientation
+compute_orientation(struct cmdlineInfo const cmdline, 
+                    struct box         const extract_box) {
+
+    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;
+
+    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;
+        } 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;
+            }
+
+            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;
+        }
+    }
+    return retval;
+}
+
+
+
+static struct box
+add_borders(const struct box input_box, 
+            const float xborder_scale, float yborder_scale,
+            const int verbose) {
+/*----------------------------------------------------------------------------
+   Return a box which is 'input_box' plus some borders.
+
+   Add left and right borders that are the fraction 'xborder_scale' of the
+   width of the input box; likewise for top and bottom borders with 
+   'yborder_scale'.
+-----------------------------------------------------------------------------*/
+    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;
+
+    if (verbose)
+        pm_message("With borders, extracted box is ((%d,%d),(%d,%d))",
+                   retval.llx, retval.lly, retval.urx, retval.ury);
+
+    return retval;
+}
+
+
+
+static const char *
+compute_pstrans(const struct box box, const enum orientation orientation,
+                const int xsize, const int ysize, 
+                const int xres, const int yres) {
+
+    const char * retval;
+
+    if (orientation == 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 {
+        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);
+    }
+
+    if (retval == NULL)
+        pm_error("Unable to allocate memory for pstrans");
+
+    return retval;
+}
+
+
+
+static const char *
+compute_outfile_arg(const struct cmdlineInfo cmdline) {
+
+    const char *retval;  /* malloc'ed */
+
+    if (cmdline.goto_stdout)
+        retval = strdup("-");
+    else if (STREQ(cmdline.input_filespec, "-"))
+        retval = strdup("-");
+    else {
+        char * basename;
+        const char * suffix;
+        
+        basename  = strdup(cmdline.input_filespec);
+        if (strlen(basename) > 3 && 
+            STREQ(basename+strlen(basename)-3, ".ps")) 
+            /* The input filespec ends in ".ps".  Chop it off. */
+            basename[strlen(basename)-3] = '\0';
+
+        switch (cmdline.format_type) {
+        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);
+        }
+        asprintfN(&retval, "%s%%03d.%s", basename, suffix);
+
+        strfree(basename);
+    }
+    return(retval);
+}
+
+
+
+static const char *
+compute_gs_device(const int format_type, const int forceplain) {
+
+    const char * basetype;
+    const char * retval;
+
+    switch (format_type) {
+    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");
+    }
+    if (forceplain)
+        retval = strdup(basetype);
+    else
+        asprintfN(&retval, "%sraw", basetype);
+
+    if (retval == NULL)
+        pm_error("Unable to allocate memory for gs device");
+
+    return(retval);
+}
+
+
+
+static void
+findGhostscriptProg(const char ** const retvalP) {
+    
+    *retvalP = NULL;  /* initial assumption */
+    if (getenv("GHOSTSCRIPT"))
+        *retvalP = strdup(getenv("GHOSTSCRIPT"));
+    if (*retvalP == NULL) {
+        if (getenv("PATH") != NULL) {
+            char *pathwork;  /* malloc'ed */
+            const char * candidate;
+
+            pathwork = strdup(getenv("PATH"));
+            
+            candidate = strtok(pathwork, ":");
+
+            *retvalP = NULL;
+            while (!*retvalP && candidate) {
+                struct stat statbuf;
+                const char * filename;
+                int rc;
+
+                asprintfN(&filename, "%s/gs", candidate);
+                rc = stat(filename, &statbuf);
+                if (rc == 0) {
+                    if (S_ISREG(statbuf.st_mode))
+                        *retvalP = strdup(filename);
+                } else if (errno != ENOENT)
+                    pm_error("Error looking for Ghostscript program.  "
+                             "stat(\"%s\") returns errno %d (%s)",
+                             filename, errno, strerror(errno));
+                strfree(filename);
+
+                candidate = strtok(NULL, ":");
+            }
+            free(pathwork);
+        }
+    }
+    if (*retvalP == NULL)
+        *retvalP = strdup("/usr/bin/gs");
+}
+
+
+
+static void
+execGhostscript(int const inputPipeFd,
+                const char ghostscript_device[],
+                const char outfile_arg[], 
+                int const xsize, int const ysize, 
+                int const xres, int const yres,
+                const char input_filespec[], int const verbose) {
+    
+    const char *arg0;
+    const char *ghostscriptProg;
+    const char *deviceopt;
+    const char *outfileopt;
+    const char *gopt;
+    const char *ropt;
+    int rc;
+
+    findGhostscriptProg(&ghostscriptProg);
+
+    /* Put the input pipe on Standard Input */
+    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);
+
+    /* -dSAFER causes Postscript to disable %pipe and file operations,
+       which are almost certainly not needed here.  This prevents our
+       Postscript program from doing crazy unexpected things, possibly
+       as a result of a malicious booby trapping of our Postscript file.
+    */
+
+    if (verbose) {
+        pm_message("execing '%s' with args '%s' (arg 0), "
+                   "'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'",
+                   ghostscriptProg, arg0,
+                   deviceopt, outfileopt, gopt, ropt, "-q", "-dNOPAUSE", 
+                   "-dSAFER", "-");
+    }
+
+    execl(ghostscriptProg, arg0, deviceopt, outfileopt, gopt, ropt, "-q",
+          "-dNOPAUSE", "-dSAFER", "-", NULL);
+    
+    pm_error("execl() of Ghostscript ('%s') failed, errno=%d (%s)",
+             ghostscriptProg, errno, strerror(errno));
+}
+
+
+
+
+static void
+execute_ghostscript(const char pstrans[], const char ghostscript_device[],
+                    const char outfile_arg[], 
+                    const int xsize, const int ysize, 
+                    const int xres, const int yres,
+                    const char input_filespec[], 
+                    const enum postscript_language language,
+                    const int verbose) {
+
+    int gs_exit;  /* wait4 exit code from Ghostscript */
+    FILE *gs;  /* Pipe to Ghostscript's standard input */
+    FILE *infile;
+    int rc;
+    int eof;  /* End of file on input */
+    int pipefd[2];
+
+    if (strlen(outfile_arg) > 80)
+        pm_error("output file spec too long.");
+    
+    rc = pipe(pipefd);
+    if (rc < 0)
+        pm_error("Unable to create pipe to talk to Ghostscript process.  "
+                 "errno = %d (%s)", errno, strerror(errno));
+    
+    rc = fork();
+    if (rc < 0)
+        pm_error("Unable to fork a Ghostscript process.  errno=%d (%s)",
+                 errno, strerror(errno));
+    else if (rc == 0) {
+        /* Child process */
+        close(pipefd[1]);
+        execGhostscript(pipefd[0], ghostscript_device, outfile_arg,
+                        xsize, ysize, xres, yres, input_filespec, verbose);
+    } else {
+        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);
+
+        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);
+
+        if (language == ENCAPSULATED_POSTSCRIPT)
+            fprintf(gs, "\nb4_Inc_state restore showpage\n");
+
+        fclose(gs);
+        
+        waitpid(ghostscriptPid, &gs_exit, 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))
+                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));
+            else 
+                pm_error("Ghostscript process died with exit code %d", 
+                         gs_exit);
+        }
+    }
+}
+
+
+
+int
+main(int argc, char **argv) {
+
+    struct cmdlineInfo cmdline;
+    char *input_filespec;  /* 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;
+        /* coordinates of the box within the input we are to extract; i.e.
+           that will become the output. 
+           */
+    struct box bordered_box;
+        /* 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;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    add_ps_to_filespec(cmdline.input_filespec, &input_filespec,
+                       cmdline.verbose);
+
+    extract_box = compute_box_to_extract(cmdline.extract_box, input_filespec, 
+                                         cmdline.verbose);
+
+    language = language_declaration(input_filespec, cmdline.verbose);
+    
+    orientation = compute_orientation(cmdline, extract_box);
+
+    bordered_box = add_borders(extract_box, cmdline.xborder, cmdline.yborder,
+                               cmdline.verbose);
+
+    compute_size_res(cmdline, orientation, bordered_box, 
+                     &xsize, &ysize, &xres, &yres);
+    
+    pstrans = compute_pstrans(bordered_box, orientation,
+                              xsize, ysize, xres, yres);
+
+    outfile_arg = compute_outfile_arg(cmdline);
+
+    ghostscript_device = 
+        compute_gs_device(cmdline.format_type, cmdline.forceplain);
+    
+    pm_message("Writing %s file", ghostscript_device);
+    
+    execute_ghostscript(pstrans, ghostscript_device, outfile_arg, 
+                        xsize, ysize, xres, yres, input_filespec,
+                        language, cmdline.verbose);
+
+    strfree(ghostscript_device);
+    strfree(outfile_arg);
+    strfree(pstrans);
+    
+    return 0;
+}
+
+
diff --git a/converter/other/pstopnm.csh b/converter/other/pstopnm.csh
new file mode 100755
index 00000000..adde3e6f
--- /dev/null
+++ b/converter/other/pstopnm.csh
@@ -0,0 +1,301 @@
+#!/bin/csh -f
+#
+#	Uses ghostscript to translate an Encapsulated PostScript file to
+#	Portable Anymap format file(s).
+#	pstopnm will create as many files as the number of pages in 
+#	the Postscript document.  The name of the files will be 
+#	psfile001.ppm, psfile002.ppm, etc.
+#	The ouput files will contain the area inside the BoundingBox.
+#	If BoundingBox parameters are not found in the PostScript
+#	document, default values are used.
+#
+#
+#       Usage: pstopnm [-forceplain] [-help] [-llx s] [-lly s] 
+#		       [-urx s] [-ury s] [-nocrop] [-pbm|-pgm|-ppm] 
+#		       [-verbose] [-xborder n] [-xmax n] [-xsize n] 
+#		       [-yborder n] [-ymax n] [-ysize n] 
+#		       [-portrait] [-landscape] psfile[.ps]
+# 
+# 	Copyright (C) 1992 by Alberto Accomazzi, Smithsonian Astrophysical
+#	Observatory (alberto@cfa.harvard.edu).
+#
+# 	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.
+#
+set noglob
+
+set progname = $0
+set progname = $progname:t
+set filtertail = "raw"
+set filterhead = "ppm"
+set xsize = 0
+set ysize = 0
+set xres = ""
+set yres = ""
+
+# default values: max image x and y sizes
+set xmax = 612
+set ymax = 792
+# default values: image area fits in a 8.5x11 sheet with 1 inch border
+set llx = 72
+set lly = 72
+set urx = 540
+set ury = 720
+# default values: x and y borders are 10% of x and y size
+set xborder = "0.1"
+set yborder = "0.1"
+# default values: orientation is unknown
+set orient = 0
+
+set psfile = ""
+set USAGE = "Usage: $progname [-forceplain] [-help] [-llx s] [-lly s]\
+[-urx s] [-ury s] [-landscape] [-portrait]\
+[-nocrop] [-pbm|-pgm|-ppm] [-verbose] [-xborder s] [-xmax s]\
+[-xsize s] [-yborder s] [-ymax s] [-ysize s] psfile[.ps]"
+alias usage 'echo $USAGE; exit 1'
+
+while ($#argv > 0)
+    switch ($argv[1])
+    case -h*:   # -help
+        usage
+        breaksw
+    case -pbm:
+    case -pgm:
+    case -ppm:
+    	set filterhead = `echo "$argv[1]" | sed "s/-//1"`
+	breaksw
+    case -llx:
+        shift argv
+        if ($#argv == 0) eval usage
+    	set llx = `(echo "scale=4";echo "$argv[1] * 72")|bc -l`
+	set nobb
+	breaksw
+    case -lly:
+        shift argv
+        if ($#argv == 0) eval usage
+	set lly = `(echo "scale=4";echo "$argv[1] * 72")|bc -l`
+	set nobb
+	breaksw
+    case -urx:
+        shift argv
+        if ($#argv == 0) eval usage
+	set urx = `(echo "scale=4";echo "$argv[1] * 72")|bc -l`
+	set nobb
+	breaksw
+    case -ury:
+        shift argv
+        if ($#argv == 0) eval usage
+	set ury = `(echo "scale=4";echo "$argv[1] * 72")|bc -l`
+	set nobb
+	breaksw
+    case -no*:	# -nocrop
+	set nocrop
+	breaksw
+    case -xs*:	# -xsize
+        shift argv
+        if ($#argv == 0) eval usage
+	@ xsize = $argv[1]
+	breaksw
+    case -ys*:	# -ysize
+        shift argv
+        if ($#argv == 0) eval usage
+	@ ysize = $argv[1]
+	breaksw
+    case -xm*:	# -xmax
+        shift argv
+        if ($#argv == 0) eval usage
+	@ xmax = $argv[1]
+	breaksw
+    case -ym*:	# -ymax
+        shift argv
+        if ($#argv == 0) eval usage
+	@ ymax = $argv[1]
+	breaksw
+    case -xb*:	# -xborder
+        shift argv
+        if ($#argv == 0) eval usage
+	set xborder = $argv[1]
+	breaksw
+    case -yb*:	# -yborder
+        shift argv
+        if ($#argv == 0) eval usage
+	set yborder = $argv[1]
+	breaksw
+    case -f*:	# -forceplain
+	set filtertail = ""
+	breaksw
+    case -s*:	# -stdout
+	set goto_stdout
+	breaksw
+    case -v*:	# -verbose
+	set verb
+	breaksw
+    case -po*:	# -portrait
+	set orient = 1
+	breaksw
+    case -la*:	# -landscape
+	set orient = 2
+	breaksw
+    case -*:
+        echo "${progname}: Unknown option $argv[1]"
+        usage
+        breaksw
+    default:	# input file
+	set psfile = $argv[1]
+	set ppmfile = `basename $argv[1] .ps`
+        breaksw
+    endsw
+    shift argv
+end
+
+if ($psfile =~ "") eval usage
+if (! -f $psfile) then
+    echo "${progname}: file $psfile not found"
+    usage
+endif
+
+set bb = `grep "%%BoundingBox" $psfile`
+if ($?nobb == 0 && $#bb == 5) then
+    set llx = $bb[2]
+    set lly = $bb[3]
+    set urx = $bb[4]
+    set ury = $bb[5]
+else
+    if ($?nobb == 0) \
+    	echo "${progname}: warning: BoundingBox not found in input file"
+endif
+
+set tmpsx = `(echo "scale=4";echo "$urx - $llx")|bc -l`
+set tmpsy = `(echo "scale=4";echo "$ury - $lly")|bc -l`
+
+# see if orientation was specified 
+if ($orient == 0) then
+    # no orientation was specified; compute default orientation
+    set tmpx = 0
+    set tmpy = 0
+    set tmpsx1 = $tmpsx:r
+    set tmpsy1 = $tmpsy:r
+    # default is landscape mode
+    set orient = 2
+    if ($xsize == 0 && $ysize == 0) then
+	set tmpx = $xmax
+	set tmpy = $ymax
+    else
+	if ($xsize != 0) set tmpx = $xsize
+	if ($ysize != 0) set tmpy = $ysize
+    endif
+    if ($tmpx == 0 || $tmpy == 0) then
+	# only one size was specified
+	if ($tmpsy1 > $tmpsx1) set orient = 1
+    else
+	# no size or both sizes were specified
+	if ($tmpsy1 > $tmpsx1 && $tmpy > $tmpx) set orient = 1
+	if ($tmpsx1 > $tmpsy1 && $tmpx > $tmpy) set orient = 1
+    endif
+endif
+
+# now reset BoundingBox llc and total size to take into account margin
+set llx = `(echo "scale=4";echo "$llx - $tmpsx * $xborder")|bc -l`
+set lly = `(echo "scale=4";echo "$lly - $tmpsy * $yborder")|bc -l`
+set urx = `(echo "scale=4";echo "$urx + $tmpsx * $xborder")|bc -l`
+set ury = `(echo "scale=4";echo "$ury + $tmpsy * $yborder")|bc -l`
+# compute image area size 
+set sx = `(echo "scale=4";echo "$tmpsx + 2 * $xborder * $tmpsx")|bc -l`
+set sy = `(echo "scale=4";echo "$tmpsy + 2 * $yborder * $tmpsy")|bc -l`
+    
+if ($orient != 1) then
+    # render image in landscape mode
+    set tmpsx = $sx
+    set sx = $sy
+    set sy = $tmpsx
+endif
+
+# if xsize or ysize was specified, compute resolution from them
+if ($xsize != 0) set xres = `(echo "scale=4";echo "$xsize *72 / $sx")|bc -l`
+if ($ysize != 0) set yres = `(echo "scale=4";echo "$ysize *72 / $sy")|bc -l`
+
+if ($xres =~ "" && $yres !~ "") then
+    # ysize was specified, xsize was not; compute xsize based on ysize
+    set xres = $yres 
+    set xsize = `(echo "scale=4";echo "$sx * $xres /72 + 0.5")|bc -l`
+    set xsize = $xsize:r
+else 
+    if ($yres =~ "" && $xres !~ "") then
+	# xsize was specified, ysize was not; compute ysize based on xsize
+        set yres = $xres
+    	set ysize = `(echo "scale=4";echo "$sy * $yres /72 + 0.5")|bc -l`
+    	set ysize = $ysize:r
+    else
+	if ($xres =~ "" && $yres =~ "") then
+    	    # neither xsize nor ysize was specified; compute them from
+	    # xmax and ymax
+	    set xres = `(echo "scale=4";echo "$xmax *72/$sx")|bc -l`
+	    set yres = `(echo "scale=4";echo "$ymax *72/$sy")|bc -l`
+	    set xres = `(echo "scale=4";echo "if($xres>$yres)$yres";echo "if($yres>$xres)$xres";echo "if($xres==$yres)$xres")|bc -l`
+	    set yres = $xres
+	    if ($?nocrop) then
+		# keep output file dimensions equal to xmax and ymax
+		set xsize = $xmax
+		set ysize = $ymax
+	    else
+    	    	set xsize = `(echo "scale=4";echo "$sx * $xres /72+0.5")|bc -l`
+    	    	set ysize = `(echo "scale=4";echo "$sy * $yres /72+0.5")|bc -l`
+	    endif
+    	    set xsize = $xsize:r
+    	    set ysize = $ysize:r
+	endif
+    endif
+endif
+
+# translate + rotate image, if necessary
+if ($orient == 1) then
+    # portrait mode
+    # adjust offsets
+    set llx = `(echo "scale=4";echo "$llx - ($xsize *72/$xres - $sx)/2")|bc -l`
+    set lly = `(echo "scale=4";echo "$lly - ($ysize *72/$yres - $sy)/2")|bc -l`
+    set pstrans = "$llx neg $lly neg translate"
+else
+    # landscape mode
+    # adjust offsets
+    set llx = `(echo "scale=4";echo "$llx - ($ysize *72/$yres - $sy)/2")|bc -l`
+    set ury = `(echo "scale=4";echo "$ury + ($xsize *72/$xres - $sx)/2")|bc -l`
+    set pstrans = "90 rotate $llx neg $ury neg translate"
+endif
+   
+if ($?goto_stdout) then
+    set outfile = "-"
+else
+    set outfile = $ppmfile%03d.$filterhead 
+endif
+
+if ($?verb) then
+    echo "sx = $sx" 
+    echo "sy = $sy"
+    echo "xres  = $xres"
+    echo "yres  = $yres"
+    echo "xsize = $xsize"
+    echo "ysize = $ysize"
+    echo -n "orientation "
+    if ($orient == 1) then 
+	echo "portrait"
+    else
+	echo "landscape"
+    endif
+    echo "PS header: $pstrans"
+endif
+
+echo "${progname}: writing $filterhead file(s)" 1>&2
+
+echo $pstrans | \
+	gs -sDEVICE=${filterhead}${filtertail} \
+	   -sOutputFile=$outfile \
+	   -g${xsize}x${ysize} \
+	   -r${xres}x${yres} \
+	   -q - $psfile 
+
+
+
diff --git a/converter/other/rast.c b/converter/other/rast.c
new file mode 100644
index 00000000..91c50ccd
--- /dev/null
+++ b/converter/other/rast.c
@@ -0,0 +1,465 @@
+/* libpnm4.c - pnm utility library part 4
+**
+** 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 "pnm.h"
+#include "rast.h"
+#include "mallocvar.h"
+
+/*
+** Semi-work-alike versions of some Sun pixrect routines.  Just enough
+** for rasterfile reading and writing to work.
+*/
+
+struct pixrect*
+mem_create( w, h, depth )
+    int w, h, depth;
+{
+    struct pixrect* p;
+    struct mpr_data* m;
+
+    MALLOCVAR(p);
+    if ( p == NULL )
+        return NULL;
+    p->pr_ops = NULL;
+    p->pr_size.x = w;
+    p->pr_size.y = h;
+    p->pr_depth = depth;
+    MALLOCVAR(m);
+    if ( m == NULL )
+    {
+        free( p );
+        return NULL;
+    }
+    p->pr_data = m;
+
+    /* According to the documentation, linebytes is supposed to be rounded
+    ** up to a longword (except on 386 boxes).  However, this turns out
+    ** not to be the case.  In reality, all of Sun's code rounds up to
+    ** a short, not a long.
+    */
+    m->md_linebytes = ( w * depth + 15 ) / 16 * 2;
+    m->md_offset.x = 0;
+    m->md_offset.y = 0;
+    m->md_flags = 0;
+    MALLOCARRAY(m->md_image, m->md_linebytes * h );
+    if ( m->md_image == NULL )
+    {
+        free( m );
+        free( p );
+        return NULL;
+    }
+
+    return p;
+}
+
+void
+mem_free( p )
+    struct pixrect* p;
+{
+    free( p->pr_data->md_image );
+    free( p->pr_data );
+    free( p );
+}
+
+int
+pr_dump( p, out, colormap, type, copy_flag )
+    struct pixrect* p;
+    FILE* out;
+    colormap_t* colormap;
+    int type, copy_flag;
+{
+    struct rasterfile h;
+    int size, besize, count;
+    unsigned char* beimage;
+    unsigned char* bp;
+    unsigned char c, pc;
+    int i, j;
+
+    h.ras_magic = RAS_MAGIC;
+    h.ras_width = p->pr_size.x;
+    h.ras_height = p->pr_size.y;
+    h.ras_depth = p->pr_depth;
+
+    h.ras_type = type;
+    switch ( type )
+    {
+    case RT_OLD:
+        pm_error( "This program does not know the Old rasterfile type" );
+
+    case RT_FORMAT_TIFF:
+        pm_error( "This program does not know the TIFF rasterfile type" );
+
+    case RT_FORMAT_IFF:
+        pm_error( "This program does not know the IFF rasterfile type" );
+
+    case RT_EXPERIMENTAL:
+        pm_error( "This program does not know the Experimental "
+                  "rasterfile type" );
+
+    case RT_STANDARD:
+    case RT_FORMAT_RGB:
+        /* Ignore hP->ras_length. */
+        h.ras_length = p->pr_size.y * p->pr_data->md_linebytes;
+        break;
+
+    case RT_BYTE_ENCODED:
+        size = p->pr_size.y * p->pr_data->md_linebytes;
+        bp = p->pr_data->md_image;
+        MALLOCARRAY(beimage, size * 3 / 2);  /* worst case */
+        if ( beimage == NULL )
+            return PIX_ERR;
+        besize = 0;
+        count = 0;
+        for ( i = 0; i < size; ++i )
+        {
+            c = *bp++;
+            if ( count > 0 )
+            {
+                if ( pc != c )
+                {
+                    if ( count == 1 && pc == 128 )
+                    {
+                        beimage[besize++] = 128;
+                        beimage[besize++] = 0;
+                        count = 0;
+                    }
+                    else if ( count > 2 || pc == 128 )
+                    {
+                        beimage[besize++] = 128;
+                        beimage[besize++] = count - 1;
+                        beimage[besize++] = pc;
+                        count = 0;
+                    }
+                    else
+                    {
+                        for ( j = 0; j < count; ++j )
+                            beimage[besize++] = pc;
+                        count = 0;
+                    }
+                }
+            }
+            pc = c;
+            ++count;
+            if ( count == 256 )
+            {
+                beimage[besize++] = 128;
+                beimage[besize++] = count - 1;
+                beimage[besize++] = c;
+                count = 0;
+            }
+        }
+        if ( count > 0 )
+        {
+            if ( count == 1 && c == 128 )
+            {
+                beimage[besize++] = 128;
+                beimage[besize++] = 0;
+            }
+            if ( count > 2 || c == 128 )
+            {
+                beimage[besize++] = 128;
+                beimage[besize++] = count - 1;
+                beimage[besize++] = c;
+            }
+            else
+            {
+                for ( j = 0; j < count; ++j )
+                    beimage[besize++] = c;
+            }
+        }
+        h.ras_length = besize;
+        break;
+
+    default:
+        pm_error( "unknown rasterfile type" );
+    }
+
+    if ( colormap == NULL )
+    {
+        h.ras_maptype = RMT_NONE;
+        h.ras_maplength = 0;
+    }
+    else
+    {
+        h.ras_maptype = colormap->type;
+        switch ( colormap->type )
+        {
+        case RMT_EQUAL_RGB:
+            h.ras_maplength = colormap->length * 3;
+            break;
+
+        case RMT_RAW:
+            h.ras_maplength = colormap->length;
+            break;
+
+        default:
+            pm_error( "unknown colormap type" );
+        }
+    }
+
+    if ( pm_writebiglong( out, h.ras_magic ) == -1 )
+        return PIX_ERR;
+    if ( pm_writebiglong( out, h.ras_width ) == -1 )
+        return PIX_ERR;
+    if ( pm_writebiglong( out, h.ras_height ) == -1 )
+        return PIX_ERR;
+    if ( pm_writebiglong( out, h.ras_depth ) == -1 )
+        return PIX_ERR;
+    if ( pm_writebiglong( out, h.ras_length ) == -1 )
+        return PIX_ERR;
+    if ( pm_writebiglong( out, h.ras_type ) == -1 )
+        return PIX_ERR;
+    if ( pm_writebiglong( out, h.ras_maptype ) == -1 )
+        return PIX_ERR;
+    if ( pm_writebiglong( out, h.ras_maplength ) == -1 )
+        return PIX_ERR;
+
+    if ( colormap != NULL )
+    {
+        switch ( colormap->type )
+        {
+        case RMT_EQUAL_RGB:
+            if ( fwrite( colormap->map[0], 1, colormap->length, out ) !=
+                 colormap->length )
+                return PIX_ERR;
+            if ( fwrite( colormap->map[1], 1, colormap->length, out ) !=
+                 colormap->length )
+                return PIX_ERR;
+            if ( fwrite( colormap->map[2], 1, colormap->length, out ) !=
+                 colormap->length )
+                return PIX_ERR;
+            break;
+
+        case RMT_RAW:
+            if ( fwrite( colormap->map[0], 1, colormap->length, out ) !=
+                 colormap->length )
+                return PIX_ERR;
+            break;
+        }
+    }
+
+    switch ( type )
+    {
+    case RT_STANDARD:
+    case RT_FORMAT_RGB:
+        if ( fwrite( p->pr_data->md_image, 1, h.ras_length, out ) !=
+             h.ras_length )
+            return PIX_ERR;
+        break;
+
+    case RT_BYTE_ENCODED:
+        if ( fwrite( beimage, 1, besize, out ) != besize )
+        {
+            free( beimage );
+            return PIX_ERR;
+        }
+        free( beimage );
+        break;
+    }
+
+    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;
+    return 0;
+}
+
+int
+pr_load_colormap( in, hP, colormap )
+    FILE* in;
+    struct rasterfile* hP;
+    colormap_t* colormap;
+{
+    if ( colormap == NULL || hP->ras_maptype == RMT_NONE )
+    {
+        int i;
+
+        for ( i = 0; i < hP->ras_maplength; ++i )
+            if ( getc( in ) == EOF )
+                return PIX_ERR;
+    }
+    else
+    {
+        colormap->type = hP->ras_maptype;
+        switch ( hP->ras_maptype )
+        {
+        case RMT_EQUAL_RGB:
+            colormap->length = hP->ras_maplength / 3;
+            MALLOCARRAY( colormap->map[0], colormap->length );
+            if ( colormap->map[0] == NULL )
+                return PIX_ERR;
+            MALLOCARRAY( colormap->map[1], colormap->length );
+            if ( colormap->map[1] == NULL )
+            {
+                free( colormap->map[0] );
+                return PIX_ERR;
+            }
+            MALLOCARRAY( colormap->map[2], colormap->length );
+            if ( colormap->map[2] == NULL )
+            {
+                free( colormap->map[0] );
+                free( colormap->map[1] );
+                return PIX_ERR;
+            }
+            if ( fread( colormap->map[0], 1, colormap->length, in ) != 
+                 colormap->length ||
+                 fread( colormap->map[1], 1, colormap->length, in ) != 
+                 colormap->length ||
+                 fread( colormap->map[2], 1, colormap->length, in ) != 
+                 colormap->length )
+            {
+                free( colormap->map[0] );
+                free( colormap->map[1] );
+                free( colormap->map[2] );
+                return PIX_ERR;
+            }
+            break;
+
+        case RMT_RAW: {
+            size_t bytesRead;
+
+            colormap->length = hP->ras_maplength;
+            MALLOCARRAY( colormap->map[0], colormap->length );
+            if ( colormap->map[0] == NULL )
+                return PIX_ERR;
+            colormap->map[2] = colormap->map[1] = colormap->map[0];
+            bytesRead = fread( colormap->map[0], 1, hP->ras_maplength, in );
+            if ( bytesRead != hP->ras_maplength )
+            {
+                free( colormap->map[0] );
+                return PIX_ERR;
+            }
+        }
+            break;
+
+        default:
+            pm_error( "unknown colormap type" );
+        }
+    }
+    return 0;
+}
+
+struct pixrect*
+pr_load_image( in, hP, colormap )
+    FILE* in;
+    struct rasterfile* hP;
+    colormap_t* colormap;
+{
+    struct pixrect* p;
+    unsigned char* beimage;
+    register unsigned char* bep;
+    register unsigned char* bp;
+    register unsigned char c;
+    int i;
+    register int j, count;
+
+    p = mem_create( hP->ras_width, hP->ras_height, hP->ras_depth );
+    if ( p == NULL )
+        return NULL;
+
+    switch ( hP->ras_type )
+    {
+    case RT_OLD:
+        pm_error( "This program does not know the Old rasterfile type" );
+
+    case RT_FORMAT_TIFF:
+        pm_error( "This program does not know the TIFF rasterfile type" );
+
+    case RT_FORMAT_IFF:
+        pm_error( "This program does not know the IFF rasterfile type" );
+
+    case RT_EXPERIMENTAL:
+        pm_error( "This program does not know the Experimental "
+                  "rasterfile type" );
+
+    case RT_STANDARD:
+    case RT_FORMAT_RGB:
+        /* Ignore hP->ras_length. */
+        i = p->pr_size.y * p->pr_data->md_linebytes;
+        if ( fread( p->pr_data->md_image, 1, i, in ) != i )
+        {
+            mem_free( p );
+            return NULL;
+        }
+        break;
+
+    case RT_BYTE_ENCODED:
+        MALLOCARRAY( beimage, hP->ras_length );
+        if ( beimage == NULL )
+        {
+            mem_free( p );
+            return NULL;
+        }
+        if ( fread( beimage, 1, hP->ras_length, in ) != hP->ras_length )
+        {
+            mem_free( p );
+            free( beimage );
+            return NULL;
+        }
+        bep = beimage;
+        bp = p->pr_data->md_image;
+        for ( i = 0; i < hP->ras_length; )
+        {
+            c = *bep++;
+            if ( c == 128 )
+            {
+                count = ( *bep++ ) + 1;
+                if ( count == 1 )
+                {
+                    *bp++ = 128;
+                    i += 2;
+                }
+                else
+                {
+                    c = *bep++;
+                    for ( j = 0; j < count; ++j )
+                        *bp++ = c;
+                    i += 3;
+                }
+            }
+            else
+            {
+                *bp++ = c;
+                ++i;
+            }
+        }
+        free( beimage );
+        break;
+
+    default:
+        pm_error( "unknown rasterfile type" );
+    }
+
+    return p;
+}
diff --git a/converter/other/rast.h b/converter/other/rast.h
new file mode 100644
index 00000000..1854e495
--- /dev/null
+++ b/converter/other/rast.h
@@ -0,0 +1,111 @@
+/* rast.h - header file for Sun raster files
+**
+** The format of a Sun raster file is as follows.  First, a struct
+** rasterfile.  Note the 32-bit magic number at the beginning; this
+** identifies the file type and lets you figure out whether you need
+** to do little-endian / big-endian byte-swapping or not.  (The PBMPLUS
+** implementation does not do byte-swapping; instead, it reads all
+** multi-byte values a byte at a time.)
+**
+** After the struct is an optional colormap.  If ras_maptype is RMT_NONE,
+** no map is present; if it's RMT_EQUAL_RGB then the map consists of
+** three unsigned-char arrays ras_maplength long, one each for r g and b.
+** I don't know what RMT_RAW means.  Black and white bitmaps are stored
+** as ras_maptype == RMT_NONE and ras_depth == 1, with the bits stored
+** eight to a byte MSB first.
+**
+** Finally comes the image data.  If ras_type is RT_OLD or RT_STANDARD,
+** the data is just plain old uncompressed bytes, padded out to a multiple
+** of 16 bits in each row.  If ras_type is RT_BYTE_ENCODED, a run-length
+** compression scheme is used: an escape-byte of 128 indicates a run;
+** the next byte is a count, and the one after that is the byte to be
+** replicated.  The one exception to this is if the count is 1; then
+** there is no third byte in the packet, it means to put a single 128
+** in the data stream.
+*/
+
+#ifndef RAST_H_INCLUDED
+#define RAST_H_INCLUDED
+
+#define PIX_ERR		-1
+
+struct rasterfile {
+    long ras_magic;
+#define	RAS_MAGIC	0x59a66a95
+    long ras_width;
+    long ras_height;
+    long ras_depth;
+    long ras_length;
+    long ras_type;
+#define RT_OLD		0	/* Raw pixrect image in 68000 byte order */
+#define RT_STANDARD	1	/* Raw pixrect image in 68000 byte order */
+#define RT_BYTE_ENCODED	2	/* Run-length compression of bytes */
+#define RT_FORMAT_RGB	3	/* XRGB or RGB instead of XBGR or BGR */
+#define RT_FORMAT_TIFF	4	/* tiff <-> standard rasterfile */
+#define RT_FORMAT_IFF	5	/* iff (TAAC format) <-> standard rasterfile */
+#define RT_EXPERIMENTAL 0xffff	/* Reserved for testing */
+    long ras_maptype;
+#define RMT_NONE	0
+#define RMT_EQUAL_RGB	1
+#define RMT_RAW		2
+    long ras_maplength;
+    };
+
+struct pixrectops {
+    int	(*pro_rop)();
+    int	(*pro_stencil)();
+    int	(*pro_batchrop)();
+    int	(*pro_nop)();
+    int	(*pro_destroy)();
+    int	(*pro_get)();
+    int	(*pro_put)();
+    int	(*pro_vector)();
+    struct pixrect* (*pro_region)();
+    int	(*pro_putcolormap)();
+    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;
+    unsigned char* md_image;	/* note, byte not short -- avoid pr_flip() */
+    struct pr_pos md_offset;
+    short md_primary;
+    short md_flags;
+    };
+
+typedef struct {
+    int type;
+    int length;
+    unsigned char* map[3];
+    } colormap_t;
+
+/* And the routine definitions. */
+
+struct pixrect* mem_create ARGS(( int w, int h, int depth ));
+void mem_free ARGS(( struct pixrect* p ));
+
+int pr_dump ARGS(( struct pixrect* p, FILE* out, colormap_t* colormap, int type, int copy_flag ));
+
+int pr_load_header ARGS(( FILE* in, struct rasterfile* hP ));
+
+int pr_load_colormap ARGS(( FILE* in, struct rasterfile* hP, colormap_t* colormap ));
+
+struct pixrect* pr_load_image ARGS(( FILE* in, struct rasterfile* hP, colormap_t* colormap ));
+
+#endif
diff --git a/converter/other/rasttopnm.c b/converter/other/rasttopnm.c
new file mode 100644
index 00000000..aa55850b
--- /dev/null
+++ b/converter/other/rasttopnm.c
@@ -0,0 +1,263 @@
+/* rasttopnm.c - read a Sun rasterfile and produce a portable anymap
+**
+** Copyright (C) 1989, 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.
+*/
+
+#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;
+
+    if ( argn != argc )
+	{
+	ifp = pm_openr( argv[argn] );
+	++argn;
+	}
+    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" );
+        break;
+
+        case PGM_TYPE:
+        pm_message( "writing PGM file" );
+        break;
+
+        case PPM_TYPE:
+        pm_message( "writing PPM file" );
+        break;
+
+        default:
+        pm_error( "shouldn't happen" );
+        }
+
+    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 );
+    }
diff --git a/converter/other/rla.h b/converter/other/rla.h
new file mode 100644
index 00000000..875cbfc6
--- /dev/null
+++ b/converter/other/rla.h
@@ -0,0 +1,45 @@
+typedef struct
+{
+    short left;
+    short right;
+    short bottom;
+    short top;
+} window_s;
+
+typedef struct
+{
+    window_s	window;
+    window_s	active_window;
+    short	    frame;
+    short       storage_type;
+    short       num_chan;
+    short       num_matte;
+    short       num_aux;
+    unsigned short       revision;
+    char        gamma[16];
+    char        red_pri[24];
+    char        green_pri[24];
+    char        blue_pri[24];
+    char        white_pri[24];
+    long        job_num;
+    char        name[128];
+    char        desc[128];
+    char        program[64];
+    char        machine[32];
+    char        user[32];
+    char        date[20];
+    char        aspect[24];
+    char        aspect_ratio[8];
+    char        chan[32];
+    short       field;
+    char        time[12];
+    char        filter[32];
+    short       chan_bits;
+    short       matte_type;
+    short       matte_bits;
+    short       aux_type;
+    short       aux_bits;
+    char        aux[32];
+    char        space[36];
+    long        next;
+} rlahdr;
diff --git a/converter/other/rlatopam.c b/converter/other/rlatopam.c
new file mode 100644
index 00000000..ae1326ca
--- /dev/null
+++ b/converter/other/rlatopam.c
@@ -0,0 +1,433 @@
+/** rlatopam.c - read Alias/Wavefront RLA or RPF file
+ **
+ ** Copyright (C) 2005 Matte World Digital
+ **
+ ** Author: Simon Walton
+ **
+ ** 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 <string.h>
+#include <errno.h>
+
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "pam.h"
+#include "rla.h"
+
+static int * offsets;
+static bool is_float;
+static bool has_matte;
+
+static unsigned int depth;
+static unsigned int width;
+static unsigned int height;
+static unsigned int chanBits;
+static short storageType;
+static struct pam outpam;
+static unsigned int numChan;
+
+
+static void
+parseCommandLine(int           const argc,
+                 char **       const argv,
+                 const char ** const inputFileNameP) {
+
+    if (argc-1 < 1)
+        *inputFileNameP = "-";
+    else {
+        *inputFileNameP = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("There is at most one argument - input file name.  "
+                     "You specified %u", argc-1);
+    }
+}
+
+
+
+static bool littleEndian;
+
+
+static void
+determineEndianness(void) {
+
+    union {
+        unsigned char bytes[2];
+        unsigned short number;
+    } u;
+
+    u.number = 1;
+
+    littleEndian = (u.bytes[0] == 1);
+}
+
+
+
+static unsigned short
+byteswap(unsigned short const input) {
+
+    return (input << 8) | (input >> 8);
+}
+
+
+
+static void
+read_header(FILE *   const ifP,
+            rlahdr * const hdrP) {
+
+    rlahdr hdr;
+    size_t bytesRead;
+    
+    fseek (ifP, 0, SEEK_SET);
+    
+    /* Here we have a hack.  The bytes in the file are almost in the
+       same format as the compiler stores 'hdr' in memory.  The only
+       difference is that the compiler may store the integer values
+       in the obscene little-endian format.  So we just read the whole
+       header into 'hdr' as if it were the right format, and then
+       correct the integer values by swapping their bytes.
+
+       The _right_ way to do this is to read the file one field at a time,
+       using pm_readbigshort() where appropriate.
+    */
+
+    bytesRead = fread(&hdr, sizeof hdr, 1, ifP);
+    if (bytesRead != 1)
+        pm_error("Unexpected EOF on input file.");
+
+    if (littleEndian) {
+        hdr.window.left          = byteswap(hdr.window.left);
+        hdr.window.right         = byteswap(hdr.window.right);
+        hdr.window.bottom        = byteswap(hdr.window.bottom);
+        hdr.window.top           = byteswap(hdr.window.top);
+        hdr.active_window.left   = byteswap(hdr.active_window.left);
+        hdr.active_window.right  = byteswap(hdr.active_window.right);
+        hdr.active_window.bottom = byteswap(hdr.active_window.bottom);
+        hdr.active_window.top    = byteswap(hdr.active_window.top);
+        hdr.storage_type         = byteswap(hdr.storage_type);
+        hdr.num_chan             = byteswap(hdr.num_chan);
+        hdr.num_matte            = byteswap(hdr.num_matte);
+        hdr.revision             = byteswap(hdr.revision);
+        hdr.chan_bits            = byteswap(hdr.chan_bits);
+        hdr.matte_type           = byteswap(hdr.matte_type);
+        hdr.matte_bits           = byteswap(hdr.matte_bits);
+    }
+
+    if (hdr.revision != 0xfffe && hdr.revision != 0xfffd)
+        pm_error("Invalid file header.  \"revision\" field should contain "
+                 "0xfffe or 0xfffd, but contains 0x%04x", hdr.revision);
+
+    *hdrP = hdr;
+}
+
+
+
+static void
+decodeFP(unsigned char * const in,
+         unsigned char * const out,
+         int             const width,
+         int             const stride) {
+
+    unsigned int x;
+    unsigned char * inputCursor;
+    unsigned char * outputCursor;
+
+    inputCursor = &in[0];
+
+    for (x = 0; x < width; ++x) {
+        union {char bytes [4]; float fv;} fi;
+        unsigned short val;
+
+        if (littleEndian) {
+            fi.bytes [3] = *inputCursor++;
+            fi.bytes [2] = *inputCursor++;
+            fi.bytes [1] = *inputCursor++;
+            fi.bytes [0] = *inputCursor++;
+        } else {
+            fi.bytes [0] = *inputCursor++;
+            fi.bytes [1] = *inputCursor++;
+            fi.bytes [2] = *inputCursor++;
+            fi.bytes [3] = *inputCursor++;
+        }
+
+        val = fi.fv > 1 ? 65535 : (fi.fv < 0 ? 0 :
+                                   (unsigned short) (65535 * fi.fv + .5));
+        outputCursor[0] = val >> 8; outputCursor[1] = val & 0xff;
+        outputCursor += stride;
+    }
+}
+
+
+
+static unsigned char *
+decode(unsigned char * const input,
+       unsigned char * const output,
+       int             const xFile,
+       int             const xImage,
+       int             const stride) {
+
+    int x;
+    unsigned int bytes;
+    unsigned int useX;
+    unsigned char * inputCursor;
+    unsigned char * outputCursor;
+
+    inputCursor = &input[0];
+    outputCursor = &output[0];
+    x = xFile;
+    bytes = 0;
+    useX = 0;
+    
+    while (x > 0) {
+        int count;
+
+        count = *(signed char *)inputCursor++;
+        ++bytes;
+
+        if (count >= 0) {
+            /* Repeat pixel value (count + 1) times. */
+            while (count-- >= 0) {
+                if (useX < xImage) {
+                    *outputCursor = *inputCursor;
+                    outputCursor += stride;
+                }
+                --x;
+                ++useX;
+            }
+            ++inputCursor;
+            ++bytes;
+        } else {
+            /* Copy (-count) unencoded values. */
+            for (count = -count; count > 0; --count) {
+                if (useX < xImage) {
+                    *outputCursor = *inputCursor;
+                    outputCursor += stride;
+                }
+                ++inputCursor;
+                ++bytes;
+                --x;
+                ++useX;
+            }
+        }
+    }
+    return inputCursor;
+}
+
+
+
+static void
+decode_row(FILE *          const ifP,
+           int             const row,
+           unsigned char * const rb) {
+
+    static unsigned char * read_buffer = NULL;
+    unsigned int chan;
+    int rc;
+
+    if (!read_buffer) {
+        MALLOCARRAY(read_buffer, width * 4);
+        if (read_buffer == 0)
+            pm_error("Unable to get memory for read_buffer");
+    }
+
+    rc = fseek (ifP, offsets [height - row - 1], SEEK_SET);
+    if (rc != 0)
+        pm_error("fseek() failed with errno %d (%s)",
+                 errno, strerror(errno));
+
+    for (chan = 0; chan < outpam.depth; ++chan) {
+        unsigned short length;
+        size_t bytesRead;
+        
+        pm_readbigshortu(ifP, &length);
+        if (length > width * 4)
+            pm_error("Line too long - row %u, channel %u", row, chan);
+
+        bytesRead = fread(read_buffer, 1, length, ifP);
+        if (bytesRead != length)
+            pm_error("EOF encountered unexpectedly");
+
+        if (is_float)
+            decodeFP(read_buffer, rb + chan * 2, width, outpam.depth * 2);
+        else if (depth > 8) {
+            /* Hi byte */
+            unsigned char * const newpos =
+                decode(read_buffer, rb + chan * 2, width, width,
+                       outpam.depth * 2);
+            /* Lo byte */
+            decode(newpos, rb + chan * 2 + 1, width, width,
+                   outpam.depth * 2);
+        } else
+            decode(read_buffer, rb + chan, width, width, outpam.depth); 
+    }
+}
+
+
+
+static void
+getHeaderInfo(FILE *         const ifP,
+              unsigned int * const widthP,
+              unsigned int * const heightP,
+              unsigned int * const depthP,
+              bool *         const hasMatteP,
+              unsigned int * const chanBitsP,
+              short *        const storageType) {
+    
+    rlahdr hdr;
+    int width, height;
+
+    read_header(ifP, &hdr);
+
+    height = hdr.active_window.top - hdr.active_window.bottom + 1;
+    width  = hdr.active_window.right - hdr.active_window.left + 1;
+    if (width <=0)
+        pm_error("Invalid input image.  It says its width isn't positive");
+    if (height <=0)
+        pm_error("Invalid input image.  It says its height isn't positive");
+
+    *widthP  = width;
+    *heightP = height;
+
+    if (hdr.num_chan != 1 && hdr.num_chan != 3)
+        pm_error ("Input image has bad number of channels: %d.  "
+                  "Should be 1 or 3.",
+                  hdr.num_chan);
+
+    *depthP = hdr.chan_bits <= 8 ? 8 : 16;
+
+    *hasMatteP = (hdr.num_matte > 0);
+    *chanBitsP = hdr.chan_bits;
+}
+
+
+
+static void
+readOffsetArray(FILE *       const ifP,
+                int **       const offsetsP,
+                unsigned int const height) {
+
+    int * offsets;
+    unsigned int row;
+
+    MALLOCARRAY(offsets, height);
+    if (offsets == NULL)
+        pm_error("Unable to allocate memory for the offsets array");
+
+    for (row = 0; row < height; ++row) {
+        long l;
+        pm_readbiglong(ifP, &l);
+        offsets[row] = l;
+    }
+    *offsetsP = offsets;
+}
+
+
+
+static void
+destroyOffsetArray(int * const offsets) {
+
+    free(offsets);
+}
+
+
+
+static void
+readAndWriteRaster(FILE *             const ifP,
+                   const struct pam * const outpamP) {
+
+    unsigned char * rowBuffer;
+    tuple * tuplerow;
+    unsigned int row;
+
+    /* Hold one row of all image planes */
+    rowBuffer = calloc(1, width * outpamP->depth * 4);
+    if (rowBuffer == NULL)
+        pm_error("Unable to allocate memor for row buffer.");
+
+    tuplerow = pnm_allocpamrow(outpamP);
+
+    for (row = 0; row < height; ++row) {
+        unsigned int col;
+        unsigned char * rbP;
+
+        decode_row(ifP, row, rowBuffer);
+        for (col = 0, rbP = rowBuffer; col < width; ++col) {
+            unsigned int chan;
+            for (chan = 0; chan < outpamP->depth; ++chan) {
+                if (depth > 8) {
+                    tuplerow[col][chan] = 256 * rbP[0] + rbP[1];
+                    rbP += 2;
+                } else {
+                    tuplerow[col][chan] = *rbP;
+                    rbP += 1;
+                }
+            }
+        }
+        pnm_writepamrow(outpamP, tuplerow);
+    }
+    pnm_freepamrow(tuplerow);
+    free(rowBuffer);
+}
+
+
+
+int
+main(int    argc,
+     char * argv[]) {
+
+    const char * inputFileName;
+    FILE * ifP;
+
+    pnm_init(&argc, argv);
+
+    determineEndianness();
+
+    parseCommandLine(argc, argv, &inputFileName);
+
+    ifP = pm_openr_seekable(inputFileName);
+
+    getHeaderInfo(ifP, &width, &height, &depth, &has_matte,
+                  &chanBits, &storageType);
+
+    outpam.size   = outpam.len = sizeof (struct pam);
+    outpam.file   = stdout;
+    outpam.format = PAM_FORMAT;
+    outpam.height = height;
+    outpam.width  = width;
+    outpam.depth  = numChan + (has_matte ? 1 : 0);
+    outpam.maxval = (1 << (chanBits > 16 ? 
+                           (9 + (chanBits - 1) % 8)
+                                /* Take top 2 of 3 or 4 bytes */
+                           : chanBits)) - 1;
+
+    /* Most apps seem to assume 32 bit integer is really floating point */
+    if (chanBits == 32 || storageType == 4) {
+        is_float = TRUE;
+        outpam.maxval = 65535;
+        depth = 16;
+    }
+
+    outpam.bytes_per_sample = depth / 8;
+    strcpy(outpam.tuple_type, (numChan == 3 ? "RGB" : "GRAYSCALE"));
+    if (has_matte)
+        strcat(outpam.tuple_type, "A");
+
+    readOffsetArray(ifP, &offsets, height);
+
+    pnm_writepaminit(&outpam);
+
+    readAndWriteRaster(ifP, &outpam);
+
+    destroyOffsetArray(offsets);
+    
+    pm_close(ifP);
+
+    return 0; 
+}
diff --git a/converter/other/rletopnm.c b/converter/other/rletopnm.c
new file mode 100644
index 00000000..aaa86388
--- /dev/null
+++ b/converter/other/rletopnm.c
@@ -0,0 +1,497 @@
+/*
+ * This is derived from the file of the same name dated June 5, 1995,
+ * copied from the Army High Performance Computing Research Center's
+ * media-tools.tar.gz package, received from 
+ * http://www.arc.umn.edu/gvl-software/media-tools.tar.gz on 2000.04.13.
+ *
+ * This software is copyrighted as noted below.  It may be freely copied,
+ * modified, and redistributed, provided that the copyright notice is
+ * preserved on all copies.
+ *
+ * There is no warranty or other guarantee of fitness for this software,
+ * it is provided solely "as is".  Bug reports or fixes may be sent
+ * to the author, who may or may not act on them as he desires.
+ *
+ * You may not include this software in a program or other software product
+ * without supplying the source, or without informing the end-user that the
+ * source is available for no extra charge.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+/*
+ * rletopnm - A conversion program to convert from Utah's "rle" image format
+ *            to pbmplus ppm or pgm image formats.
+ *
+ * Author:      Wes Barris (wes@msc.edu)
+ *              AHPCRC
+ *              Minnesota Supercomputer Center, Inc.
+ * Date:        March 30, 1994
+ * Copyright (c) Minnesota Supercomputer Center 1994
+ * 
+ * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler 
+ *            warnings.  Added --alpha option.  Accept input on stdin
+ *
+ */
+
+#define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+/*-----------------------------------------------------------------------------
+ * System includes.
+ */
+#include <string.h>
+#include <stdio.h>
+#define NO_DECLARE_MALLOC
+#include <rle.h>
+
+#include "pnm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+
+#define HMSG if (headerDump) pm_message
+#define GRAYSCALE   001 /* 8 bits, no colormap */
+#define PSEUDOCOLOR 010 /* 8 bits, colormap */
+#define TRUECOLOR   011 /* 24 bits, colormap */
+#define DIRECTCOLOR 100 /* 24 bits, no colormap */
+#define RLE_MAXVAL 255
+/*
+ * Utah type declarations.
+ */
+rle_hdr     hdr;
+rle_map     *colormap;
+
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    char *input_filename;
+    unsigned int headerdump;
+    unsigned int verbose;
+    char *alpha_filename;
+    bool alpha_stdout;
+};
+
+
+
+/*
+ * Other declarations.
+ */
+int     visual, maplen;
+int     width, height;
+
+
+
+
+static void
+parseCommandLine(int argc, char ** argv,
+                   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
+   sometimes, one of these strings is actually just a suffix of an entry
+   in argv!
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;  /* malloc'ed */
+    optStruct3 opt;
+    unsigned int option_def_index;
+
+    unsigned int alphaoutSpec;
+
+    MALLOCARRAY(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3('h', "headerdump", OPT_FLAG,   
+            NULL,                      &cmdlineP->headerdump,     0);
+    OPTENT3('v', "verbose",    OPT_FLAG,   
+            NULL,                      &cmdlineP->verbose,        0);
+    OPTENT3(0,   "alphaout",   OPT_STRING, 
+            &cmdlineP->alpha_filename, &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);
+        /* Uses and sets argc, argv, and all of *cmdlineP. */
+
+    if (!alphaoutSpec)
+        cmdlineP->alpha_filename = NULL;
+
+    if (argc - 1 == 0)
+        cmdlineP->input_filename = NULL;  /* he wants stdin */
+    else if (argc - 1 == 1) {
+        if (STREQ(argv[1], "-"))
+            cmdlineP->input_filename = NULL;  /* he wants stdin */
+        else 
+            cmdlineP->input_filename = 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;
+    else 
+        cmdlineP->alpha_stdout = FALSE;
+}
+
+
+
+static void
+reportRleGetSetupError(int const rleGetSetupRc) {
+    
+    switch (rleGetSetupRc) {
+    case -1:
+        pm_error("According to the URT library, the input is not "
+                 "an RLE file.  rle_get_setup() failed.");
+        break;
+    case -2:
+        pm_error("Unable to get memory for the color map.  "
+                 "rle_get_setup() failed.");
+        break;
+    case -3:
+        pm_error("Input file is empty.  rle_get_setup() failed.");
+        break;
+    case -4:
+        pm_error("End of file in the middle of where the RLE header should "
+                 "be.  rle_get_setup() failed.");
+        break;
+    default:
+        pm_error("rle_get_setup() failed for an unknown reason");
+    }
+}
+
+
+/*-----------------------------------------------------------------------------
+ *                                                         Read the rle header.
+ */
+static void 
+read_rle_header(FILE * const ifp,
+                bool   const headerDump) {
+    int rc;
+    int  i;
+    hdr.rle_file = ifp;
+    rc = rle_get_setup(&hdr);
+    if (rc != 0)
+        reportRleGetSetupError(rc);
+
+    width = hdr.xmax - hdr.xmin + 1;
+    height = hdr.ymax - hdr.ymin + 1;
+    HMSG("Image size: %dx%d", width, height);
+    if (hdr.ncolors == 1 && hdr.ncmap == 3) {
+        visual = PSEUDOCOLOR;
+        colormap = hdr.cmap;
+        maplen = (1 << hdr.cmaplen);
+        HMSG("Mapped color image with a map of length %d.",
+                maplen);
+    }
+    else if (hdr.ncolors == 3 && hdr.ncmap == 0) {
+        visual = DIRECTCOLOR;
+        HMSG("24 bit color image, no colormap.");
+    }
+    else if (hdr.ncolors == 3 && hdr.ncmap == 3) {
+        visual = TRUECOLOR;
+        colormap = hdr.cmap;
+        maplen = (1 << hdr.cmaplen);
+        HMSG(
+                "24 bit color image with color map of length %d" ,maplen);
+    }
+    else if (hdr.ncolors == 1 && hdr.ncmap == 0) {
+        visual = GRAYSCALE;
+        HMSG("Grayscale image.");
+    }
+    else {
+        fprintf(stderr,
+                "ncolors = %d, ncmap = %d, I don't know how to handle this!",
+                hdr.ncolors, hdr.ncmap);
+        exit(-1);
+    }
+    if (hdr.alpha == 0) {
+        HMSG("No alpha channel.");
+    } else if (hdr.alpha == 1) {
+        HMSG("Alpha channel exists!");
+    } else {
+        fprintf(stderr, "alpha = %d, I don't know how to handle this!\n",
+                hdr.alpha);
+        exit(-1);
+    }
+    switch (hdr.background) {
+    case 0:
+        HMSG("Use all pixels, ignore background color.");
+        break;
+    case 1:
+        HMSG("Use only non-background pixels, ignore background color.");
+        break;
+    case 2:
+        HMSG("Use only non-background pixels, "
+             "clear to background color (default).");
+        break;
+    default:
+        HMSG("Unknown background flag!");
+        break;
+    }
+    if (hdr.background == 2)
+        for (i = 0; i < hdr.ncolors; i++)
+            HMSG(" %d", hdr.bg_color[i]);
+    if (hdr.ncolors == 1 && hdr.ncmap == 3) {
+        HMSG(" (%d %d %d)",
+                hdr.cmap[hdr.bg_color[0]]>>8,
+                hdr.cmap[hdr.bg_color[0]+256]>>8,
+                hdr.cmap[hdr.bg_color[0]+512]>>8);
+    }
+    else if (hdr.ncolors == 3 && hdr.ncmap == 3) {
+        HMSG(" (%d %d %d)",
+                hdr.cmap[hdr.bg_color[0]]>>8,
+                hdr.cmap[hdr.bg_color[1]+256]>>8,
+                hdr.cmap[hdr.bg_color[2]+512]>>8);
+    }
+    if (hdr.comments)
+        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) {
+
+    rle_pixel ***scanlines, **scanline;
+    pixval r, g, b;
+    pixel *pixelrow;
+    gray *alpharow;
+   
+    int scan, x, y;
+    /*
+     *  Allocate some stuff.
+     */
+    pixelrow = ppm_allocrow(width);
+    alpharow = pgm_allocrow(width);
+
+    MALLOCARRAY(scanlines, height);
+    RLE_CHECK_ALLOC( hdr.cmd, scanlines, "scanline pointers" );
+
+    for ( scan = 0; scan < height; scan++ )
+        RLE_CHECK_ALLOC( hdr.cmd, (rle_row_alloc(&hdr, &scanlines[scan]) >= 0),
+                         "pixel memory" );
+    /*
+     * Loop through those scan lines.
+     */
+    for (scan = 0; scan < height; scan++)
+        y = rle_getrow(&hdr, scanlines[height - scan - 1]);
+    for (scan = 0; scan < height; scan++) {
+        scanline = scanlines[scan];
+        switch (visual) {
+        case GRAYSCALE:    /* 8 bits without colormap */
+            for (x = 0; x < width; x++) {
+                r = scanline[0][x];
+                g = scanline[0][x];
+                b = scanline[0][x];
+                PPM_ASSIGN(pixelrow[x], r, g, b);
+                if (hdr.alpha)
+                    alpharow[x] = scanline[-1][x];
+                else 
+                    alpharow[x] = 0;
+            }
+            break;
+        case TRUECOLOR:    /* 24 bits with colormap */
+            for (x = 0; x < width; x++) {
+                r = colormap[scanline[0][x]]>>8;
+                g = colormap[scanline[1][x]+256]>>8;
+                b = colormap[scanline[2][x]+512]>>8;
+                PPM_ASSIGN(pixelrow[x], r, g, b);
+                if (hdr.alpha) 
+                    alpharow[x] = colormap[scanline[-1][x]];
+                else
+                    alpharow[x] = 0;
+            }
+            break;
+        case DIRECTCOLOR:  /* 24 bits without colormap */
+            for (x = 0; x < width; x++) {
+                r = scanline[0][x];
+                g = scanline[1][x];
+                b = scanline[2][x];
+                PPM_ASSIGN(pixelrow[x], r, g, b);
+                if (hdr.alpha)
+                    alpharow[x] = scanline[-1][x];
+                else
+                    alpharow[x] = 0;
+            }
+            break;
+        case PSEUDOCOLOR:  /* 8 bits with colormap */
+            for (x = 0; x < width; x++) {
+                r = colormap[scanline[0][x]]>>8;
+                g = colormap[scanline[0][x]+256]>>8;
+                b = colormap[scanline[0][x]+512]>>8;
+                PPM_ASSIGN(pixelrow[x], r, g, b);
+                if (hdr.alpha) 
+                    alpharow[x] = colormap[scanline[-1][x]];
+                else
+                    alpharow[x] = 0;
+            }
+            break;
+        default:
+            break;
+        }
+        /*
+         * 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);
+
+    } /* end of for scan = 0 to height */
+
+    /* Free scanline memory. */
+    for ( scan = 0; scan < height; scan++ )
+        rle_row_free( &hdr, scanlines[scan] );
+    free( scanlines );
+    ppm_freerow(pixelrow);
+    pgm_freerow(alpharow);
+}
+
+
+
+static void 
+write_pgm_data(FILE * const imageout_file,
+               FILE * const alpha_file) {
+/*----------------------------------------------------------------------------
+   Write the PGM image data
+-----------------------------------------------------------------------------*/
+    rle_pixel ***scanlines, **scanline;
+    gray * pixelrow;
+    gray * alpharow;
+    int scan;
+    int y;
+    /*
+     *  Allocate some stuff.
+     */
+    pixelrow = pgm_allocrow(width);
+    alpharow = pgm_allocrow(width);
+
+    MALLOCARRAY(scanlines, height);
+    RLE_CHECK_ALLOC( hdr.cmd, scanlines, "scanline pointers" );
+
+    for (scan = 0; scan < height; ++scan)
+        RLE_CHECK_ALLOC(hdr.cmd, (rle_row_alloc(&hdr, &scanlines[scan]) >= 0),
+                        "pixel memory" );
+    /*
+     * Loop through those scan lines.
+     */
+    for (scan = 0; scan < height; ++scan)
+        y = rle_getrow(&hdr, scanlines[height - scan - 1]);
+
+    for (scan = 0; scan < height; ++scan) {
+        int x;
+        scanline = scanlines[scan];
+        for (x = 0; x < width; ++x) {
+            pixelrow[x] = scanline[0][x];
+            if (hdr.alpha) 
+                alpharow[x] = scanline[1][x];
+            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);
+
+        }   /* end of for scan = 0 to height */
+
+    /* Free scanline memory. */
+    for (scan = 0; scan < height; ++scan)
+        rle_row_free(&hdr, scanlines[scan]);
+    free(scanlines);
+    pgm_freerow(pixelrow);
+    pgm_freerow(alpharow);
+}
+
+
+
+/*-----------------------------------------------------------------------------
+ *                               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;
+
+    pnm_init( &argc, argv );
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    if ( cmdline.input_filename != NULL ) 
+        ifp = pm_openr( cmdline.input_filename );
+    else
+        ifp = stdin;
+
+    if (cmdline.alpha_stdout)
+        alpha_file = stdout;
+    else if (cmdline.alpha_filename == NULL) 
+        alpha_file = NULL;
+    else {
+        alpha_file = pm_openw(cmdline.alpha_filename);
+    }
+
+    if (cmdline.alpha_stdout) 
+        imageout_file = NULL;
+    else
+        imageout_file = stdout;
+
+
+    /*
+     * Open the file.
+     */
+    /* Initialize header. */
+    hdr = *rle_hdr_init( (rle_hdr *)NULL );
+    rle_names( &hdr, cmd_name( argv ), fname, 0 );
+
+    /*
+     * Read the rle file header.
+     */
+    read_rle_header(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);
+
+    /*
+     * Write the pnm file header.
+     */
+    switch (visual) {
+    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);
+        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);
+        break;
+    }
+   
+    pm_close(ifp);
+    if (imageout_file) 
+        pm_close( imageout_file );
+    if (alpha_file)
+        pm_close( alpha_file );
+
+    return 0;
+}
diff --git a/converter/other/sgi.h b/converter/other/sgi.h
new file mode 100644
index 00000000..3700d356
--- /dev/null
+++ b/converter/other/sgi.h
@@ -0,0 +1,33 @@
+#ifndef SGI_H_INCLUDED
+#define SGI_H_INCLUDED
+
+/* sgi.h - definitions for SGI format */
+
+typedef struct {
+    short           magic;
+    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 */
+                    ysize,          /* height in pixels */
+                    zsize;          /* # of channels; B/W=1, RGB=3, RGBA=4 */
+    long            pixmin, pixmax; /* min/max pixel values */
+    char            dummy1[4];
+    char            name[80];
+    long            colormap;
+    char            dummy2[404];
+} Header;
+#define HeaderSize  512
+
+#define SGI_MAGIC           (short)474
+
+#define STORAGE_VERBATIM    0
+#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 */
+
+#endif
+
diff --git a/converter/other/sgitopnm.c b/converter/other/sgitopnm.c
new file mode 100644
index 00000000..0d26bb9c
--- /dev/null
+++ b/converter/other/sgitopnm.c
@@ -0,0 +1,463 @@
+/* sgitopnm.c - read an SGI image and and produce a portable anymap
+**
+** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
+**
+** Based on the SGI image description v0.9 by Paul Haeberli (paul@sgi.comp)
+** Available via ftp from sgi.com:graphics/SGIIMAGESPEC
+**
+** 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.
+**
+** 29Jan94: first version
+** 08Feb94: minor bugfix
+** 29Jul00: added -channel option (smar@reptiles.org)
+*/
+#include "pnm.h"
+#include "sgi.h"
+#include "mallocvar.h"
+#ifndef VMS
+#include <unistd.h>
+#endif
+
+/*#define DEBUG*/
+
+#ifndef SEEK_SET
+#define SEEK_SET    0
+#endif
+
+
+/* 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 short verbose = 0;
+
+
+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;
+    }
+
+    if( argn < argc ) {
+        ifp = pm_openr( argv[argn] );
+        argn++;
+    }
+    else
+        ifp = stdin;
+
+    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);
+
+    exit(0);
+}
+
+
+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 )
+        pm_error("bad magic number - not an SGI image");
+    if( head->storage != STORAGE_VERBATIM && head->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 )
+        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 ) {
+        case 1:
+            head->ysize = 1;
+            break;
+        case 2:
+            head->zsize = 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( 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
+    }
+
+    return head;
+}
+
+
+static TabEntry *
+read_table(ifp, tablen)
+    FILE *ifp;
+    int tablen;
+{
+    TabEntry *table;
+    int i;
+
+    MALLOCARRAY_NOFAIL(table, tablen);
+
+#ifdef DEBUG
+    pm_message("reading offset table");
+#endif
+
+    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);
+
+    return table;
+}
+
+
+
+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;
+        MALLOCARRAY_NOFAIL(image, head->ysize);
+    }
+    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;
+
+            sgi_index = channel * head->ysize + row;
+            iindex = (ochan < 0) ? sgi_index : row;
+            if (ochan < 0 || ochan == 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 ) 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;
+
+    if( head->zsize == 1 || channel >= 0) {
+        pm_message("writing PGM image");
+        format = PGM_TYPE;
+    }
+    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_ASSIGN1(pnmrow[col], image[row][col] - sub);
+            else {
+                pixval r, g, b;
+                r = image[row][col] - sub;
+                g = image[head->ysize + row][col] - sub;
+                b = image[2* head->ysize + row][col] - sub;
+                PPM_ASSIGN(pnmrow[col], r, g, b);
+            }
+        }
+        pnm_writepnmrow(stdout, pnmrow, head->xsize, (xelval)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;
+}
+
+static long
+get_big_long(ifp)
+    FILE *ifp;
+{
+    long l;
+
+    if( pm_readbiglong(ifp, &l) == -1 )
+        readerr(ifp);
+
+    return l;
+}
+
+static unsigned char
+get_byte(ifp)
+    FILE* ifp;
+{
+    int i;
+
+    i = getc(ifp);
+    if( i == EOF )
+        readerr(ifp);
+
+    return (unsigned char) i;
+}
+
+
+static void
+readerr(f)
+    FILE *f;
+{
+    if( ferror(f) )
+        pm_error("read error");
+    else
+        pm_error("premature EOF");
+}
+
+
+static void
+read_bytes(ifp, n, buf)
+    FILE *ifp;
+    int n;
+    char *buf;
+{
+    int r;
+
+    r = fread((void *)buf, 1, n, ifp);
+    if( r != n )
+        readerr(ifp);
+}
+
+
+static short
+get_byte_as_short(ifp)
+    FILE *ifp;
+{
+    return (short)get_byte(ifp);
+}
+
+
+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/sirtopnm.c b/converter/other/sirtopnm.c
new file mode 100644
index 00000000..fafcc913
--- /dev/null
+++ b/converter/other/sirtopnm.c
@@ -0,0 +1,95 @@
+/* sirtopnm.c - read a Solitaire Image Recorder file and write a portable anymap
+**
+** Copyright (C) 1991 by Marvin Landis.
+**
+** 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 "pnm.h"
+
+int main( argc, argv )
+int argc;
+char* argv[];
+{
+    FILE *ifp;
+    xel *xelrow, *xP;
+    unsigned char *sirarray;
+    int rows, cols, row, format, picsize, planesize;
+    register int col, i;
+    short info;
+
+    pnm_init( &argc, argv );
+
+    if ( argc > 2 )
+	pm_usage( "[sirfile]" );
+
+    if ( argc == 2 )
+	ifp = pm_openr( argv[1] );
+    else
+	ifp = stdin;
+
+    pm_readlittleshort( ifp, &info );
+    if ( info != 0x3a4f)
+	pm_error( "Input file is not a Solitaire file" );
+    pm_readlittleshort( ifp, &info );
+    pm_readlittleshort( ifp, &info );
+    if ( info == 17 )
+    {
+	format = PGM_TYPE;
+    }
+    else if ( info == 11 )
+    {
+	format = PPM_TYPE;
+    }
+    else
+	pm_error( "Input is not MGI TYPE 11 or MGI TYPE 17" );
+    pm_readlittleshort( ifp, &info );
+    cols = (int) ( info );
+    pm_readlittleshort( ifp, &info );
+    rows = (int) ( info );
+    for ( i = 1; i < 1531; i++ )
+	pm_readlittleshort( ifp, &info );
+
+    pnm_writepnminit( stdout, cols, rows, 255, format, 0 );
+    xelrow = pnm_allocrow( cols );
+    switch ( PNM_FORMAT_TYPE(format) )
+    {
+	case PGM_TYPE:
+            pm_message( "Writing a PGM file" );
+	    for ( row = 0; row < rows; ++row )
+	    {
+	        for ( col = 0, xP = xelrow; col < cols; col++, xP++ )
+	        	PNM_ASSIGN1( *xP, fgetc( ifp ) );
+	        pnm_writepnmrow( stdout, xelrow, cols, 255, format, 0 );
+	    }
+	    break;
+	case PPM_TYPE:
+	    picsize = cols * rows * 3;
+	    planesize = cols * rows;
+            if ( !( sirarray = (unsigned char*) malloc( picsize ) ) ) 
+	        pm_error( "Not enough memory to load SIR file" );
+	    if ( fread( sirarray, 1, picsize, ifp ) != picsize )
+	        pm_error( "Error reading SIR file" );
+            pm_message( "Writing a PPM file" );
+            for ( row = 0; row < rows; row++ )
+	    {
+	        for ( col = 0, xP = xelrow; col < cols; col++, xP++ )
+        	    PPM_ASSIGN( *xP, sirarray[row*cols+col],
+				 sirarray[planesize + (row*cols+col)],
+				 sirarray[2*planesize + (row*cols+col)] );
+                pnm_writepnmrow( stdout, xelrow, cols, 255, format, 0 );
+	    }
+	    break;
+	default:
+	    pm_error( "Shouldn't happen" );
+    }
+
+    pm_close( ifp );
+
+    exit( 0 );
+}
diff --git a/converter/other/svgtopam.c b/converter/other/svgtopam.c
new file mode 100644
index 00000000..268515ad
--- /dev/null
+++ b/converter/other/svgtopam.c
@@ -0,0 +1,940 @@
+/*============================================================================
+                               svgtopam
+==============================================================================
+  This is not useful today.  It is merely a stub from which someone who
+  cares about SVG can build a full converter.
+
+  The framework is all there; it should be just a matter of coding to
+  add each of the SVG features to it.
+
+  Today, the program works fine on an image that consists solely of
+  <path> elements, which use only the "M", "L", and "z" commands.
+
+  By Bryan Henderson, San Jose, California.  May 2006
+
+  Contributed to the public domain.
+============================================================================*/
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <libxml/xmlreader.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+#include "ppm.h"
+#include "ppmdraw.h"
+
+
+static bool traceDraw;
+
+struct cmdlineInfo {
+    const char * inputFileName;
+    unsigned int trace;
+};
+
+
+
+static void 
+parseCommandLine(int argc, 
+                 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 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, "trace",     OPT_FLAG,   NULL,                  
+            &cmdlineP->trace,       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 );
+    /* 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 (%u).  The only non-option argument "
+                     "is the input file name.", argc-1);
+    }
+}
+
+
+
+/*============================================================================
+   Wrappers for libxml2 routines.
+
+   The difference is that these use conventional C data types and have
+   shorter names.
+=============================================================================*/
+
+static const char *
+getAttribute(xmlTextReaderPtr const xmlReaderP,
+             const char *     const attributeName) {
+
+    return (const char *)
+        xmlTextReaderGetAttribute(xmlReaderP, (const xmlChar *)attributeName);
+}
+
+
+
+static const char *
+currentNodeName(xmlTextReaderPtr const xmlReaderP) {
+
+    return (const char *)xmlTextReaderConstName(xmlReaderP);
+}
+
+
+
+/*===========================================================================*/
+
+#define OUTPUT_MAXVAL 255
+
+typedef struct {
+    unsigned int width;
+    unsigned int height;
+    pixel ** pixels;
+    pixval maxval;
+} canvas;
+
+typedef struct {
+    pixel fillColor;
+} style;
+
+
+
+typedef struct {
+    const char * pathText;
+        /* This is e.g. "M0 0 L1 1 L9 8 Z" */
+    style        style;
+        /* This is the style as given by a 'style' attribute of <path> */
+    unsigned int pathTextLength;
+        /* This is the length in characters of 'pathText'.  It's redundant
+           with 'pathText' and exists for convenience.
+        */
+} path;
+
+static void
+createPath(const char * const pathText,
+           style        const style,
+           path **      const pathPP) {
+/*----------------------------------------------------------------------------
+   Create a path as described by a <path> element whose "style" attribute
+   indicates style 'style' and whose "d" attribute indicates path data
+   'pathText'.
+-----------------------------------------------------------------------------*/
+    bool error;
+    path * pathP;
+    
+    MALLOCVAR(pathP);
+    if (pathP == NULL)
+        error = TRUE;
+    else {
+        pathP->style = style;
+
+        pathP->pathText = strdup(pathText);
+        if (pathP->pathText == NULL)
+            error = TRUE;
+        else {
+            pathP->pathTextLength = strlen(pathP->pathText);
+
+            error = FALSE;
+        }
+        if (error)
+            free(pathP);
+    }
+    if (error )
+        *pathPP = NULL;
+    else
+        *pathPP = pathP;
+}
+
+
+
+static void
+destroyPath(path * const pathP) {
+    
+    assert(pathP->pathTextLength == strlen(pathP->pathText));
+
+    strfree(pathP->pathText);
+
+    free(pathP);
+}
+
+
+
+typedef struct {
+    uint x;
+    uint y;
+} point;
+
+static point
+makePoint(uint const x,
+          uint const y) {
+
+    point p;
+    
+    p.x = x;
+    p.y = y;
+    
+    return p;
+}
+
+
+
+typedef enum {
+    PATH_MOVETO,
+    PATH_LINETO,
+    PATH_CLOSEPATH,
+    PATH_CUBIC
+} pathCommandVerb;
+
+typedef struct {
+    point dest;
+} pathMovetoArgs;
+
+typedef struct {
+    /* Draw a line segment from current point to 'dest' */
+    point dest;
+} pathLinetoArgs;
+
+typedef struct {
+    /* Draw a cubic spline from current point to 'dest' with control points
+       'ctl1' at the beginning of the curve and 'ctl2' at the end.
+
+       I.e. it's a section of a cubic curve which passes through the
+       current point and 'dest' and whose slope at the current point
+       is that of the line through the current point and 'ctl1' and
+       whose slope at 'dest' is that of the line through 'dest' and
+       'ctl2';
+
+       A cubic curve is a plot of a polynomial equation of degree 3
+       (or less, for our purposes).
+    */
+    point dest;
+    point ctl1;
+    point ctl2;
+} pathCubicArgs;
+
+typedef struct {
+    pathCommandVerb verb;
+    union {
+        pathMovetoArgs moveto;
+        pathLinetoArgs lineto;
+        pathCubicArgs  cubic;
+    } args;
+} pathCommand;
+
+
+
+typedef struct {
+/*----------------------------------------------------------------------------
+   This is an object for reading through a path from beginning to end.
+-----------------------------------------------------------------------------*/
+    path *       pathP;
+    unsigned int cursor;
+} pathReader;
+
+static void
+createPathReader(path *        const pathP,
+                 pathReader ** const pathReaderPP) {
+
+    pathReader * pathReaderP;
+
+    MALLOCVAR_NOFAIL(pathReaderP);
+
+    pathReaderP->pathP = pathP;
+    pathReaderP->cursor = 0;
+
+    *pathReaderPP = pathReaderP;
+}
+
+static void
+destroyPathReader(pathReader * const pathReaderP) {
+    free(pathReaderP);
+}
+
+
+
+static void
+skipWhiteSpace(pathReader * const pathReaderP) {
+/*----------------------------------------------------------------------------
+   Move the cursor over any white space where it now points.
+-----------------------------------------------------------------------------*/
+    const path * const pathP = pathReaderP->pathP;
+
+    while (isspace(pathP->pathText[pathReaderP->cursor]) &&
+           pathReaderP->cursor < pathP->pathTextLength)
+        ++pathReaderP->cursor;
+}
+
+
+
+static void
+getNumber(pathReader * const pathReaderP,
+          uint *       const numberP) {
+
+    const path * const pathP          = pathReaderP->pathP;
+    const char * const pathText       = pathP->pathText;
+    size_t       const pathTextLength = pathP->pathTextLength;
+
+    assert(!isspace(pathText[pathReaderP->cursor]));
+
+    if (pathReaderP->cursor >= pathTextLength)
+        pm_error("Path description ends where a number was expected.");
+    else {
+        uint number;
+
+        number = 0;  /* initial value */
+
+        while (pathReaderP->cursor < pathTextLength &&
+               isdigit(pathText[pathReaderP->cursor])) {
+            number = 10 * number + (pathText[pathReaderP->cursor] - '0');
+            ++pathReaderP->cursor;
+        }
+        *numberP = number;
+    }
+}
+
+
+
+static void
+getNextCommand(pathReader *  const pathReaderP,
+               pathCommand * const pathCommandP,
+               bool *        const endOfPathP) {
+
+    const path * const pathP          = pathReaderP->pathP;
+    const char * const pathText       = pathP->pathText;
+    size_t       const pathTextLength = pathP->pathTextLength;
+
+    skipWhiteSpace(pathReaderP);
+
+    if (pathReaderP->cursor >= pathTextLength)
+        *endOfPathP = true;
+    else {
+        switch (pathText[pathReaderP->cursor++]) {
+        case 'M':
+            pathCommandP->verb = PATH_MOVETO;
+            skipWhiteSpace(pathReaderP);
+            getNumber(pathReaderP, &pathCommandP->args.moveto.dest.x);
+            skipWhiteSpace(pathReaderP);
+            getNumber(pathReaderP, &pathCommandP->args.moveto.dest.y);
+            break;
+        case 'L':
+            pathCommandP->verb = PATH_LINETO;
+            skipWhiteSpace(pathReaderP);
+            getNumber(pathReaderP, &pathCommandP->args.lineto.dest.x);
+            skipWhiteSpace(pathReaderP);
+            getNumber(pathReaderP, &pathCommandP->args.lineto.dest.y);
+            break;
+        case 'C':
+            pathCommandP->verb = PATH_CUBIC;
+            skipWhiteSpace(pathReaderP);
+            getNumber(pathReaderP, &pathCommandP->args.cubic.ctl1.x);
+            skipWhiteSpace(pathReaderP);
+            getNumber(pathReaderP, &pathCommandP->args.cubic.ctl1.y);
+            skipWhiteSpace(pathReaderP);
+            getNumber(pathReaderP, &pathCommandP->args.cubic.ctl2.x);
+            skipWhiteSpace(pathReaderP);
+            getNumber(pathReaderP, &pathCommandP->args.cubic.ctl2.y);
+            skipWhiteSpace(pathReaderP);
+            getNumber(pathReaderP, &pathCommandP->args.cubic.dest.x);
+            skipWhiteSpace(pathReaderP);
+            getNumber(pathReaderP, &pathCommandP->args.cubic.dest.y);
+            break;
+        case 'z':
+            pathCommandP->verb = PATH_CLOSEPATH;
+            break;
+        default:
+            pm_error("Unrecognized command in <path>: '%c'",
+                     pathText[pathReaderP->cursor++]);
+        }
+    }
+}
+
+
+static void
+outlineObject(path *           const pathP,
+              struct fillobj * const fillObjP) {
+/*----------------------------------------------------------------------------
+  Create a fill object, which contains and outline of the object and
+  can be used with ppmd_fill() to fill the figure.  The outline is as
+  described by *pathP.
+-----------------------------------------------------------------------------*/
+    pathReader * pathReaderP;
+    bool endOfPath;
+    point currentPos;
+    point subpathStart;
+        /* Point at which the current subpath starts */
+
+    endOfPath = false;
+    subpathStart = makePoint(0,0);
+    currentPos = subpathStart;
+
+    createPathReader(pathP, &pathReaderP);
+
+    while (!endOfPath) {
+        pathCommand pathCommand;
+        getNextCommand(pathReaderP, &pathCommand, &endOfPath);
+        if (!endOfPath) {
+            switch (pathCommand.verb) {
+            case PATH_MOVETO:
+                if (traceDraw)
+                    pm_message("Moving to (%u, %u)",
+                               pathCommand.args.moveto.dest.x,
+                               pathCommand.args.moveto.dest.y);
+                subpathStart = pathCommand.args.moveto.dest;
+                currentPos = subpathStart;
+                break;
+            case PATH_LINETO: {
+                point const dest = pathCommand.args.lineto.dest;
+                if (traceDraw)
+                    pm_message("Lining to (%u, %u)", dest.x, dest.y);
+                ppmd_line(NULL, 0, 0, 0,
+                          currentPos.x, currentPos.y, dest.x, dest.y,
+                          ppmd_fill_drawproc, fillObjP);
+                currentPos = dest;
+            } break;
+            case PATH_CLOSEPATH:
+                if (traceDraw)
+                    pm_message("Closing.");
+                ppmd_line(NULL, 0, 0, 0,
+                          currentPos.x, currentPos.y,
+                          subpathStart.x, subpathStart.y,
+                          ppmd_fill_drawproc, fillObjP);
+                currentPos = subpathStart;
+                break;
+            case PATH_CUBIC: {
+                point const dest = pathCommand.args.cubic.dest;
+                point const ctl1 = pathCommand.args.cubic.ctl1;
+                point const ctl2 = pathCommand.args.cubic.ctl2;
+                if (traceDraw)
+                    pm_message("Doing cubic spline to (%u, %u)",
+                               dest.x, dest.y);
+                /* We need to write ppmd_spline4() */
+                ppmd_spline4(NULL, 0, 0, 0,
+                             currentPos.x, currentPos.y,
+                             ctl1.x, ctl1.y,
+                             ctl2.x, ctl2.y,
+                             dest.x, dest.y,
+                             ppmd_fill_drawproc, fillObjP);
+                currentPos = dest;
+            } break;
+            }
+        }
+    }
+    destroyPathReader(pathReaderP);
+}
+
+
+
+static void
+drawPath(canvas * const canvasP,
+         path *   const pathP) {
+/*----------------------------------------------------------------------------
+   Draw the path 'pathP' on the canvas 'canvasP'.
+-----------------------------------------------------------------------------*/
+    struct fillobj * fillObjP;
+
+    if (traceDraw)
+        pm_message("Drawing path '%s' with fill color (%u, %u, %u)",
+                   pathP->pathText,
+                   pathP->style.fillColor.r,
+                   pathP->style.fillColor.g,
+                   pathP->style.fillColor.b);
+
+    fillObjP = ppmd_fill_create();
+
+    outlineObject(pathP, fillObjP);
+
+    ppmd_fill(canvasP->pixels, canvasP->width, canvasP->height,
+              canvasP->maxval,
+              fillObjP, 
+              PPMD_NULLDRAWPROC, &pathP->style.fillColor);
+
+    ppmd_fill_destroy(fillObjP);
+}
+
+
+
+static style
+interpretStyle(const char * const styleAttr) {
+
+    style style;
+
+    char * buffer;
+
+    char * p;
+
+    buffer = strdup(styleAttr);
+    if (buffer == NULL)
+        pm_error("Could not get memory for a buffer to parse style attribute");
+
+    p = &buffer[0];
+
+    while (p) {
+        const char * const token = strsepN(&p, ";");
+        const char * strippedToken;
+        const char * p;
+        char * buffer;
+
+        for (p = &token[0]; isspace(*p); ++p);
+        
+        strippedToken = p;
+
+        buffer = strdup(strippedToken);
+
+        if (strlen(strippedToken) > 0) {
+            char * const colonPos = strchr(buffer, ':');
+
+            if (colonPos == NULL)
+                pm_error("There is no colon in the attribute specification "
+                         "'%s' in the 'style' attribute of a <path> "
+                         "element.", strippedToken);
+            else {
+                const char * const value = colonPos + 1;
+                const char * const name  = &buffer[0];
+                
+                *colonPos = '\0';
+
+                if (streq(name, "fill")) {
+                    style.fillColor = ppm_parsecolor(value, OUTPUT_MAXVAL);
+                } else if (streq(name, "stroke")) {
+                    if (!streq(value, "none"))
+                        pm_error("Value of 'stroke' attribute in the 'style' "
+                                 "attribute of a <path> element is '%s'.  We "
+                                 "understand only 'none'", value);
+                } else
+                    pm_error("Unrecognized attribute '%s' "
+                             "in the 'style' attribute "
+                             "of a <path> element", name);
+            }
+        }
+        free(buffer);
+    }
+
+    free(buffer);
+
+    return style;
+}
+
+
+static void
+getPathAttributes(xmlTextReaderPtr const xmlReaderP,
+                  style *          const styleP,
+                  const char **    const pathP) {
+
+    const char * const style = getAttribute(xmlReaderP, "style");
+    const char * const d     = getAttribute(xmlReaderP, "d");
+
+    *styleP = interpretStyle(style);
+    *pathP = d;
+}
+
+
+
+static void
+processSubPathNode(xmlTextReaderPtr const xmlReaderP,
+                   bool *           const endOfPathP) {
+
+    xmlReaderTypes const nodeType  = xmlTextReaderNodeType(xmlReaderP);
+
+    *endOfPathP = FALSE;  /* initial assumption */
+
+    switch (nodeType) {
+    case XML_READER_TYPE_ELEMENT:
+        pm_error("<path> contains a <%s> element.  <path> should have "
+                 "no contents", currentNodeName(xmlReaderP));
+        break;
+    case XML_READER_TYPE_END_ELEMENT: {
+        const char * nodeName = currentNodeName(xmlReaderP);
+        if (streq(nodeName, "path"))
+            *endOfPathP = TRUE;
+        else
+            pm_error("</%s> found where </path> expected", nodeName);
+        } break;
+    default:
+        /* Just ignore whatever this is.  Contents of <path> are
+           meaningless; all the information is in the attributes 
+        */
+        break;
+    }
+}
+
+
+
+static void
+processPathElement(xmlTextReaderPtr const xmlReaderP,
+                   canvas *         const canvasP) {
+
+    style style;
+    const char * pathData;
+    path * pathP;
+    bool endOfPath;
+
+    assert(xmlTextReaderNodeType(xmlReaderP) == XML_READER_TYPE_ELEMENT);
+    assert(streq(currentNodeName(xmlReaderP), "path"));
+
+    getPathAttributes(xmlReaderP, &style, &pathData);
+
+    createPath(pathData, style, &pathP);
+
+    if (pathP) {
+        drawPath(canvasP, pathP);
+        destroyPath(pathP);
+    }
+
+    endOfPath = xmlTextReaderIsEmptyElement(xmlReaderP);
+
+    while (!endOfPath) {
+        int rc;
+
+        rc = xmlTextReaderRead(xmlReaderP);
+        
+        switch (rc) {
+        case 1:
+            processSubPathNode(xmlReaderP, &endOfPath);
+            break;
+        case 0:
+            pm_error("Input file ends in the middle of a <path>");
+            break;
+        default:
+            pm_error("xmlTextReaderRead() failed, rc=%d", rc);
+        }
+    }
+}
+
+
+
+static void
+stringToUint(const char *   const string,
+             unsigned int * const uintP,
+             const char **  const errorP) {
+
+    /* TODO: move this to nstring.c */
+
+    if (strlen(string) == 0)
+        asprintfN(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);
+        else
+            *errorP = NULL;
+    }
+}
+
+
+
+static void
+getSvgAttributes(xmlTextReaderPtr const xmlReaderP,
+                 unsigned int *   const colsP,
+                 unsigned int *   const rowsP) {
+
+    const char * const width  = getAttribute(xmlReaderP, "width");
+    const char * const height = getAttribute(xmlReaderP, "height");
+
+    const char * error;
+
+    stringToUint(width, colsP, &error);
+    if (error) {
+        pm_error("'width' attribute of <svg> has invalid value.  %s", error);
+        strfree(error);
+    }
+    stringToUint(height, rowsP, &error);
+    if (error) {
+        pm_error("'height' attribute of <svg> has invalid value.  %s", error);
+        strfree(error);
+    }
+}
+
+
+
+static void
+processSubSvgElement(xmlTextReaderPtr const xmlReaderP,
+                     canvas *         const canvasP) {
+
+    const char * const nodeName = currentNodeName(xmlReaderP);
+
+    assert(xmlTextReaderNodeType(xmlReaderP) == XML_READER_TYPE_ELEMENT);
+    
+    if (streq(nodeName, "path"))
+        processPathElement(xmlReaderP, canvasP);
+    else
+        pm_error("This image contains a <%s> element.  This program "
+                 "understands only <path>!", nodeName);
+}
+
+
+
+static void
+processSubSvgNode(xmlTextReaderPtr const xmlReaderP,
+                  canvas *         const canvasP,
+                  bool *           const endOfSvgP) {
+
+    xmlReaderTypes const nodeType = xmlTextReaderNodeType(xmlReaderP);
+
+    *endOfSvgP = FALSE;  /* initial assumption */
+
+    switch (nodeType) {
+    case XML_READER_TYPE_ELEMENT:
+        processSubSvgElement(xmlReaderP, canvasP);
+        break;
+    case XML_READER_TYPE_END_ELEMENT: {
+        const char * const nodeName = currentNodeName(xmlReaderP);
+        if (streq(nodeName, "svg"))
+            *endOfSvgP = TRUE;
+        else
+            pm_error("</%s> found where </svg> expected", nodeName);
+    } break;
+    default:
+        /* Just ignore whatever this is */
+        break;
+    }
+}
+
+
+
+static void
+createCanvas(unsigned int const width,
+             unsigned int const height,
+             pixval       const maxval,
+             canvas **    const canvasPP) {
+
+    canvas * canvasP;
+
+    MALLOCVAR_NOFAIL(canvasP);
+
+    canvasP->width  = width;
+    canvasP->height = height;
+    canvasP->pixels = ppm_allocarray(width, height);
+    canvasP->maxval = maxval;
+
+    *canvasPP = canvasP;
+}
+
+
+
+static void
+destroyCanvas(canvas * const canvasP) {
+
+    ppm_freearray(canvasP->pixels, canvasP->height);
+
+    free(canvasP);
+}
+
+
+
+static void
+writePam(FILE *   const ofP,
+         canvas * const canvasP) {
+
+    unsigned int row;
+    struct pam pam;
+    tuple * tuplerow;
+
+    pam.size             = sizeof(pam);
+    pam.len              = PAM_STRUCT_SIZE(tuple_type);
+    pam.file             = ofP;
+    pam.format           = PAM_FORMAT;
+    pam.plainformat      = 0;
+    pam.width            = canvasP->width;
+    pam.height           = canvasP->height;
+    pam.depth            = 3;
+    pam.maxval           = OUTPUT_MAXVAL;
+    strcpy(pam.tuple_type, PAM_PPM_TUPLETYPE);
+    
+    pnm_writepaminit(&pam);
+
+    tuplerow = pnm_allocpamrow(&pam);
+
+    for (row = 0; row < (unsigned)pam.height; ++row) {
+        pixel * const pixelrow = canvasP->pixels[row];
+        unsigned int col;
+
+        for (col = 0; col < (unsigned)pam.width; ++col) {
+            pixel const thisPixel = pixelrow[col];
+            assert(pam.depth >= 3);
+
+            tuplerow[col][PAM_RED_PLANE] = PPM_GETR(thisPixel);
+            tuplerow[col][PAM_GRN_PLANE] = PPM_GETG(thisPixel);
+            tuplerow[col][PAM_BLU_PLANE] = PPM_GETB(thisPixel);
+        }
+        pnm_writepamrow(&pam, tuplerow);
+    }
+    pnm_freepamrow(tuplerow);
+}
+
+
+
+static void
+processSvgElement(xmlTextReaderPtr const xmlReaderP,
+                  FILE *           const ofP) {
+
+    unsigned int width, height;
+    bool endOfSvg;
+    canvas * canvasP;
+
+    assert(xmlTextReaderNodeType(xmlReaderP) == XML_READER_TYPE_ELEMENT);
+    assert(streq(currentNodeName(xmlReaderP), "svg"));
+
+    getSvgAttributes(xmlReaderP, &width, &height);
+
+    createCanvas(width, height, 255, &canvasP);
+
+    endOfSvg = xmlTextReaderIsEmptyElement(xmlReaderP);
+
+    while (!endOfSvg) {
+        int rc;
+
+        rc = xmlTextReaderRead(xmlReaderP);
+        
+        switch (rc) {
+        case 1:
+            processSubSvgNode(xmlReaderP, canvasP, &endOfSvg);
+            break;
+        case 0:
+            pm_error("Input file ends in the middle of a <svg>");
+            break;
+        default:
+            pm_error("xmlTextReaderRead() failed, rc=%d", rc);
+        }
+    }
+    writePam(ofP, canvasP);
+
+    destroyCanvas(canvasP);
+}
+
+
+
+static void
+processTopLevelElement(xmlTextReaderPtr const xmlReaderP,
+                       FILE *           const ofP) {
+
+    const char * const nodeName = currentNodeName(xmlReaderP);
+
+    assert(xmlTextReaderNodeType(xmlReaderP) == XML_READER_TYPE_ELEMENT);
+    assert(xmlTextReaderDepth(xmlReaderP) == 0);
+
+    if (!streq(nodeName, "svg"))
+        pm_error("Not an SVG image.  This XML document consists of "
+                 "a <%s> element, whereas an SVG image is an <svg> "
+                 "element.", nodeName);
+    else
+        processSvgElement(xmlReaderP, ofP);
+}
+
+
+
+static void
+processTopLevelNode(xmlTextReaderPtr const xmlReaderP,
+                    FILE *           const ofP) {
+
+    unsigned int   const depth    = xmlTextReaderDepth(xmlReaderP);
+    xmlReaderTypes const nodeType = xmlTextReaderNodeType(xmlReaderP);
+
+    assert(depth == 0);
+
+    switch (nodeType) {
+    case XML_READER_TYPE_ELEMENT:
+        processTopLevelElement(xmlReaderP, ofP);
+        break;
+    default:
+        /* Just ignore whatever this is */
+        break;
+    }
+}
+
+
+
+static void
+processDocument(xmlTextReaderPtr const xmlReaderP,
+                FILE *           const ofP) {
+
+    bool eof;
+
+    eof = false;
+
+    while (!eof) {
+        int rc;
+
+        rc = xmlTextReaderRead(xmlReaderP);
+        
+        switch (rc) {
+        case 1:
+            processTopLevelNode(xmlReaderP, ofP);
+            break;
+        case 0:
+            eof = true;
+            break;
+        default:
+            pm_error("xmlTextReaderRead() failed, rc=%d", rc);
+        }
+    }
+}
+
+
+
+int
+main(int argc, char **argv) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    xmlTextReaderPtr xmlReaderP;
+
+    pnm_init(&argc, argv);
+
+    xmlInitParser();
+
+    LIBXML_TEST_VERSION;
+
+    parseCommandLine(argc, argv, &cmdline);
+    
+    traceDraw = cmdline.trace;
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    xmlReaderP = xmlReaderForFd(fileno(ifP), "SVG_IMAGE", NULL, 0);
+
+    if (xmlReaderP) {
+        processDocument(xmlReaderP, stdout);
+
+        /* xmlTextReaderIsValid() does not appear to work.  It always says
+           the document is invalid
+        */
+
+        xmlFreeTextReader(xmlReaderP);
+    } else
+        pm_error("Failed to create xmlReader");
+
+    xmlCleanupParser();
+
+    return 0;
+}
diff --git a/converter/other/tiff.c b/converter/other/tiff.c
new file mode 100644
index 00000000..a498571b
--- /dev/null
+++ b/converter/other/tiff.c
@@ -0,0 +1,468 @@
+/*============================================================================
+                                 tiff.c
+==============================================================================
+
+  Stuff specific to the TIFF format -- essentially and extension to libtiff.
+
+============================================================================*/
+
+#include <string.h>
+
+#ifdef VMS
+#ifdef SYSV
+#undef SYSV
+#endif
+#include <tiffioP.h>
+#endif
+#include <tiffio.h>
+
+#include "pm_c_util.h"
+#include "nstring.h"
+#include "mallocvar.h"
+#include "pm.h"
+#include "pm_tiff.h"
+
+
+
+static uint32
+number(const char * const value,
+       tagvalmap    const tagvallist[]) {
+    
+    char * ep;
+    long num;
+
+    if (strlen(value) == 0)
+        pm_error("null string where numeric tag value or enumerated tag "
+                 "value name expected");
+    
+    num = strtol(value, &ep, 10);
+    if (*ep != '\0') {
+        /* It's not a numeric string, so it must be an enumerated value name */
+        unsigned int i;
+        for (i = 0; tagvallist[i].name; ++i) {
+            if (STRCASEEQ(value, tagvallist[i].name))
+                return tagvallist[i].value;
+        }
+        pm_error("'%s' is neither a number nor a valid value name", value);
+        return 0; /* avoid compiler warning */
+    } else
+        return num;
+}
+
+
+
+static double
+dnumber(const char * const value) {
+
+    char * ep;
+    double num;
+    
+    num = strtod(value, &ep);
+    if (ep == value || *ep != '\0')
+        pm_error("Bad floating point number %s", value);
+
+    return num;
+}
+
+
+
+#if 0
+static void
+putByte(TIFF *          const tifP,
+        unsigned int    const tagnum,
+        const char *    const value,
+        tagvalmap const tagvallist[]) {
+
+    uint16 const num = number(value, tagvallist);
+
+    TIFFSetField(tifP, tagnum, num);
+}
+#endif
+
+
+
+static void
+putAscii(TIFF *       const tifP,
+         unsigned int const tagnum,
+         const char * const value,
+         tagvalmap    const tagvallist[]) {
+
+    TIFFSetField(tifP, tagnum, value);
+}
+
+
+
+static void
+putShort(TIFF *       const tifP,
+         unsigned     const tagnum,
+         const char * const value,
+         tagvalmap    const tagvallist[]) {
+
+    uint16 const num = number(value, tagvallist);
+
+    TIFFSetField(tifP, tagnum, num);
+}
+
+
+
+static void
+putLong(TIFF *       const tifP,
+        unsigned int const tagnum,
+        const char * const value,
+        tagvalmap    const tagvallist[]) {
+
+    uint32 const num = number(value, tagvallist);
+
+    TIFFSetField(tifP, tagnum, num);
+}
+
+
+
+static void
+putRational(TIFF *       const tifP,
+            unsigned     const tagnum,
+            const char * const value,
+            tagvalmap    const tagvallist[]) {
+
+    float const num = dnumber(value);
+
+    TIFFSetField(tifP, tagnum, num);
+}
+
+
+
+static void
+putCountBytes(TIFF *       const tifP,
+              unsigned     const tagnum,
+              const char * const value,
+              tagvalmap    const tagvallist[]) {
+
+    uint32 const len = strlen(value)/2;
+
+    char * data;
+    uint32 i;
+    bool   error;
+
+    MALLOCARRAY_NOFAIL(data, len);
+
+    for (i = 0, error = FALSE; !error && i < len; ++i) {
+        unsigned int val;
+        int    nb;
+        int    rc;
+        rc = sscanf(&value[i*2], "%2x%n", &val, &nb);
+        if (rc != 1 || nb != 2)
+            error = TRUE;
+        else
+            data[i] = val;
+    }
+    if (!error)
+        TIFFSetField(tifP, tagnum, len, (void *)data);
+
+    free(data);
+}
+
+
+
+#define TV(p,a) { #a, p##a, }
+
+static tagvalmap const 
+tvm_compression[] = {
+    TV(COMPRESSION_,NONE),
+    TV(COMPRESSION_,CCITTRLE),
+    TV(COMPRESSION_,CCITTFAX3),
+    TV(COMPRESSION_,CCITTFAX4),
+    TV(COMPRESSION_,LZW),
+    TV(COMPRESSION_,OJPEG),
+    TV(COMPRESSION_,JPEG),
+    TV(COMPRESSION_,NEXT),
+    TV(COMPRESSION_,CCITTRLEW),
+    TV(COMPRESSION_,PACKBITS),
+    TV(COMPRESSION_,THUNDERSCAN),
+    TV(COMPRESSION_,IT8CTPAD),
+    TV(COMPRESSION_,IT8LW),
+    TV(COMPRESSION_,IT8MP),
+    TV(COMPRESSION_,IT8BL),
+    TV(COMPRESSION_,PIXARFILM),
+    TV(COMPRESSION_,PIXARLOG),
+    TV(COMPRESSION_,DEFLATE),
+    TV(COMPRESSION_,ADOBE_DEFLATE),
+    TV(COMPRESSION_,DCS),
+    TV(COMPRESSION_,JBIG),
+    TV(COMPRESSION_,SGILOG),
+    TV(COMPRESSION_,SGILOG24),
+    { NULL, 0, },
+};
+
+static tagvalmap const
+tvm_faxmode[] = {
+    TV(FAXMODE_,CLASSIC),
+    TV(FAXMODE_,NORTC),
+    TV(FAXMODE_,NOEOL),
+    TV(FAXMODE_,BYTEALIGN),
+    TV(FAXMODE_,WORDALIGN),
+    TV(FAXMODE_,CLASSF),
+    { NULL, 0, },
+};
+
+static tagvalmap const
+tvm_fillorder[] = {
+    TV(FILLORDER_,MSB2LSB),
+    TV(FILLORDER_,LSB2MSB),
+    { NULL, 0, },
+};
+
+static tagvalmap
+const tvm_group3options[] = {
+    TV(GROUP3OPT_,2DENCODING),
+    TV(GROUP3OPT_,UNCOMPRESSED),
+    TV(GROUP3OPT_,FILLBITS),
+    { NULL, 0, },
+};
+
+static tagvalmap
+const tvm_group4options[] = {
+    TV(GROUP4OPT_,UNCOMPRESSED),
+    { NULL, 0, },
+};
+
+static tagvalmap
+const tvm_inkset[] = {
+    TV(INKSET_,CMYK),
+    { NULL, 0, },
+};
+
+static tagvalmap
+const tvm_orientation[] = {
+    TV(ORIENTATION_,TOPLEFT),
+    TV(ORIENTATION_,TOPRIGHT),
+    TV(ORIENTATION_,BOTRIGHT),
+    TV(ORIENTATION_,BOTLEFT),
+    TV(ORIENTATION_,LEFTTOP),
+    TV(ORIENTATION_,RIGHTTOP),
+    TV(ORIENTATION_,RIGHTBOT),
+    TV(ORIENTATION_,LEFTBOT),
+    { NULL, 0, },
+};
+
+static tagvalmap const
+tvm_photometric[] = {
+    TV(PHOTOMETRIC_,MINISWHITE),
+    TV(PHOTOMETRIC_,MINISBLACK),
+    TV(PHOTOMETRIC_,RGB),
+    TV(PHOTOMETRIC_,PALETTE),
+    TV(PHOTOMETRIC_,MASK),
+    TV(PHOTOMETRIC_,SEPARATED),
+    TV(PHOTOMETRIC_,YCBCR),
+    TV(PHOTOMETRIC_,CIELAB),
+    TV(PHOTOMETRIC_,LOGL),
+    TV(PHOTOMETRIC_,LOGLUV),
+    { NULL, 0, },
+};
+
+static tagvalmap const
+tvm_planarconfig[] = {
+    TV(PLANARCONFIG_,CONTIG),
+    TV(PLANARCONFIG_,SEPARATE),
+    { NULL, 0, },
+};
+
+static tagvalmap const
+tvm_resolutionunit[] = {
+    TV(RESUNIT_,NONE),
+    TV(RESUNIT_,INCH),
+    TV(RESUNIT_,CENTIMETER),
+    { NULL, 0, },
+};
+
+static tagvalmap const
+tvm_sampleformat[] = {
+    TV(SAMPLEFORMAT_,UINT),
+    TV(SAMPLEFORMAT_,INT),
+    TV(SAMPLEFORMAT_,IEEEFP),
+    TV(SAMPLEFORMAT_,VOID),
+    { NULL, 0, },
+};
+
+static tagvalmap const
+tvm_subfiletype[] = {
+    TV(FILETYPE_,REDUCEDIMAGE),
+    TV(FILETYPE_,PAGE),
+    TV(FILETYPE_,MASK),
+    { NULL, 0, },
+};
+
+static tagvalmap const
+tvm_threshholding[] =
+{
+    TV(THRESHHOLD_,BILEVEL),
+    TV(THRESHHOLD_,HALFTONE),
+    TV(THRESHHOLD_,ERRORDIFFUSE),
+    { NULL, 0, },
+};
+#undef TV
+
+/*
+ * For full functionality, some tags have an implied count
+ * (eg. colormap, dotrange). See TIFFGetField(3).
+ * Also, some are arrays.
+ */
+#define DECL(a,p,c) { #a, TIFFTAG_##a, p, c, }
+
+static tagDefinition const
+tagDefinitions[] = {
+    DECL(ARTIST,                  putAscii,    NULL),
+    DECL(BADFAXLINES,             putLong,     NULL),
+    DECL(BITSPERSAMPLE,           putShort,    NULL),
+    DECL(CELLLENGTH,              NULL,        NULL),
+    DECL(CELLWIDTH,               NULL,        NULL),
+    DECL(CLEANFAXDATA,            putShort,    NULL),
+    DECL(COLORMAP,                NULL,        NULL),
+    DECL(COLORRESPONSEUNIT,       NULL,        NULL),
+    DECL(COMPRESSION,             putShort,    tvm_compression),
+    DECL(CONSECUTIVEBADFAXLINES,  putLong,     NULL),
+    DECL(COPYRIGHT,               putAscii,    NULL),
+    DECL(DATATYPE,                putShort,    NULL),
+    DECL(DATETIME,                putAscii,    NULL),
+    DECL(DCSBALANCEARRAY,         NULL,        NULL),
+    DECL(DCSCALIBRATIONFD,        NULL,        NULL),
+    DECL(DCSCLIPRECTANGLE,        NULL,        NULL),
+    DECL(DCSCORRECTMATRIX,        NULL,        NULL),
+    DECL(DCSGAMMA,                NULL,        NULL),
+    DECL(DCSHUESHIFTVALUES,       NULL,        NULL),
+    DECL(DCSIMAGERTYPE,           NULL,        NULL),
+    DECL(DCSINTERPMODE,           NULL,        NULL),
+    DECL(DCSTOESHOULDERPTS,       NULL,        NULL),
+    DECL(DOCUMENTNAME,            putAscii,    NULL),
+    DECL(DOTRANGE,                NULL,        NULL),
+    DECL(EXTRASAMPLES,            NULL,        NULL),
+    DECL(FAXFILLFUNC,             NULL,        NULL),
+    DECL(FAXMODE,                 putLong,     tvm_faxmode),
+    DECL(FAXRECVPARAMS,           NULL,        NULL),
+    DECL(FAXRECVTIME,             NULL,        NULL),
+    DECL(FAXSUBADDRESS,           NULL,        NULL),
+    DECL(FEDEX_EDR,               NULL,        NULL),
+    DECL(FILLORDER,               putShort,    tvm_fillorder),
+    DECL(FRAMECOUNT,              NULL,        NULL),
+    DECL(FREEBYTECOUNTS,          NULL,        NULL),
+    DECL(FREEOFFSETS,             NULL,        NULL),
+    DECL(GRAYRESPONSECURVE,       NULL,        NULL),
+    DECL(GRAYRESPONSEUNIT,        NULL,        NULL),
+    DECL(GROUP3OPTIONS,           putLong,     tvm_group3options),
+    DECL(GROUP4OPTIONS,           putLong,     tvm_group4options),
+    DECL(HALFTONEHINTS,           NULL,        NULL),
+    DECL(HOSTCOMPUTER,            putAscii,    NULL),
+    DECL(ICCPROFILE,              putCountBytes, NULL),
+    DECL(IMAGEDEPTH,              putLong,     NULL),
+    DECL(IMAGEDESCRIPTION,        putAscii,    NULL),
+    DECL(IMAGELENGTH,             putLong,     NULL),
+    DECL(IMAGEWIDTH,              putLong,     NULL),
+    DECL(INKNAMES,                putAscii,    NULL),
+    DECL(INKSET,                  putShort,    tvm_inkset),
+    DECL(IT8BITSPEREXTENDEDRUNLENGTH, NULL,    NULL),
+    DECL(IT8BITSPERRUNLENGTH,     NULL,        NULL),
+    DECL(IT8BKGCOLORINDICATOR,    NULL,        NULL),
+    DECL(IT8BKGCOLORVALUE,        NULL,        NULL),
+    DECL(IT8COLORCHARACTERIZATION, NULL,       NULL),
+    DECL(IT8COLORSEQUENCE,        NULL,        NULL),
+    DECL(IT8COLORTABLE,           NULL,        NULL),
+    DECL(IT8HEADER,               NULL,        NULL),
+    DECL(IT8IMAGECOLORINDICATOR,  NULL,        NULL),
+    DECL(IT8IMAGECOLORVALUE,      NULL,        NULL),
+    DECL(IT8PIXELINTENSITYRANGE,  NULL,        NULL),
+    DECL(IT8RASTERPADDING,        NULL,        NULL),
+    DECL(IT8SITE,                 NULL,        NULL),
+    DECL(IT8TRANSPARENCYINDICATOR, NULL,       NULL),
+    DECL(JBIGOPTIONS,             NULL,        NULL),
+    DECL(JPEGACTABLES,            NULL,        NULL),
+    DECL(JPEGCOLORMODE,           NULL,        NULL),
+    DECL(JPEGDCTABLES,            NULL,        NULL),
+    DECL(JPEGIFBYTECOUNT,         NULL,        NULL),
+    DECL(JPEGIFOFFSET,            NULL,        NULL),
+    DECL(JPEGLOSSLESSPREDICTORS,  NULL,        NULL),
+    DECL(JPEGPOINTTRANSFORM,      NULL,        NULL),
+    DECL(JPEGPROC,                NULL,        NULL),
+    DECL(JPEGQTABLES,             NULL,        NULL),
+    DECL(JPEGQUALITY,             NULL,        NULL),
+    DECL(JPEGRESTARTINTERVAL,     NULL,        NULL),
+    DECL(JPEGTABLES,              NULL,        NULL),
+    DECL(JPEGTABLESMODE,          NULL,        NULL),
+    DECL(MAKE,                    putAscii,    NULL),
+    DECL(MATTEING,                putShort,    NULL),
+    DECL(MAXSAMPLEVALUE,          putShort,    NULL),
+    DECL(MINSAMPLEVALUE,          putShort,    NULL),
+    DECL(MODEL,                   putAscii,    NULL),
+    DECL(NUMBEROFINKS,            NULL,        NULL),
+    DECL(ORIENTATION,             putShort,    tvm_orientation),
+    DECL(OSUBFILETYPE,            NULL,        NULL),
+    DECL(PAGENAME,                putAscii,    NULL),
+    DECL(PAGENUMBER,              NULL,        NULL),
+    DECL(PHOTOMETRIC,             putShort,    tvm_photometric),
+    DECL(PHOTOSHOP,               NULL,        NULL),
+    DECL(PIXAR_FOVCOT,            NULL,        NULL),
+    DECL(PIXAR_IMAGEFULLLENGTH,   NULL,        NULL),
+    DECL(PIXAR_IMAGEFULLWIDTH,    NULL,        NULL),
+    DECL(PIXAR_MATRIX_WORLDTOCAMERA, NULL,     NULL),
+    DECL(PIXAR_MATRIX_WORLDTOSCREEN, NULL,     NULL),
+    DECL(PIXAR_TEXTUREFORMAT,     NULL,        NULL),
+    DECL(PIXAR_WRAPMODES,         NULL,        NULL),
+    DECL(PIXARLOGDATAFMT,         NULL,        NULL),
+    DECL(PIXARLOGQUALITY,         NULL,        NULL),
+    DECL(PLANARCONFIG,            putShort,    tvm_planarconfig),
+    DECL(PREDICTOR,               putShort,    NULL),
+    DECL(PRIMARYCHROMATICITIES,   NULL,        NULL),
+    DECL(REFERENCEBLACKWHITE,     NULL,        NULL),
+    DECL(REFPTS,                  NULL,        NULL),
+    DECL(REGIONAFFINE,            NULL,        NULL),
+    DECL(REGIONTACKPOINT,         NULL,        NULL),
+    DECL(REGIONWARPCORNERS,       NULL,        NULL),
+    DECL(RESOLUTIONUNIT,          putShort,    tvm_resolutionunit),
+    DECL(RICHTIFFIPTC,            NULL,        NULL),
+    DECL(ROWSPERSTRIP,            putLong,     NULL),
+    DECL(SAMPLEFORMAT,            putShort,    tvm_sampleformat),
+    DECL(SAMPLESPERPIXEL,         putShort,    NULL),
+    DECL(SGILOGDATAFMT,           NULL,        NULL),
+    DECL(SMAXSAMPLEVALUE,         NULL,        NULL),
+    DECL(SMINSAMPLEVALUE,         NULL,        NULL),
+    DECL(SOFTWARE,                putAscii,    NULL),
+    DECL(STONITS,                 NULL,        NULL),
+    DECL(STRIPBYTECOUNTS,         NULL,        NULL),
+    DECL(STRIPOFFSETS,            NULL,        NULL),
+    DECL(SUBFILETYPE,             putLong,     tvm_subfiletype),
+    DECL(SUBIFD,                  NULL,        NULL),
+    DECL(TARGETPRINTER,           putAscii,    NULL),
+    DECL(THRESHHOLDING,           putShort,    tvm_threshholding),
+    DECL(TILEBYTECOUNTS,          NULL,        NULL),
+    DECL(TILEDEPTH,               putLong,     NULL),
+    DECL(TILELENGTH,              putLong,     NULL),
+    DECL(TILEOFFSETS,             NULL,        NULL),
+    DECL(TILEWIDTH,               putLong,     NULL),
+    DECL(TRANSFERFUNCTION,        NULL,        NULL),
+    DECL(WHITEPOINT,              NULL,        NULL),
+    DECL(WRITERSERIALNUMBER,      NULL,        NULL),
+    DECL(XPOSITION,               putRational, NULL),
+    DECL(XRESOLUTION,             putRational, NULL),
+    DECL(YCBCRCOEFFICIENTS,       NULL,        NULL),
+    DECL(YCBCRPOSITIONING,        NULL,        NULL),
+    DECL(YCBCRSUBSAMPLING,        NULL,        NULL),
+    DECL(YPOSITION,               putRational, NULL),
+    DECL(YRESOLUTION,             putRational, NULL),
+    DECL(ZIPQUALITY,              NULL,        NULL),
+};
+#undef DECL
+
+
+
+const tagDefinition *
+tagDefFind(const char * const name) {
+
+    unsigned int i;
+
+    for (i = 0;
+         i < ARRAY_SIZE(tagDefinitions) && tagDefinitions[i].name;
+         ++i) {
+        if (STRCASEEQ(tagDefinitions[i].name, name))
+            return &tagDefinitions[i];
+    }
+
+    return NULL;
+}
diff --git a/converter/other/tifftopnm.c b/converter/other/tifftopnm.c
new file mode 100644
index 00000000..5969a49a
--- /dev/null
+++ b/converter/other/tifftopnm.c
@@ -0,0 +1,1062 @@
+/*
+** tifftopnm.c - converts a Tagged Image File to a portable anymap
+**
+** Derived by Jef Poskanzer from tif2ras.c, which is:
+**
+** Copyright (c) 1990 by Sun Microsystems, Inc.
+**
+** Author: Patrick J. Naughton
+** naughton@wind.sun.com
+**
+** 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 file is provided AS IS with no warranties of any kind.  The author
+** shall have no liability with respect to the infringement of copyrights,
+** trade secrets or any patents by this file or any part thereof.  In no
+** event will the author be liable for any lost revenue or profits or
+** other special, indirect and consequential damages.
+*/
+
+/* Design note:
+
+   We have two different ways of converting from Tiff, as provided by the
+   Tiff library:  
+
+   1) decode the entire image into memory at once, using
+      TIFFRGBAImageGet(), then convert to PNM and output row by row.
+   
+   2) read, convert, and output one row at a time using TIFFReadScanline().
+
+   (1) is preferable because the Tiff library does more of the work, which
+   means it understands more of the Tiff format possibilities now and in 
+   the future.  Also, some compressed TIFF formats don't allow you to 
+   extract an individual row.
+
+   (2) uses far less memory, and because our code does more of the work,
+   it's possible that it can be more flexible or at least give better
+   diagnostic information if there's something wrong with the TIFF.
+
+   In Netpbm, we stress function over performance, so by default we
+   try (1) first, and if we can't get enough memory for the decoded
+   image or TIFFRGBAImageGet() fails, we fall back to (2).  But we
+   give the user the -byrow option to order (2) only.
+*/
+
+#define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include <string.h>
+#include "pnm.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+
+#ifdef VMS
+#ifdef SYSV
+#undef SYSV
+#endif
+#include <tiffioP.h>
+#endif
+/* See warning about tiffio.h in pamtotiff.c */
+#include <tiffio.h>
+
+/* The following are in current tiff.h, but so that we can compile against
+   older tiff libraries, we define them here.
+*/
+
+#ifndef PHOTOMETRIC_LOGL
+#define PHOTOMETRIC_LOGL 32844
+#endif
+#ifndef PHOTOMETRIC_LOGLUV
+#define PHOTOMETRIC_LOGLUV 32845
+#endif
+
+#define MAXCOLORS 1024
+#ifndef PHOTOMETRIC_DEPTH
+#define PHOTOMETRIC_DEPTH 32768
+#endif
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    char * inputFilename;
+    unsigned int headerdump;
+    char * alphaFilename;
+    bool alphaStdout;
+    unsigned int respectfillorder;   /* -respectfillorder option */
+    unsigned int byrow;
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, char ** argv,
+                 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
+   sometimes, one of these strings is actually just a suffix of an entry
+   in argv!
+-----------------------------------------------------------------------------*/
+    optStruct3 opt;
+    optEntry *option_def;
+    unsigned int option_def_index;
+    unsigned int alphaSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;
+    opt.allowNegNum = FALSE;
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "verbose", 
+            OPT_FLAG,   NULL, &cmdlineP->verbose,              0);
+    OPTENT3(0, "respectfillorder", 
+            OPT_FLAG,   NULL, &cmdlineP->respectfillorder,     0);
+    OPTENT3(0,   "byrow",   
+            OPT_FLAG,   NULL, &cmdlineP->byrow,                0);
+    OPTENT3('h', "headerdump", 
+            OPT_FLAG,   NULL, &cmdlineP->headerdump,           0);
+    OPTENT3(0,   "alphaout",   
+            OPT_STRING, &cmdlineP->alphaFilename, &alphaSpec,  0);
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+
+    if (argc - 1 == 0)
+        cmdlineP->inputFilename = strdup("-");  /* he wants stdin */
+    else if (argc - 1 == 1)
+        cmdlineP->inputFilename = strdup(argv[1]);
+    else 
+        pm_error("Too many arguments.  The only argument accepted "
+                 "is the input file name");
+
+    if (alphaSpec) {
+        if (STREQ(cmdlineP->alphaFilename, "-"))
+            cmdlineP->alphaStdout = TRUE;
+        else
+            cmdlineP->alphaStdout = FALSE;
+    } else {
+        cmdlineP->alphaFilename = NULL;
+        cmdlineP->alphaStdout = FALSE;
+    }
+}
+
+
+
+static void 
+read_directory(TIFF * const tif,
+               unsigned short * const bps_p,
+               unsigned short * const spp_p,
+               unsigned short * const photomet_p,
+               unsigned short * const planarconfig_p,
+               unsigned short * const fillorder_p,
+               unsigned int *   const cols_p,
+               unsigned int *   const rows_p,
+               bool             const headerdump) {
+/*----------------------------------------------------------------------------
+   Read various values of TIFF tags from the TIFF directory, and
+   default them if not in there and make guesses where values are
+   invalid.  Exit program with error message if required tags aren't
+   there or values are inconsistent or beyond our capabilities.  if
+   'headerdump' is true, issue informational messages about what we
+   find.
+
+   The TIFF library is capable of returning invalid values (if the
+   input file contains invalid values).  We generally return those
+   invalid values to our caller.
+-----------------------------------------------------------------------------*/
+    int rc;
+    unsigned short tiff_bps;
+    unsigned short tiff_spp;
+
+    if (headerdump)
+        TIFFPrintDirectory(tif, stderr, TIFFPRINT_NONE);
+
+    rc = TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &tiff_bps);
+    *bps_p = (rc == 0) ? 1 : tiff_bps;
+
+    if (*bps_p < 1 || (*bps_p > 8 && *bps_p != 16 && *bps_p != 32))
+        pm_error("This program can process Tiff images with only "
+                 "1-8 or 16 bits per sample.  The input Tiff image "
+                 "has %d bits per sample.", *bps_p);
+
+    rc = TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, fillorder_p);
+    rc = TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &tiff_spp);
+    *spp_p = (rc == 0) ? 1: tiff_spp;
+
+    rc = TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, photomet_p);
+    if (rc == 0)
+        pm_error("PHOTOMETRIC tag is not in Tiff file.  "
+                 "TIFFGetField() of it failed.\n"
+                 "This means the input is not valid Tiff.");
+
+    if (*spp_p > 1) {
+        rc = TIFFGetField(tif, TIFFTAG_PLANARCONFIG, planarconfig_p);
+        if (rc == 0)
+            pm_error("PLANARCONFIG tag is not in Tiff file, though it "
+                     "has more than one sample per pixel.  "
+                     "TIFFGetField() of it failed.  This means the input "
+                     "is not valid Tiff.");
+    } else {
+        *planarconfig_p = PLANARCONFIG_CONTIG;
+    }
+
+    switch(*planarconfig_p) {
+    case PLANARCONFIG_CONTIG:
+        break;
+    case PLANARCONFIG_SEPARATE:
+        if (*photomet_p != PHOTOMETRIC_RGB && 
+            *photomet_p != PHOTOMETRIC_SEPARATED)
+            pm_error("This program can handle separate planes only "
+                     "with RGB (PHOTOMETRIC tag = %d) or SEPARATED "
+                     "(PHOTOMETRIC tag = %d) data.  The input Tiff file " 
+                     "has PHOTOMETRIC tag = %d.",
+                     PHOTOMETRIC_RGB, PHOTOMETRIC_SEPARATED, *photomet_p);
+        break;
+    default:
+        pm_error("Unrecognized PLANARCONFIG tag value in Tiff input: %d.\n",
+                 *planarconfig_p);
+    }
+
+    rc = TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, cols_p);
+    if (rc == 0)
+        pm_error("Input Tiff file is invalid.  It has no IMAGEWIDTH tag.");
+    rc = TIFFGetField( tif, TIFFTAG_IMAGELENGTH, rows_p );
+    if (rc == 0)
+        pm_error("Input Tiff file is invalid.  It has no IMAGELENGTH tag.");
+
+    if (headerdump) {
+        pm_message( "%dx%dx%d image", *cols_p, *rows_p, *bps_p * *spp_p );
+        pm_message( "%d bits/sample, %d samples/pixel", *bps_p, *spp_p );
+    }
+}
+
+
+
+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) {
+/*----------------------------------------------------------------------------
+   Read one scanline out of the Tiff input and store it into samplebuf[].
+   Unlike the scanline returned by the Tiff library function, samplebuf[]
+   is composed of one sample per array element, which makes it easier for
+   our caller to process.
+
+   scanbuf[] is a scratch array for our use, which is big enough to hold
+   a Tiff scanline.
+-----------------------------------------------------------------------------*/
+    int rc;
+    const unsigned int bpsmask = (1 << bps) - 1;
+      /* A mask for taking the lowest 'bps' bits of a number */
+
+    /* The TIFFReadScanline man page doesn't tell the format of its
+       'buf' return value, but it is exactly the same format as the 'buf'
+       input to TIFFWriteScanline.  The man page for that doesn't say 
+       anything either, but the source code for Pnmtotiff contains a
+       specification.
+    */
+
+    rc = TIFFReadScanline(tif, scanbuf, row, plane);
+    if (rc < 0)
+        pm_error( "Unable to read row %d, plane %d of input Tiff image.  "
+                  "TIFFReadScanline() failed.",
+                  row, plane);
+    else if (bps == 8) {
+        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,
+           each byte may have don't-care bits in the right-end positions.
+           At least that's how I infer the format from reading pnmtotiff.c
+           -Bryan 00.11.18
+           */
+        int sample;
+        int bitsleft;
+        unsigned char * inP;
+
+        for (sample = 0, bitsleft=8, inP=scanbuf; 
+             sample < cols*spp; 
+             sample++) {
+            if (bitsleft == 0) {
+                ++inP; 
+                bitsleft = 8;
+            } 
+            switch (fillorder) {
+            case FILLORDER_MSB2LSB:
+                samplebuf[sample] = (*inP >> (bitsleft-bps)) & bpsmask; 
+                break;
+            case FILLORDER_LSB2MSB:
+                samplebuf[sample] = (*inP >> (8-bitsleft)) & bpsmask;
+                break;
+            default:
+                pm_error("Internal error: invalid value for fillorder: %u", 
+                         fillorder);
+            }
+            bitsleft -= bps; 
+            if (bitsleft < bps)
+                /* Don't count dregs at end of byte */
+                bitsleft = 0;
+       }
+    } else if (bps == 16) {
+        /* Before Netpbm 9.17, this program assumed that scanbuf[]
+           contained an array of bytes as read from the Tiff file.  In
+           fact, in this bps == 16 case, it's an array of "shorts",
+           each stored in whatever format this platform uses (which is
+           none of our concern).  The pre-9.17 code also presumed that
+           the TIFF "FILLORDER" tag determined the order in which the
+           bytes of each sample appear in a TIFF file, which is
+           contrary to the TIFF spec.  
+        */
+        uint16 * const scanbuf16 = (uint16 *) scanbuf;
+        unsigned int sample;
+
+        for (sample = 0; sample < cols*spp; ++sample)
+            samplebuf[sample] = scanbuf16[sample];
+    } else if (bps == 32) {
+        uint32 * const scanbuf32 = (uint32 *) scanbuf;
+        unsigned int sample;
+        
+        for (sample = 0; sample < cols*spp; ++sample)
+            samplebuf[sample] = scanbuf32[sample];
+    } else 
+        pm_error("Internal error: invalid bits per sample passed to "
+                 "readscanline()");
+}
+
+
+
+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) {
+
+    /* 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
+       Netpbm 10.21 (March 2004), we assumed C,Y,M,K for some reason.
+       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];
+
+    /* The CMYK->RGB formula used by TIFFRGBAImageGet() in the TIFF 
+       library is the following, (with some apparent confusion with
+       the names of the yellow and magenta pigments being reversed).
+
+       R = (1-K)*(1-C)     (with C,Y,M,K normalized to 0..1)
+       G = (1-K)*(1-M)
+       B = (1-K)*(1-Y)
+
+       We used that too before Netpbm 10.21 (March 2004).
+
+       Now we use the inverse of what Pnmtotiffcmyk has always used, which
+       makes sense as follows:  A microliter of black ink is simply a 
+       substitute for a microliter each of cyan, magenta, and yellow ink.
+       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);
+}
+
+
+
+static void
+computeFillorder(unsigned short   const fillorderTag, 
+                 unsigned short * const fillorderP, 
+                 bool             const respectfillorder) {
+
+    if (respectfillorder) {
+        if (fillorderTag != FILLORDER_MSB2LSB && 
+            fillorderTag != FILLORDER_LSB2MSB)
+            pm_error("Invalid value in Tiff input for the FILLORDER tag: %u.  "
+                     "Valid values are %u and %u.  Try omitting the "
+                     "-respectfillorder option.", 
+                     fillorderTag, FILLORDER_MSB2LSB, FILLORDER_LSB2MSB);
+        else
+            *fillorderP = fillorderTag;
+    } else {
+        *fillorderP = FILLORDER_MSB2LSB;
+        if (fillorderTag != *fillorderP)
+            pm_message("Warning: overriding FILLORDER tag in the tiff input "
+                       "and assuming msb-to-lsb.  Consider the "
+                       "-respectfillorder option.");
+    }
+}
+
+
+
+static void
+analyzeImageType(TIFF *             const tif, 
+                 unsigned short     const bps, 
+                 unsigned short     const spp, 
+                 unsigned short     const photomet,
+                 xelval *           const maxvalP, 
+                 int *              const formatP, 
+                 xel                      colormap[],
+                 bool               const headerdump,
+                 struct cmdlineInfo const cmdline) {
+
+    bool grayscale; 
+
+    if (bps == 1 && spp == 1) {
+        if (cmdline.headerdump)
+            pm_message("bilevel");
+        grayscale = TRUE;
+        *maxvalP = 1;
+    } else {
+        /* How come we don't deal with the photometric for the monochrome 
+           case (make sure it's one we know)?  -Bryan 00.03.04
+        */
+        switch (photomet) {
+        case PHOTOMETRIC_MINISBLACK:
+        case PHOTOMETRIC_MINISWHITE:
+            if (spp != 1)
+                pm_error("This grayscale image has %d samples per pixel.  "
+                         "We understand only 1.", spp);
+            grayscale = TRUE;
+            *maxvalP = pm_bitstomaxval(MIN(bps,16));
+            if (headerdump)
+                pm_message("grayscale image, (min=%s) output maxval %u ", 
+                           photomet == PHOTOMETRIC_MINISBLACK ? 
+                           "black" : "white",
+                           *maxvalP
+                           );
+            break;
+            
+        case PHOTOMETRIC_PALETTE: {
+            int i;
+            int numcolors;
+            unsigned short* redcolormap;
+            unsigned short* greencolormap;
+            unsigned short* bluecolormap;
+
+            if (headerdump)
+                pm_message("colormapped");
+
+            if (spp != 1)
+                pm_error("This paletted image has %d samples per pixel.  "
+                         "We understand only 1.", spp);
+
+            if (!TIFFGetField(tif, TIFFTAG_COLORMAP, 
+                              &redcolormap, &greencolormap, &bluecolormap))
+                pm_error("error getting colormaps");
+
+            numcolors = 1 << bps;
+            if (numcolors > MAXCOLORS)
+                pm_error("too many colors");
+            *maxvalP = PNM_MAXMAXVAL;
+            grayscale = FALSE;
+            for (i = 0; i < numcolors; ++i) {
+                xelval r, g, b;
+                r = (long) redcolormap[i] * PNM_MAXMAXVAL / 65535L;
+                g = (long) greencolormap[i] * PNM_MAXMAXVAL / 65535L;
+                b = (long) bluecolormap[i] * PNM_MAXMAXVAL / 65535L;
+                PPM_ASSIGN(colormap[i], r, g, b);
+            }
+        }
+        break;
+
+        case PHOTOMETRIC_SEPARATED: {
+            unsigned short inkset;
+
+            if (headerdump)
+                pm_message("color separation");
+            if (TIFFGetField(tif, TIFFTAG_INKNAMES, &inkset) == 1
+                && inkset != INKSET_CMYK)
+            if (inkset != INKSET_CMYK) 
+                pm_error("This color separation file uses an inkset (%d) "
+                         "we can't handle.  We handle only CMYK.", inkset);
+            if (spp != 4) 
+                pm_error("This CMYK color separation file is %d samples per "
+                         "pixel.  "
+                         "We need 4 samples, though: C, M, Y, and K.  ",
+                         spp);
+            grayscale = FALSE;
+            *maxvalP = (1 << bps) - 1;
+        }
+        break;
+            
+        case PHOTOMETRIC_RGB:
+            if (headerdump)
+                pm_message("RGB truecolor");
+            grayscale = FALSE;
+
+            if (spp != 3 && spp != 4)
+                pm_error("This RGB image has %d samples per pixel.  "
+                         "We understand only 3 or 4.", spp);
+
+            *maxvalP = (1 << bps) - 1;
+            break;
+
+        case PHOTOMETRIC_MASK:
+            pm_error("don't know how to handle PHOTOMETRIC_MASK");
+
+        case PHOTOMETRIC_DEPTH:
+            pm_error("don't know how to handle PHOTOMETRIC_DEPTH");
+
+        case PHOTOMETRIC_YCBCR:
+            pm_error("don't know how to handle PHOTOMETRIC_YCBCR");
+
+        case PHOTOMETRIC_CIELAB:
+            pm_error("don't know how to handle PHOTOMETRIC_CIELAB");
+
+        case PHOTOMETRIC_LOGL:
+            pm_error("don't know how to handle PHOTOMETRIC_LOGL");
+
+        case PHOTOMETRIC_LOGLUV:
+            pm_error("don't know how to handle PHOTOMETRIC_LOGLUV");
+            
+        default:
+            pm_error("unknown photometric: %d", photomet);
+        }
+    }
+    if (*maxvalP > PNM_OVERALLMAXVAL)
+        pm_error("bits/sample (%d) in the input image is too large.",
+                 bps);
+    if (grayscale) {
+        if (*maxvalP == 1) {
+            *formatP = PBM_TYPE;
+            pm_message("writing PBM file");
+        } else {
+            *formatP = PGM_TYPE;
+            pm_message("writing PGM file");
+        }
+    } else {
+        *formatP = PPM_TYPE;
+        pm_message("writing PPM file");
+    }
+}
+
+
+
+static void
+convertRow(unsigned int   const samplebuf[], 
+           xel                  xelrow[], 
+           gray                 alpharow[], 
+           int            const cols, 
+           xelval         const maxval, 
+           unsigned short const photomet, 
+           unsigned short const spp,
+           xel            const colormap[]) {
+/*----------------------------------------------------------------------------
+   Assuming samplebuf[] is an array of raster values as returned by the Tiff
+   library, convert it to a libnetpbm row in xelrow[] and alpharow[].
+-----------------------------------------------------------------------------*/
+    switch (photomet) {
+    case PHOTOMETRIC_MINISBLACK: {
+        int col;
+        for (col = 0; col < cols; ++col) {
+            PNM_ASSIGN1(xelrow[col], samplebuf[col]);
+            alpharow[col] = 0;
+        }
+    }
+    break;
+    
+    case PHOTOMETRIC_MINISWHITE: {
+        int col;
+        for (col = 0; col < cols; ++col) {
+            PNM_ASSIGN1(xelrow[col], maxval - samplebuf[col]);
+            alpharow[col] = 0;
+        }
+    }
+    break;
+
+    case PHOTOMETRIC_PALETTE: {
+        int col;
+        for ( col = 0; col < cols; ++col ) {
+            /* We know the following array index is in bounds because
+               we filled samplebuf with samples of 'bps' bits each and
+               we verified that the largest number that fits in 'bps'
+               bits is less than MAXCOLORS, the dimension of the array.
+            */
+            xelrow[col] = colormap[samplebuf[col]];
+            alpharow[col] = 0;
+        }
+    }
+    break;
+
+    case PHOTOMETRIC_SEPARATED: {
+        int col, sample;
+        for (col = 0, sample = 0; col < cols; ++col, sample+=spp) {
+            xelval r, g, b;
+            pick_cmyk_pixel(samplebuf, sample, &r, &b, &g);
+            
+            PPM_ASSIGN(xelrow[col], r, g, b);
+            alpharow[col] = 0;
+        }
+    }
+    break;
+
+    case PHOTOMETRIC_RGB: {
+        int col, sample;
+        for (col = 0, sample = 0; col < cols; ++col, sample+=spp) {
+            PPM_ASSIGN(xelrow[col], samplebuf[sample+0],
+                       samplebuf[sample+1], samplebuf[sample+2]);
+            if (spp >= 4)
+                alpharow[col] = samplebuf[sample+3];
+            else
+                alpharow[col] = 0;
+        }
+        break;
+    }       
+    default:
+        pm_error("internal error:  unknown photometric in the picking "
+                 "routine: %d", photomet);
+    }
+}
+
+
+
+static void
+scale32to16(unsigned int       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.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+    for (i = 0; i < cols * spp; ++i)
+        samplebuf[i] >>= 16; 
+}
+
+
+
+static void
+convertMultiPlaneRow(TIFF *         const tif,
+                     xel                   xelrow[],
+                     gray                  alpharow[],
+                     int             const cols,
+                     xelval          const maxval,
+                     int             const row,
+                     unsigned short  const photomet,
+                     unsigned short  const bps,
+                     unsigned short  const spp,
+                     unsigned short  const fillorder,
+                     unsigned char * const scanbuf,
+                     unsigned int *  const samplebuf) {
+
+    /* The input is in separate planes, so we need to read one
+       scanline for the reds, another for the greens, then another
+       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 {
+        /* 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);
+
+        /* Read the reds */
+        readscanline(tif, scanbuf, row, 0, cols, bps, spp, fillorder, 
+                     samplebuf);
+        if (bps == 32)
+            scale32to16(samplebuf, cols, spp);
+        for (col = 0; col < cols; ++col) 
+            PPM_PUTR(xelrow[col], samplebuf[col]);
+                
+        /* Next the greens */
+        readscanline(tif, scanbuf, row, 1, cols, bps, spp, fillorder,
+                     samplebuf);
+        if (bps == 32)
+            scale32to16(samplebuf, cols, spp);
+        for (col = 0; col < cols; ++col) 
+            PPM_PUTG( xelrow[col], samplebuf[col] );
+            
+        /* And finally the blues */
+        readscanline(tif, scanbuf, row, 2, cols, bps, spp, fillorder,
+                     samplebuf);
+        if (bps == 32)
+            scale32to16(samplebuf, cols, spp);
+        for (col = 0; col < cols; ++col) 
+            PPM_PUTB(xelrow[col], samplebuf[col]);
+
+        /* Could there be an alpha plane?  (We assume no.  But if so,
+           here is where to read it) 
+        */
+        for (col = 0; col < cols; ++col) 
+            alpharow[col] = 0;
+    }
+}
+
+
+
+static void
+convertRasterByRows(FILE *         const imageoutFile, 
+                    FILE *         const alphaFile,
+                    unsigned int   const cols, 
+                    unsigned int   const rows,
+                    xelval         const maxval,
+                    int            const format, 
+                    TIFF *         const tif,
+                    unsigned short const photomet, 
+                    unsigned short const planarconfig,
+                    unsigned short const bps,
+                    unsigned short const spp,
+                    unsigned short const fillorder,
+                    xel                  colormap[]) {
+/*----------------------------------------------------------------------------
+   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.
+
+   Do this one row at a time, employing the TIFF library's
+   TIFFReadScanline.
+-----------------------------------------------------------------------------*/
+    unsigned char * scanbuf;
+        /* Buffer for a raster line in the format returned by TIFF library's
+           TIFFReadScanline
+        */
+    unsigned int * samplebuf;
+        /* Same info as 'scanbuf' above, but with each raster column (sample)
+           represented as single array element, so it's easy to work with.
+        */
+    xel* xelrow;
+        /* The ppm-format row of the image row we are presently converting */
+    gray* alpharow;
+        /* The pgm-format row representing the alpha values for the image 
+           row we are presently converting.
+        */
+
+    int row;
+
+    scanbuf = (unsigned char *) malloc(TIFFScanlineSize(tif));
+    if (scanbuf == NULL)
+        pm_error("can't allocate memory for scanline buffer");
+
+    MALLOCARRAY(samplebuf, cols * spp);
+    if (samplebuf == NULL)
+        pm_error ("can't allocate memory for row buffer");
+
+    xelrow = pnm_allocrow(cols);
+    alpharow = pgm_allocrow(cols);
+
+    for ( row = 0; row < rows; ++row ) {
+        /* Read one row of samples into samplebuf[] */
+
+        if (planarconfig == PLANARCONFIG_CONTIG) {
+            readscanline(tif, scanbuf, row, 0, cols, bps, spp, fillorder, 
+                         samplebuf);
+            if (bps == 32)
+                scale32to16(samplebuf, cols, spp);
+            convertRow(samplebuf, xelrow, alpharow, cols, maxval, 
+                       photomet, spp, colormap);
+        } else 
+            convertMultiPlaneRow(tif, xelrow, alpharow, cols, maxval, row,
+                                 photomet, bps, spp, fillorder,
+                                 scanbuf, samplebuf);
+            
+        if (imageoutFile != NULL) 
+            pnm_writepnmrow( imageoutFile, 
+                             xelrow, cols, (xelval) maxval, format, 0 );
+        if (alphaFile != NULL) 
+            pgm_writepgmrow( alphaFile, alpharow, cols, (gray) maxval, 0);
+    }
+    pgm_freerow(alpharow);
+    pnm_freerow(xelrow);
+
+    free(samplebuf);
+    free(scanbuf);
+}    
+
+
+
+
+static void 
+convertTiffRaster(uint32 *        const raster, 
+                  unsigned int    const cols,
+                  unsigned int    const rows,
+                  xelval          const maxval,
+                  int             const format,
+                  FILE *          const imageoutFile,
+                  FILE *          const alphaFile) {
+/*----------------------------------------------------------------------------
+   Convert the raster 'raster' from the format generated by the TIFF library
+   to PPM (plus PGM alpha mask where applicable) and output it to
+   the files *imageoutFile and *alphaFile in format 'format' with maxval
+   'maxval'.  The raster is 'cols' wide by 'rows' high.
+-----------------------------------------------------------------------------*/
+    xel* xelrow;
+        /* The ppm-format row of the image row we are
+           presently converting 
+        */
+    gray* alpharow;
+        /* The pgm-format row representing the alpha values
+           for the image row we are presently converting.  
+        */
+    int row;
+
+    xelrow = pnm_allocrow(cols);
+    alpharow = pgm_allocrow(cols);
+
+    for (row = 0; row < rows; ++row) {
+        uint32* rp;  
+            /* Address of pixel in 'raster' we are presently converting */
+        int col;
+
+        /* Start at beginning of row: */
+        rp = raster + (rows - row - 1) * cols;
+    
+        for (col = 0; col < cols; ++col) {
+            uint32 const tiffPixel = *rp++;
+                    
+            PPM_ASSIGN(xelrow[col], 
+                       TIFFGetR(tiffPixel) * maxval / 255, 
+                       TIFFGetG(tiffPixel) * maxval / 255, 
+                       TIFFGetB(tiffPixel) * maxval / 255);
+            alpharow[col] = TIFFGetA(tiffPixel) * maxval / 255 ;
+        }
+        
+        if (imageoutFile != NULL) 
+            pnm_writepnmrow(imageoutFile, xelrow, cols, maxval, format, 0);
+        if (alphaFile != NULL) 
+            pgm_writepgmrow(alphaFile, alpharow, cols, maxval, 0);
+    }
+    
+    pgm_freerow(alpharow);
+    pnm_freerow(xelrow);
+}    
+
+
+
+enum convertDisp {CONV_DONE, CONV_OOM, CONV_UNABLE, CONV_FAILED, 
+                  CONV_NOTATTEMPTED};
+
+static void
+convertRasterInMemory(FILE *         const imageoutFile, 
+                      FILE *         const alphaFile,
+                      unsigned int   const cols, 
+                      unsigned int   const rows,
+                      xelval         const maxval,
+                      int            const format, 
+                      TIFF *         const tif,
+                      unsigned short const photomet, 
+                      unsigned short const planarconfig,
+                      unsigned short const bps,
+                      unsigned short const spp,
+                      unsigned short const fillorder,
+                      xel                  colormap[],
+                      enum convertDisp * const statusP) {
+/*----------------------------------------------------------------------------
+   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.
+
+   Do this by reading the entire TIFF image into memory at once and formatting
+   it with the TIFF library's TIFFRGBAImageGet().
+
+   Return *statusP == CONV_OOM iff we are unable to proceed because we cannot
+   get memory to store the entire raster.  This means Caller may still be able
+   to do the conversion using a row-by-row strategy.  Like typical Netpbm
+   programs, we simply abort the program if we are unable to allocate
+   memory for other things.
+-----------------------------------------------------------------------------*/
+    if (rows == 0 || cols == 0) 
+        *statusP = CONV_DONE;
+    else {
+        char emsg[1024] ;
+        int ok;
+        ok = TIFFRGBAImageOK(tif, emsg);
+        if (!ok) {
+            pm_message(emsg);
+            *statusP = CONV_UNABLE;
+        } else {
+            uint32* raster ;
+
+            /* Note that TIFFRGBAImageGet() converts any bits per sample
+               to 8.  Maxval of the raster it returns is always 255.
+            */
+            MALLOCARRAY(raster, cols * rows);
+            if (raster == NULL) {
+                pm_message("Unable to allocate space for a raster of %u "
+                           "pixels.", cols * rows);
+                *statusP = CONV_OOM;
+            } else {
+                int const stopOnErrorFalse = FALSE;
+                TIFFRGBAImage img ;
+                int ok;
+                
+                ok = TIFFRGBAImageBegin(&img, tif, stopOnErrorFalse, emsg) ;
+                if (!ok) {
+                    pm_message(emsg);
+                    *statusP = CONV_FAILED;
+                } else {
+                    int ok;
+                    ok = TIFFRGBAImageGet(&img, raster, cols, rows);
+                    TIFFRGBAImageEnd(&img) ;
+                    if (!ok) {
+                        pm_message(emsg);
+                        *statusP = CONV_FAILED;
+                    } else {
+                        *statusP = CONV_DONE;
+                        convertTiffRaster(raster, cols, rows, maxval, format, 
+                                          imageoutFile, alphaFile);
+                    }
+                } 
+                free(raster);
+            }
+        }
+    }
+}
+
+
+
+static void
+convertImage(TIFF *             const tifP,
+             FILE *             const alphaFile, 
+             FILE *             const imageoutFile,
+             struct cmdlineInfo const cmdline) {
+
+    unsigned int cols, rows;
+    int format;
+    xelval maxval;
+    unsigned short bps, spp;
+
+    xel colormap[MAXCOLORS];
+    unsigned short photomet, planarconfig, fillorderTag;
+    unsigned short fillorder;
+
+    read_directory(tifP, &bps, &spp, &photomet, &planarconfig, &fillorderTag,
+                   &cols, &rows, 
+                   cmdline.headerdump);
+
+
+    computeFillorder(fillorderTag, &fillorder, cmdline.respectfillorder);
+
+    analyzeImageType(tifP, bps, spp, photomet, 
+                     &maxval, &format, colormap, cmdline.headerdump, cmdline);
+
+    if (imageoutFile != NULL) 
+        pnm_writepnminit( imageoutFile, 
+                          cols, rows, (xelval) maxval, format, 0 );
+    if (alphaFile != NULL) 
+        pgm_writepgminit( alphaFile, cols, rows, (gray) maxval, 0 );
+
+    {
+        enum convertDisp status;
+        if (cmdline.byrow)
+            status = CONV_NOTATTEMPTED;
+        else {
+            convertRasterInMemory(
+                imageoutFile, alphaFile, cols, rows, maxval, format, 
+                tifP, photomet, planarconfig, bps, spp, fillorder,
+                colormap, &status);
+        }
+        if (status == CONV_DONE) {
+            if (bps > 8)
+                pm_message("actual resolution has been reduced to 24 bits "
+                           "per pixel in the conversion.  You can get the "
+                           "full %u bits that are in the TIFF with the "
+                           "-byrow option.", bps);
+        } else {
+            if (status != CONV_NOTATTEMPTED)
+                pm_message("In-memory conversion failed; "
+                           "using more primitive row-by-row conversion.");
+            
+            convertRasterByRows(
+                imageoutFile, alphaFile, cols, rows, maxval, format, 
+                tifP, photomet, planarconfig, bps, spp, fillorder, colormap);
+        }
+    }
+}
+
+
+
+static void
+convertIt(TIFF *             const tifP,
+          FILE *             const alphaFile, 
+          FILE *             const imageoutFile,
+          struct cmdlineInfo const cmdline) {
+
+    unsigned int imageSeq;
+    bool eof;
+
+    imageSeq = 0;
+    eof = FALSE;
+
+    while (!eof) {
+        bool success;
+
+        if (cmdline.verbose)
+            pm_message("Converting Image %u", imageSeq);
+        convertImage(tifP, alphaFile, imageoutFile, cmdline);
+        success = TIFFReadDirectory(tifP);
+        eof = !success;
+        ++imageSeq;
+    }
+}
+
+
+
+int
+main(int argc, char * argv[]) {
+
+    struct cmdlineInfo cmdline;
+    TIFF * tif;
+    FILE * alphaFile;
+    FILE * imageoutFile;
+
+    pnm_init( &argc, 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");
+    }
+
+    if (cmdline.alphaStdout)
+        alphaFile = stdout;
+    else if (cmdline.alphaFilename == NULL) 
+        alphaFile = NULL;
+    else
+        alphaFile = pm_openw(cmdline.alphaFilename);
+
+    if (cmdline.alphaStdout) 
+        imageoutFile = NULL;
+    else
+        imageoutFile = stdout;
+
+    convertIt(tif, alphaFile, imageoutFile, cmdline);
+
+    if (imageoutFile != NULL) 
+        pm_close( imageoutFile );
+    if (alphaFile != NULL)
+        pm_close( alphaFile );
+
+    strfree(cmdline.inputFilename);
+
+    /* If the program failed, it previously aborted with nonzero completion
+       code, via various function calls.
+    */
+    return 0;
+}
diff --git a/converter/other/x10wd.h b/converter/other/x10wd.h
new file mode 100644
index 00000000..3c4fb8ca
--- /dev/null
+++ b/converter/other/x10wd.h
@@ -0,0 +1,32 @@
+/* x10wd.h - the following defs are taken from various X10 header files
+*/
+
+#ifndef X10WD_H_INCLUDED
+#define X10WD_H_INCLUDED
+
+#define XYFormat 0
+#define ZFormat 1
+
+#define X10WD_FILE_VERSION 6
+typedef struct {
+    int header_size;		/* Size of the entire file header (bytes). */
+    int file_version;		/* X10WD_FILE_VERSION */
+    int display_type;		/* Display type. */
+    int display_planes;		/* Number of display planes. */
+    int pixmap_format;		/* Pixmap format. */
+    int pixmap_width;		/* Pixmap width. */
+    int pixmap_height;		/* Pixmap height. */
+    short window_width;		/* Window width. */
+    short window_height;	/* Window height. */
+    short window_x;		/* Window upper left X coordinate. */
+    short window_y;		/* Window upper left Y coordinate. */
+    short window_bdrwidth;	/* Window border width. */
+    short window_ncolors;	/* number of Color entries in this window */
+    } X10WDFileHeader;
+
+typedef struct {
+    int pixel;
+    unsigned short red, green, blue;
+    } X10Color;
+
+#endif
diff --git a/converter/other/x11wd.h b/converter/other/x11wd.h
new file mode 100644
index 00000000..711248f5
--- /dev/null
+++ b/converter/other/x11wd.h
@@ -0,0 +1,82 @@
+/* x11wd.h - the following defs are taken from various X.V11R2 header files
+*/
+
+#ifndef X11WD_H_INCLUDED
+#define X11WD_H_INCLUDED
+
+enum byteorder {LSBFirst=0, MSBFirst=1};
+/* They used to be defined wrongly as macros:  2000.05.08 -Bryan
+
+#define LSBFirst    0
+#define MSBFirst    1
+*/
+
+#define XYBitmap    0
+#define XYPixmap    1
+#define ZPixmap     2
+
+enum visualclass {StaticGray=0,GrayScale=1,StaticColor=2,PseudoColor=3,
+                  TrueColor=4, DirectColor=5};
+
+/* They used to be defined wrongly as macros:  2000.05.08 -Bryan
+#define StaticGray  0
+#define GrayScale   1
+#define StaticColor 2
+#define PseudoColor 3
+#define TrueColor   4
+#define DirectColor 5
+*/
+
+typedef uint32n xwdval;
+#define XWDVAL_MAX ((xwdval)(-1))
+#define X11WD_FILE_VERSION 7
+typedef struct {
+    xwdval header_size;     /* Size of the entire file header (bytes). */
+    xwdval file_version;    /* X11WD_FILE_VERSION */
+    xwdval pixmap_format;   /* Pixmap format */
+    xwdval pixmap_depth;    /* Pixmap depth */
+    xwdval pixmap_width;    /* Pixmap width */
+    xwdval pixmap_height;   /* Pixmap height */
+    xwdval xoffset;     /* Bitmap x offset */
+    xwdval byte_order;      /* MSBFirst, LSBFirst */
+    xwdval bitmap_unit;     /* Bitmap unit */
+    xwdval bitmap_bit_order;    /* MSBFirst, LSBFirst */
+    xwdval bitmap_pad;      /* Bitmap scanline pad */
+    xwdval bits_per_pixel;  /* Bits per pixel */
+    xwdval bytes_per_line;  /* Bytes per scanline */
+    xwdval visual_class;    /* Class of colormap */
+    xwdval red_mask;        /* Z red mask */
+    xwdval green_mask;      /* Z green mask */
+    xwdval blue_mask;       /* Z blue mask */
+    xwdval bits_per_rgb;    /* Log base 2 of distinct color values */
+    xwdval colormap_entries;
+        /* I have no idea what this is.  An old comment says "number of
+           entries in colormap," but readers seem to use 'ncolors' for that
+           instead.  That's how Pnmtoxwd sets ncolors, and is how Xwdtopnm
+           interprets it.  Xwdtopnm doesn't even look at 'colormap_entries'.
+
+           This could be an old mistake; maybe colormap_entries was 
+           originally the number of entries in the colormap, and ncolors
+           was the number of distinct colors in the image (which might be
+           less than colormap_entries or, for direct color, could be much
+           larger).
+        */
+    xwdval ncolors;
+        /* Number of entries in the color map (for direct color, it's the
+           number of entries in each of them).  See 'colormap_entries'. 
+        */
+    xwdval window_width;    /* Window width */
+    xwdval window_height;   /* Window height */
+    int32n window_x;        /* Window upper left X coordinate */
+    int32n window_y;        /* Window upper left Y coordinate */
+    xwdval window_bdrwidth; /* Window border width */
+    } X11WDFileHeader;
+
+typedef struct {
+    uint32n num;
+    unsigned short red, green, blue;
+    char flags;         /* do_red, do_green, do_blue */
+    char pad;
+    } X11XColor;
+
+#endif
diff --git a/converter/other/xwdtopnm.c b/converter/other/xwdtopnm.c
new file mode 100644
index 00000000..28c38cfc
--- /dev/null
+++ b/converter/other/xwdtopnm.c
@@ -0,0 +1,1280 @@
+/* xwdtopnm.c - read an X11 or X10 window dump file and write a PNM image.
+**
+** Copyright (C) 1989, 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.
+*/
+
+/* IMPLEMENTATION NOTES:
+
+   The file X11/XWDFile.h from the X Window System is an authority for the
+   format of an XWD file.  Netpbm uses its own declaration, though.
+*/
+
+
+#define _BSD_SOURCE 1      /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pm_c_util.h"
+#include "shhopt.h"
+#include "mallocvar.h"
+#include "nstring.h"
+#include "pnm.h"
+#include "x10wd.h"
+#include "x11wd.h"
+
+struct cmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    char *input_filename;
+    unsigned int verbose;
+    unsigned int debug;
+    unsigned int headerdump;
+};
+
+
+static bool debug;
+static bool verbose;
+
+#ifdef DEBUG_PIXEL
+static unsigned int pixel_count = 0;
+#endif
+
+/* Byte-swapping junk. */
+
+static int
+zero_bits(const unsigned long mask) {
+/*----------------------------------------------------------------------------
+   Return the number of consective zero bits at the least significant end
+   of the binary representation of 'mask'.  E.g. if mask == 0x00fff800,
+   we would return 11.
+-----------------------------------------------------------------------------*/
+    int i;
+    unsigned long shifted_mask;
+
+    for (i=0, shifted_mask = mask; 
+         i < sizeof(mask)*8 && (shifted_mask & 0x00000001) == 0;
+         i++, shifted_mask >>= 1 );
+    return(i);
+}
+
+
+
+static int
+one_bits(const unsigned long input) {
+/*----------------------------------------------------------------------------
+   Return the number of one bits in the binary representation of 'input'.
+-----------------------------------------------------------------------------*/
+    int one_bits;
+    unsigned long mask;
+
+    one_bits = 0;   /* initial value */
+    for (mask = 0x00000001; mask != 0x00000000; mask <<= 1)
+        if (input & mask) one_bits++;
+
+    return(one_bits);
+}
+
+
+
+static void
+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
+   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 option_def_index;
+
+    MALLOCARRAY(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+
+    OPTENT3(0,   "verbose",    OPT_FLAG,   NULL, &cmdlineP->verbose,       0);
+    OPTENT3(0,   "debug",      OPT_FLAG,   NULL, &cmdlineP->debug,         0);
+    OPTENT3(0,   "headerdump", OPT_FLAG,   NULL, &cmdlineP->headerdump,    0);
+
+    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 */
+
+    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (argc - 1 == 0)
+        cmdlineP->input_filename = NULL;  /* he wants stdin */
+    else if (argc - 1 == 1) {
+        if (STREQ(argv[1], "-"))
+            cmdlineP->input_filename = NULL;  /* he wants stdin */
+        else 
+            cmdlineP->input_filename = strdup(argv[1]);
+    } else 
+        pm_error("Too many arguments.  The only argument accepted\n"
+                 "is the input file specification");
+}
+
+
+
+static void
+processX10Header(X10WDFileHeader *  const h10P, 
+                 FILE *             const file,
+                 int *              const colsP, 
+                 int *              const rowsP, 
+                 int *              const padrightP, 
+                 xelval *           const maxvalP, 
+                 enum visualclass * const visualclassP, 
+                 int *              const formatP, 
+                 xel **             const colorsP, 
+                 int *              const bits_per_pixelP, 
+                 int *              const bits_per_itemP, 
+                 unsigned long *    const red_maskP, 
+                 unsigned long *    const green_maskP, 
+                 unsigned long *    const blue_maskP,
+                 enum byteorder *   const byte_orderP,
+                 enum byteorder *   const bit_orderP) {
+
+    int i;
+    X10Color* x10colors;
+    bool grayscale;
+    bool byte_swap;
+
+    *maxvalP = 65535;   /* Initial assumption */
+
+    if ( h10P->file_version != X10WD_FILE_VERSION ) {
+        byte_swap = TRUE;
+        h10P->header_size     = pm_bs_long(h10P->header_size);
+        h10P->file_version    = pm_bs_long(h10P->file_version);
+        h10P->display_type    = pm_bs_long(h10P->display_type);
+        h10P->display_planes  = pm_bs_long(h10P->display_planes);
+        h10P->pixmap_format   = pm_bs_long(h10P->pixmap_format);
+        h10P->pixmap_width    = pm_bs_long(h10P->pixmap_width);
+        h10P->pixmap_height   = pm_bs_long(h10P->pixmap_height);
+        h10P->window_width    = pm_bs_short(h10P->window_width);
+        h10P->window_height   = pm_bs_short(h10P->window_height);
+        h10P->window_x        = pm_bs_short(h10P->window_x);
+        h10P->window_y        = pm_bs_short(h10P->window_y);
+        h10P->window_bdrwidth = pm_bs_short(h10P->window_bdrwidth);
+        h10P->window_ncolors  = pm_bs_short(h10P->window_ncolors);
+    } else
+        byte_swap = FALSE;
+
+    for ( i = 0; i < h10P->header_size - sizeof(*h10P); ++i )
+        if ( getc( file ) == EOF )
+            pm_error( "couldn't read rest of X10 XWD file header" );
+
+    /* Check whether we can handle this dump. */
+    if ( h10P->window_ncolors > 256 )
+        pm_error( "can't handle X10 window_ncolors > %d", 256 );
+    if ( h10P->pixmap_format != ZFormat && h10P->display_planes != 1 )
+        pm_error(
+            "can't handle X10 pixmap_format %d with planes != 1",
+            h10P->pixmap_format );
+
+    grayscale = TRUE;  /* initial assumption */
+    if ( h10P->window_ncolors != 0 ) {
+        /* Read X10 colormap. */
+        MALLOCARRAY( x10colors, h10P->window_ncolors );
+        if ( x10colors == NULL )
+            pm_error( "out of memory" );
+        for ( i = 0; i < h10P->window_ncolors; ++i ) {
+            if ( fread( &x10colors[i], sizeof(X10Color), 1, file ) != 1 )
+                pm_error( "couldn't read X10 XWD colormap" );
+            if ( byte_swap ) {
+                x10colors[i].red   = pm_bs_short(x10colors[i].red);
+                x10colors[i].green = pm_bs_short(x10colors[i].green);
+                x10colors[i].blue  = pm_bs_short(x10colors[i].blue);
+            }
+            if ( x10colors[i].red != x10colors[i].green ||
+                 x10colors[i].green != x10colors[i].blue )
+                grayscale = FALSE;
+        }
+    }
+
+    if ( h10P->display_planes == 1 ) {
+        *formatP = PBM_TYPE;
+        *visualclassP = StaticGray;
+        *maxvalP = 1;
+        *colorsP = pnm_allocrow( 2 );
+        PNM_ASSIGN1( (*colorsP)[0], 0 );
+        PNM_ASSIGN1( (*colorsP)[1], *maxvalP );
+        *padrightP =
+            ( ( h10P->pixmap_width + 15 ) / 16 ) * 16 - h10P->pixmap_width;
+        *bits_per_itemP = 16;
+        *bits_per_pixelP = 1;
+    } else if ( h10P->window_ncolors == 0 ) { 
+        /* Must be grayscale. */
+        *formatP = PGM_TYPE;
+        *visualclassP = StaticGray;
+        *maxvalP = ( 1 << h10P->display_planes ) - 1;
+        *colorsP = pnm_allocrow( *maxvalP + 1 );
+        for ( i = 0; i <= *maxvalP; ++i )
+            PNM_ASSIGN1( (*colorsP)[i], i );
+        *padrightP =
+            ( ( h10P->pixmap_width + 15 ) / 16 ) * 16 - h10P->pixmap_width;
+        *bits_per_itemP = 16;
+        *bits_per_pixelP = 1;
+    } else {
+        *colorsP = pnm_allocrow( h10P->window_ncolors );
+        *visualclassP = PseudoColor;
+        if ( grayscale ) {
+            *formatP = PGM_TYPE;
+            for ( i = 0; i < h10P->window_ncolors; ++i )
+                PNM_ASSIGN1( (*colorsP)[i], x10colors[i].red );
+        } else {
+            *formatP = PPM_TYPE;
+            for ( i = 0; i < h10P->window_ncolors; ++i )
+                PPM_ASSIGN(
+                    (*colorsP)[i], x10colors[i].red, x10colors[i].green,
+                    x10colors[i].blue);
+        }
+
+        *padrightP = h10P->pixmap_width & 1;
+        *bits_per_itemP = 8;
+        *bits_per_pixelP = 8;
+    }
+    *colsP = h10P->pixmap_width;
+    *rowsP = h10P->pixmap_height;
+    *byte_orderP = MSBFirst;
+    *bit_orderP = LSBFirst;
+}
+
+
+
+static void
+fixH11ByteOrder(X11WDFileHeader *  const h11P,
+                X11WDFileHeader ** const h11FixedPP) {
+
+    X11WDFileHeader * h11FixedP;
+
+    MALLOCVAR_NOFAIL(h11FixedP);
+
+    if (h11P->file_version == X11WD_FILE_VERSION) {
+        memcpy(h11FixedP, h11P, sizeof(*h11FixedP));
+    } else {
+        h11FixedP->header_size      = pm_bs_long(h11P->header_size);
+        h11FixedP->file_version     = pm_bs_long(h11P->file_version);
+        h11FixedP->pixmap_format    = pm_bs_long(h11P->pixmap_format);
+        h11FixedP->pixmap_depth     = pm_bs_long(h11P->pixmap_depth);
+        h11FixedP->pixmap_width     = pm_bs_long(h11P->pixmap_width);
+        h11FixedP->pixmap_height    = pm_bs_long(h11P->pixmap_height);
+        h11FixedP->xoffset          = pm_bs_long(h11P->xoffset);
+        h11FixedP->byte_order       = pm_bs_long(h11P->byte_order);
+        h11FixedP->bitmap_unit      = pm_bs_long(h11P->bitmap_unit);
+        h11FixedP->bitmap_bit_order = pm_bs_long(h11P->bitmap_bit_order);
+        h11FixedP->bitmap_pad       = pm_bs_long(h11P->bitmap_pad);
+        h11FixedP->bits_per_pixel   = pm_bs_long(h11P->bits_per_pixel);
+        h11FixedP->bytes_per_line   = pm_bs_long(h11P->bytes_per_line);
+        h11FixedP->visual_class     = pm_bs_long(h11P->visual_class);
+        h11FixedP->red_mask         = pm_bs_long(h11P->red_mask);
+        h11FixedP->green_mask       = pm_bs_long(h11P->green_mask);
+        h11FixedP->blue_mask        = pm_bs_long(h11P->blue_mask);
+        h11FixedP->bits_per_rgb     = pm_bs_long(h11P->bits_per_rgb);
+        h11FixedP->colormap_entries = pm_bs_long(h11P->colormap_entries);
+        h11FixedP->ncolors          = pm_bs_long(h11P->ncolors);
+        h11FixedP->window_width     = pm_bs_long(h11P->window_width);
+        h11FixedP->window_height    = pm_bs_long(h11P->window_height);
+        h11FixedP->window_x         = pm_bs_long(h11P->window_x);
+        h11FixedP->window_y         = pm_bs_long(h11P->window_y);
+        h11FixedP->window_bdrwidth  = pm_bs_long(h11P->window_bdrwidth);
+    }
+    *h11FixedPP = h11FixedP;
+}
+
+
+
+static void
+readX11Colormap(FILE *      const file,
+                int         const ncolors, 
+                bool        const byteSwap,
+                X11XColor** const x11colorsP) {
+                
+    X11XColor * x11colors;
+    int rc;
+
+    /* Read X11 colormap. */
+    MALLOCARRAY(x11colors, ncolors);
+    if (x11colors == NULL)
+        pm_error("out of memory");
+    rc = fread(x11colors, sizeof(x11colors[0]), ncolors, file);
+    if (rc != ncolors)
+        pm_error("couldn't read X11 XWD colormap");
+    if (byteSwap) {
+        unsigned int i;
+        for (i = 0; i < ncolors; ++i) {
+            x11colors[i].red   = pm_bs_short(x11colors[i].red);
+            x11colors[i].green = pm_bs_short(x11colors[i].green);
+            x11colors[i].blue  = pm_bs_short(x11colors[i].blue);
+        }
+    }
+    if (debug) {
+        unsigned int i;
+        for (i = 0; i < ncolors && i < 8; ++i)
+            pm_message("Color %d r/g/b = %d/%d/%d", i, 
+                       x11colors[i].red, x11colors[i].green, 
+                       x11colors[i].blue);
+    }
+    *x11colorsP = x11colors;
+}
+
+
+
+static bool
+colormapAllGray(const X11XColor* const x11colors,
+                unsigned int     const ncolors) {
+
+    unsigned int i;
+    bool grayscale;
+
+    grayscale = TRUE;  /* initial assumption */
+    for (i = 0; i < ncolors; ++i) 
+        if (x11colors[i].red != x11colors[i].green ||
+            x11colors[i].green != x11colors[i].blue )
+            grayscale = FALSE;
+
+    return grayscale;
+}
+
+
+
+static void
+dumpX11Header(X11WDFileHeader * const h11P) {
+
+    const char * formatDesc;
+    const char * byteOrderDesc;
+    const char * bitOrderDesc;
+    const char * visualClassDesc;
+
+    X11WDFileHeader * h11FixedP;
+
+    fixH11ByteOrder(h11P, &h11FixedP);
+ 
+    switch(h11FixedP->pixmap_format) {
+    case XYBitmap: formatDesc = "XY bit map"; break;
+    case XYPixmap: formatDesc = "XY pix map"; break;
+    case ZPixmap:  formatDesc = "Z pix map";  break;
+    default:       formatDesc = "???";
+    }
+
+    switch(h11FixedP->byte_order) {
+    case LSBFirst: byteOrderDesc = "LSB first"; break;
+    case MSBFirst: byteOrderDesc = "MSB first"; break;
+    default:       byteOrderDesc = "???";
+    }
+
+    switch (h11FixedP->bitmap_bit_order) {
+    case LSBFirst: bitOrderDesc = "LSB first"; break;
+    case MSBFirst: bitOrderDesc = "MSB first"; break;
+    default:       bitOrderDesc = "???";
+    }
+
+    switch (h11FixedP->visual_class) {
+    case StaticGray:  visualClassDesc = "StaticGray";  break;
+    case GrayScale:   visualClassDesc = "GrayScale";   break;
+    case StaticColor: visualClassDesc = "StaticColor"; break;
+    case PseudoColor: visualClassDesc = "PseudoColor"; break;
+    case TrueColor:   visualClassDesc = "TrueColor"; break;
+    case DirectColor: visualClassDesc = "DirectColor"; break;
+    default:          visualClassDesc = "???";
+    }
+
+    pm_message("File version: %u", h11FixedP->file_version);
+    pm_message("Format: %s (%u)", formatDesc, h11FixedP->pixmap_format);
+    pm_message("Width:  %u", h11FixedP->pixmap_width);
+    pm_message("Height: %u", h11FixedP->pixmap_height);
+    pm_message("Depth: %u bits", h11FixedP->pixmap_depth);
+    pm_message("X offset: %u", h11FixedP->xoffset);
+    pm_message("byte order: %s (%u)", byteOrderDesc, h11FixedP->byte_order);
+    pm_message("bitmap unit: %u", h11FixedP->bitmap_unit);
+    pm_message("bit order: %s (%u)", 
+               bitOrderDesc, h11FixedP->bitmap_bit_order);
+    pm_message("bitmap pad: %u", h11FixedP->bitmap_pad);
+    pm_message("bits per pixel: %u", h11FixedP->bits_per_pixel);
+    pm_message("bytes per line: %u", h11FixedP->bytes_per_line);
+    pm_message("visual class: %s (%u)", 
+               visualClassDesc, h11FixedP->visual_class);
+    pm_message("red mask:   %08x", h11FixedP->red_mask);
+    pm_message("green mask: %08x", h11FixedP->green_mask);
+    pm_message("blue mask:  %08x", h11FixedP->blue_mask);
+    pm_message("bits per rgb: %u", h11FixedP->bits_per_rgb);
+    pm_message("number of colormap entries: %u", h11FixedP->colormap_entries);
+    pm_message("number of colors in colormap: %u", h11FixedP->ncolors);
+    pm_message("window width:  %u", h11FixedP->window_width);
+    pm_message("window height: %u", h11FixedP->window_height);
+    pm_message("window upper left X coordinate: %u", h11FixedP->window_x);
+    pm_message("window upper left Y coordinate: %u", h11FixedP->window_y);
+    pm_message("window border width: %u", h11FixedP->window_bdrwidth);
+
+    free(h11FixedP);
+}
+
+
+
+static void
+processX11Header(X11WDFileHeader *  const h11P, 
+                 FILE *             const file,
+                 int *              const colsP, 
+                 int *              const rowsP, 
+                 int *              const padrightP, 
+                 xelval *           const maxvalP, 
+                 enum visualclass * const visualclassP, 
+                 int *              const formatP, 
+                 xel **             const colorsP, 
+                 int *              const bits_per_pixelP, 
+                 int *              const bits_per_itemP, 
+                 unsigned long *    const red_maskP, 
+                 unsigned long *    const green_maskP, 
+                 unsigned long *    const blue_maskP,
+                 enum byteorder *   const byte_orderP,
+                 enum byteorder *   const bit_orderP) {
+
+    int i;
+    X11XColor* x11colors;
+    bool grayscale;
+    bool const byte_swap = (h11P->file_version != X11WD_FILE_VERSION);
+    X11WDFileHeader * h11FixedP;
+ 
+    fixH11ByteOrder(h11P, &h11FixedP);
+
+    if (byte_swap && verbose)
+        pm_message("Header is different endianness from this machine.");
+    
+    for (i = 0; i < h11FixedP->header_size - sizeof(*h11FixedP); ++i)
+        if (getc(file) == EOF)
+            pm_error("couldn't read rest of X11 XWD file header");
+
+    /* Check whether we can handle this dump. */
+    if ( h11FixedP->pixmap_depth > 24 )
+        pm_error( "can't handle X11 pixmap_depth > 24" );
+    if ( h11FixedP->bits_per_rgb > 24 )
+        pm_error( "can't handle X11 bits_per_rgb > 24" );
+    if ( h11FixedP->pixmap_format != ZPixmap && h11FixedP->pixmap_depth != 1 )
+        pm_error(
+            "can't handle X11 pixmap_format %d with depth != 1",
+            h11FixedP->pixmap_format );
+    if ( h11FixedP->bitmap_unit != 8 && h11FixedP->bitmap_unit != 16 &&
+         h11FixedP->bitmap_unit != 32 )
+        pm_error(
+            "X11 bitmap_unit (%d) is non-standard - can't handle",
+            h11FixedP->bitmap_unit );
+    /* The following check was added in 10.19 (November 2003) */
+    if ( h11FixedP->bitmap_pad != 8 && h11FixedP->bitmap_pad != 16 &&
+         h11FixedP->bitmap_pad != 32 )
+        pm_error(
+            "X11 bitmap_pad (%d) is non-standard - can't handle",
+            h11FixedP->bitmap_unit );
+
+    if ( h11FixedP->ncolors > 0 ) {
+        readX11Colormap( file, h11FixedP->ncolors, byte_swap, &x11colors );
+        grayscale = colormapAllGray( x11colors, h11FixedP->ncolors );
+    } else
+        grayscale = TRUE;
+
+    *visualclassP = (enum visualclass) h11FixedP->visual_class;
+    if ( *visualclassP == DirectColor ) {
+        unsigned int i;
+        *formatP = PPM_TYPE;
+        *maxvalP = 65535;
+        /*
+          DirectColor is like PseudoColor except that there are essentially
+          3 colormaps (shade maps) -- one for each color component.  Each pixel
+          is composed of 3 separate indices.
+        */
+
+        *colorsP = pnm_allocrow( h11FixedP->ncolors );
+        for ( i = 0; i < h11FixedP->ncolors; ++i )
+            PPM_ASSIGN(
+                (*colorsP)[i], x11colors[i].red, x11colors[i].green,
+                x11colors[i].blue);
+    } else if ( *visualclassP == TrueColor ) {
+        *formatP = PPM_TYPE;
+
+        *maxvalP = pm_lcm(pm_bitstomaxval(one_bits(h11FixedP->red_mask)),
+                          pm_bitstomaxval(one_bits(h11FixedP->green_mask)),
+                          pm_bitstomaxval(one_bits(h11FixedP->blue_mask)),
+                          PPM_OVERALLMAXVAL
+            );
+    }
+    else if ( *visualclassP == StaticGray && h11FixedP->bits_per_pixel == 1 ) {
+        *formatP = PBM_TYPE;
+        *maxvalP = 1;
+        *colorsP = pnm_allocrow( 2 );
+        PNM_ASSIGN1( (*colorsP)[0], *maxvalP );
+        PNM_ASSIGN1( (*colorsP)[1], 0 );
+    } else if ( *visualclassP == StaticGray ) {
+        unsigned int i;
+        *formatP = PGM_TYPE;
+        *maxvalP = ( 1 << h11FixedP->bits_per_pixel ) - 1;
+        *colorsP = pnm_allocrow( *maxvalP + 1 );
+        for ( i = 0; i <= *maxvalP; ++i )
+            PNM_ASSIGN1( (*colorsP)[i], i );
+    } else {
+        *colorsP = pnm_allocrow( h11FixedP->ncolors );
+        if ( grayscale ) {
+            unsigned int i;
+            *formatP = PGM_TYPE;
+            for ( i = 0; i < h11FixedP->ncolors; ++i )
+                PNM_ASSIGN1( (*colorsP)[i], x11colors[i].red );
+        } else {
+            unsigned int i;
+            *formatP = PPM_TYPE;
+            for ( i = 0; i < h11FixedP->ncolors; ++i )
+                PPM_ASSIGN(
+                    (*colorsP)[i], x11colors[i].red, x11colors[i].green,
+                    x11colors[i].blue);
+        }
+        *maxvalP = 65535;
+    }
+
+    *colsP = h11FixedP->pixmap_width;
+    *rowsP = h11FixedP->pixmap_height;
+    *padrightP =
+        h11FixedP->bytes_per_line * 8 / h11FixedP->bits_per_pixel -
+        h11FixedP->pixmap_width;
+    /* According to X11/XWDFile.h, the item size is 'bitmap_pad' for some
+       images and 'bitmap_unit' for others.  This is strange, so there may
+       be some subtlety of their definitions that we're missing.
+
+       See comments in getpix() about what an item is.
+
+       Ben Kelley in January 2002 had a 32 bits-per-pixel xwd file
+       from a truecolor 32 bit window on a Hummingbird Exceed X server
+       on Win32, and it had bitmap_unit = 8 and bitmap_pad = 32.
+
+       But Björn Eriksson in October 2003 had an xwd file from a 24
+       bit-per-pixel direct color window that had bitmap_unit = 32 and
+       bitmap_pad = 8.  This was made by Xwd in Red Hat Xfree86 4.3.0-2.
+
+       Before Netpbm 9.23 (January 2002), we used bitmap_unit as the
+       item size always.  Then, until 10.19 (November 2003), we used
+       bitmap_pad when pixmap_depth > 1 and pixmap_format == ZPixmap.
+       We still don't see any logic in these fields at all, but we
+       figure whichever one is greater (assuming both are meaningful)
+       has to be the item size.  
+    */
+    *bits_per_itemP = MAX(h11FixedP->bitmap_pad, h11FixedP->bitmap_unit);
+
+    *bits_per_pixelP = h11FixedP->bits_per_pixel;
+
+    *byte_orderP = (enum byteorder) h11FixedP->byte_order;
+    *bit_orderP = (enum byteorder) h11FixedP->bitmap_bit_order;
+    *red_maskP = h11FixedP->red_mask;
+    *green_maskP = h11FixedP->green_mask;
+    *blue_maskP = h11FixedP->blue_mask;
+
+    free(h11FixedP);
+} 
+
+
+
+static void
+getinit(FILE *             const ifP, 
+        int *              const colsP, 
+        int *              const rowsP, 
+        int *              const padrightP, 
+        xelval *           const maxvalP, 
+        enum visualclass * const visualclassP, 
+        int *              const formatP, 
+        xel **             const colorsP,
+        int *              const bits_per_pixelP, 
+        int *              const bits_per_itemP, 
+        unsigned long *    const red_maskP, 
+        unsigned long *    const green_maskP,
+        unsigned long *    const blue_maskP,
+        enum byteorder *   const byte_orderP,
+        enum byteorder *   const bit_orderP,
+        bool               const headerDump) {
+/*----------------------------------------------------------------------------
+   Read the header from the XWD image in input stream 'ifP'.  Leave
+   the stream positioned to the beginning of the raster.
+
+   Return various fields from the header.
+
+   Return as *padrightP the number of additional pixels of padding are
+   at the end of each line of input.  This says the input stream
+   contains *colsP pixels of image data plus *padrightP pixels of
+   padding.
+-----------------------------------------------------------------------------*/
+    /* Assume X11 headers are larger than X10 ones. */
+    unsigned char header[sizeof(X11WDFileHeader)];
+    X10WDFileHeader* h10P;
+    X11WDFileHeader* h11P;
+    int rc;
+
+    h10P = (X10WDFileHeader*) header;
+    h11P = (X11WDFileHeader*) header;
+    if ( sizeof(*h10P) > sizeof(*h11P) )
+        pm_error("ARGH!  On this machine, X10 headers are larger than "
+                 "X11 headers!\n    You will have to re-write xwdtopnm." );
+    
+    /* We read an X10 header's worth of data from the file, then look
+       at it to see if it looks like an X10 header.  If so we process
+       the X10 header.  If not, but it looks like the beginning of an
+       X11 header, we read more bytes so we have an X11 header's worth
+       of data, then process the X11 header.  Otherwise, we raise an
+       error.  
+    */
+
+    rc = fread(&header[0], sizeof(*h10P), 1, ifP);
+    if (rc != 1)
+        pm_error( "couldn't read XWD file header" );
+
+    if (h10P->file_version == X10WD_FILE_VERSION ||
+        pm_bs_long(h10P->file_version) == X10WD_FILE_VERSION) {
+        
+        if (verbose)
+            pm_message("Input is X10");
+        processX10Header(h10P, ifP, colsP, rowsP, padrightP, maxvalP, 
+                         visualclassP, formatP, 
+                         colorsP, bits_per_pixelP, bits_per_itemP, 
+                         red_maskP, green_maskP, blue_maskP, 
+                         byte_orderP, bit_orderP);
+    } else if (h11P->file_version == X11WD_FILE_VERSION ||
+               pm_bs_long(h11P->file_version) == X11WD_FILE_VERSION) {
+        
+        int rc;
+
+        if (verbose)
+            pm_message("Input is X11");
+
+        /* Read the balance of the X11 header */
+        rc = fread(&header[sizeof(*h10P)], 
+                   sizeof(*h11P) - sizeof(*h10P), 1, ifP);
+        if (rc != 1)
+            pm_error("couldn't read end of X11 XWD file header");
+
+        if (headerDump)
+            dumpX11Header(h11P);
+
+        processX11Header(h11P, ifP, colsP, rowsP, padrightP, maxvalP, 
+                         visualclassP, formatP, 
+                         colorsP, bits_per_pixelP, bits_per_itemP, 
+                         red_maskP, green_maskP, blue_maskP, 
+                         byte_orderP, bit_orderP);
+    } else
+        pm_error("unknown XWD file version: %u", h11P->file_version);
+}
+
+
+
+#ifdef DEBUG_PIXEL
+#define DEBUG_PIXEL_1 \
+   if (pixel_count < 4) \
+       pm_message("getting pixel %d", pixel_count);
+
+#define DEBUG_PIXEL_2 \
+    if (pixel_count < 4) \
+        pm_message("item: %.8lx", row_controlP->item.l); 
+
+
+#define DEBUG_PIXEL_3 \
+    if (pixel_count < 4) \
+        pm_message("  bits_taken: %lx(%d), carryover_bits: %lx(%d), " \
+                     "pixel: %lx", \
+                     bits_taken, bits_to_take, row_controlP->carryover_bits, \
+                     row_controlP->bits_carried_over, pixel);
+
+#define DEBUG_PIXEL_4 \
+    if (pixel_count < 4) { \
+        pm_message("  row_control.bits_carried_over = %d" \
+                   "  carryover_bits= %.8lx", \
+                   row_controlP->bits_carried_over, \
+                   row_controlP->carryover_bits); \
+        pm_message("  row_control.bits_used = %d", \
+                   row_controlP->bits_used); \
+        pm_message("  row_control.bits_left = %d", \
+                   row_controlP->bits_left); \
+                   } \
+    \
+    pixel_count++;
+#else
+#define DEBUG_PIXEL_1 do {} while(0)
+#define DEBUG_PIXEL_2 do {} while(0)
+#define DEBUG_PIXEL_3 do {} while(0)
+#define DEBUG_PIXEL_4 do {} while(0)
+#endif
+
+
+
+/*----------------------------------------------------------------------------
+   The pixel reader.
+
+   The pixel reader is an object that reads an XWD raster and gives you
+   one pixel at a time from it.
+
+   It consists of a structure of type 'pixelReader' and the
+   getpix() and pixelReaderInit() subroutines.
+-----------------------------------------------------------------------------*/
+
+typedef struct {
+    /* This structure contains the state of the getpix() reader as it
+       reads across a row in the input image.
+       */
+    FILE * fileP;
+    unsigned long itemBuffer;
+        /* The item buffer.  This contains what's left of the item
+           most recently read from the image file -- an item goes from the
+           XWD raster into here and then bits disappear from it as they
+           become part of pixels returned by the object.
+
+           '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 numeric value of the member is the number whose pure
+           binary representation is the bit string in the buffer.
+
+           That bit string starts out as the contents of one item of
+           the XWD raster, with the "byte order" value from the XWD
+           header applied.  E.g. Assume bits per item is 16 and the
+           and the "byte order" value is "MSB First".  Assume the
+           raster contains 0x01 at Offset 109 and 0x02 at Offset 110.
+           The value of this member just after that item is read is
+           two hundred fifty-eight.  If we are running on a
+           little-endian machine, it appears in memory as 0x02 at
+           Address A and 0x01 at Address A+1.
+
+           Then we pull bits from either the beginning or end of the
+           buffer according to the "bit order" value from the XWD
+           header.  E.g. in the example above, assume "bit order" is
+           lsb first.  and bits per pixel is 4.  After reading the
+           first pixel (0010b) from the buffer, 'itemBuffer' is
+           sixteen (0x010) and 'nBitsLeft' is 12.
+        */
+    unsigned int nBitsLeft;
+      /* This is the number of bits in the current item that have not yet
+         been returned as part of a pixel.
+      */
+    int bitsPerPixel;
+    int bitsPerItem;
+    enum byteorder byteOrder;
+    enum byteorder bitOrder;
+} pixelReader;
+
+
+
+static void
+pixelReaderInit(pixelReader *  const pixelReaderP,
+                FILE *         const fileP,
+                int            const bitsPerPixel,
+                int            const bitsPerItem, 
+                enum byteorder const byteOrder,
+                enum byteorder const bitOrder) {
+    
+    pixelReaderP->fileP           = fileP;
+    pixelReaderP->bitsPerPixel    = bitsPerPixel;
+    pixelReaderP->bitsPerItem     = bitsPerItem;
+    pixelReaderP->byteOrder       = byteOrder;
+    pixelReaderP->bitOrder        = bitOrder;
+
+    pixelReaderP->nBitsLeft       = 0;
+}    
+
+
+
+static void
+readItem(pixelReader * const rdrP) {
+/*----------------------------------------------------------------------------
+   Read one item from the XWD raster associated with pixel reader *rdrP.
+
+   Put the item into the item buffer of the pixel reader object *rdrP.
+-----------------------------------------------------------------------------*/
+    assert(rdrP->nBitsLeft == 0);
+
+    switch (rdrP->bitsPerItem) {
+    case 8: {
+        unsigned char const item8 = getc(rdrP->fileP);
+        rdrP->itemBuffer = item8;
+        rdrP->nBitsLeft = 8;
+    }
+        break;
+
+    case 16: {
+        short item16;
+
+        switch (rdrP->byteOrder) {
+        case MSBFirst:
+            pm_readbigshort(rdrP->fileP, &item16);
+            break;
+        case LSBFirst:
+            pm_readlittleshort(rdrP->fileP, &item16);
+            break;
+        }
+        rdrP->itemBuffer = (unsigned short)item16;
+        rdrP->nBitsLeft = 16;
+    }
+        break;
+        
+    case 32: {
+        long item32;
+        
+        switch (rdrP->byteOrder) {
+        case MSBFirst:
+            pm_readbiglong(rdrP->fileP, &item32);
+            break;
+        case LSBFirst:
+            pm_readlittlelong(rdrP->fileP, &item32);
+            break;
+        }
+        rdrP->itemBuffer = item32;
+        rdrP->nBitsLeft = 32;
+    }
+        break;
+    default:
+        pm_error("INTERNAL ERROR: impossible bits_per_item");
+    }
+}
+
+
+
+static unsigned long const lsbmask[] = {
+/*----------------------------------------------------------------------------
+   lsbmask[i] is the mask you use to select the i least signficant bits
+   of a bit string.
+-----------------------------------------------------------------------------*/
+    0x00000000,
+    0x00000001, 0x00000003, 0x00000007, 0x0000000f, 
+    0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
+    0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
+    0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
+    0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
+    0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
+    0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
+    0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff
+};
+
+
+static unsigned long
+getpix(pixelReader * const rdrP) {
+/*----------------------------------------------------------------------------
+   Get a pixel from the input image.
+
+   A pixel is a bit string.  It may be either an rgb triplet or an index
+   into the colormap (or even an rgb triplet of indices into the colormaps!).
+   We don't care -- it's just a bit string.
+
+   We return an integer.  It's the integer that the pixel represents as
+   pure binary cipher, with the first bit the most significant bit.
+   
+   The basic unit of storage in the input file is an "item."  An item
+   can be 1, 2, or 4 bytes, and 'bits_per_item' tells us which.  Each
+   item can have its bytes stored in forward or reverse order, and
+   'byte_order' tells us which.
+
+   Each item can contain one or more pixels, and may contain
+   fractional pixels.  'bits_per_pixel' tells us how many bits each
+   pixel has, and 'bits_per_pixel' is always less than or equal to
+   'bits_per_item', but not necessarily a factor of it.  Within an item,
+   after taking care of the endianness of its storage format, the pixels
+   may be arranged from left to right or right to left.  'bit_order' tells
+   us which.
+
+   But it's not that simple.  Sometimes dummy pixels are added to the
+   right edge of the image in order to make an integral number of
+   items in each row of the raster.  getpix() doesn't know anything
+   about that, though -- it gets the dummy pixels the same as any
+   other pixel.  (This program is written as if it is always whole
+   pixels that get added for padding, but I wonder.  When pixels are 3
+   or 4 bytes and items are 4 bytes, sub-pixel padding would make
+   sense.  But then, maybe in formats with 3 or 4 bytes pixels,
+   there's never padding.  That seems to be the case so far...).  The
+   XWD header has a field that tells how many bytes there are per XWD
+   raster line, so that's the final word on how much padding there is.
+   
+   The most difficult part of getting the pixel is the ones that span
+   items.  We detect when an item has part, but not all, of the next
+   pixel (after the one we return) in it and store the fragment as
+   "carryover" bits for use in the next call to this function.
+
+   All this state information (carryover bits, etc.) is kept in 
+   *row_controlP.
+
+-----------------------------------------------------------------------------*/
+    unsigned long pixel;
+        /* Accumulator for the value we ultimately return.  We shift in
+           bits from the right end.  The number of bits presently in the
+           accumulator is rdrP->bitsPerPixel - bitsStillNeeded .
+        */
+    
+    unsigned int nBitsStillNeeded;
+        /* How many bits we still need to add to 'pixel',
+           as we build it up to the
+           full amount we have to return.  The bits are right justified in
+           it -- additional bits will shift in from the right.
+        */
+
+    assert(rdrP->bitsPerPixel <= 32);
+
+    pixel = 0;
+    nBitsStillNeeded = rdrP->bitsPerPixel;
+
+    while (nBitsStillNeeded > 0) {
+        if (rdrP->nBitsLeft == 0)
+            /* Buffer's empty.  Have to go back to the well for
+               rdrP->bitsPerItem more bits.
+            */
+            readItem(rdrP);
+
+        {
+            unsigned int const nBitsToTake =
+                MIN(rdrP->nBitsLeft, nBitsStillNeeded);
+            unsigned long const bitsToTakeMask = lsbmask[nBitsToTake];
+                /* E.g. if nbitsToTake is 4, this is 0x0000000F */
+
+            unsigned long bitsToTake;
+                /* The actual bits we take, in the 'nBitsToTake' low bits */
+
+            assert(nBitsToTake <= 32);
+            
+            if (rdrP->bitOrder == MSBFirst) {
+                unsigned int const nBitsToLeave =
+                    rdrP->nBitsLeft - nBitsToTake;
+                bitsToTake =
+                    (rdrP->itemBuffer >> nBitsToLeave) & bitsToTakeMask;
+            } else {
+                bitsToTake = rdrP->itemBuffer & bitsToTakeMask;
+                rdrP->itemBuffer >>= nBitsToTake;
+            }                
+            /* Shift the bits into the right end of the accumulator */
+            pixel <<= nBitsToTake;
+            pixel |= bitsToTake;
+
+            rdrP->nBitsLeft -= nBitsToTake;
+            nBitsStillNeeded -= nBitsToTake;
+        }
+    }
+    return pixel;
+}
+
+
+
+static void
+reportInfo(int              const cols, 
+           int              const rows, 
+           int              const padright, 
+           xelval           const maxval, 
+           enum visualclass const visualclass,
+           int              const format, 
+           int              const bits_per_pixel,
+           int              const bits_per_item, 
+           int              const red_mask, 
+           int              const green_mask, 
+           int              const blue_mask,
+           enum byteorder   const byte_order, 
+           enum byteorder   const bit_order) {
+    
+    const char *visualclass_name;
+    const char *byte_order_name;
+    const char *bit_order_name;
+    switch (visualclass) {
+    case StaticGray:  visualclass_name="StaticGray";  break;
+    case GrayScale:   visualclass_name="Grayscale";   break;
+    case StaticColor: visualclass_name="StaticColor"; break;
+    case PseudoColor: visualclass_name="PseudoColor"; break;
+    case TrueColor:   visualclass_name="TrueColor";   break;
+    case DirectColor: visualclass_name="DirectColor"; break;
+    default:          visualclass_name="(invalid)";    break;
+    }
+    switch (byte_order) {
+    case MSBFirst: byte_order_name = "MSBFirst";  break;
+    case LSBFirst: byte_order_name = "LSBFirst";  break;
+    default:       byte_order_name = "(invalid)"; break;
+    }
+    switch (bit_order) {
+    case MSBFirst: bit_order_name = "MSBFirst";  break;
+    case LSBFirst: bit_order_name = "LSBFirst";  break;
+    default:       bit_order_name = "(invalid)"; break;
+    }
+    pm_message("%d rows of %d columns with maxval %d",
+               rows, cols, maxval);
+    pm_message("padright=%d.  visualclass = %s.  format=%d (%c%c)",
+               padright, visualclass_name, 
+               format, format/256, format%256);
+    pm_message("bits_per_pixel=%d; bits_per_item=%d",
+               bits_per_pixel, bits_per_item);
+    pm_message("byte_order=%s; bit_order=%s",
+               byte_order_name, bit_order_name);
+    pm_message("red_mask=0x%.8x; green_mask=0x%.8x; blue_mask=0x%.8x",
+               red_mask, green_mask, blue_mask);
+}
+
+
+
+static void 
+convertRowSimpleIndex(pixelReader *  const pixelReaderP,
+                      int            const cols,
+                      const xel *    const colors,
+                      xel *          const xelrow) {
+    
+    unsigned int col;
+    for (col = 0; col < cols; ++col)
+        xelrow[col] = colors[getpix(pixelReaderP)];
+}
+
+
+
+static void
+convertRowDirect(pixelReader *  const pixelReaderP,
+                 int            const cols,
+                 const xel *    const colors,
+                 unsigned long  const red_mask,
+                 unsigned long  const grn_mask,
+                 unsigned long  const blu_mask,
+                 xel *          const xelrow) {
+        
+    unsigned int col;
+
+    for (col = 0; col < cols; ++col) {
+        unsigned long pixel;
+            /* This is a triplet of indices into the color map, packed
+               into this bit string according to red_mask, etc.
+            */
+        unsigned int red_index, grn_index, blu_index;
+            /* These are indices into the color map, unpacked from 'pixel'.
+             */
+            
+        pixel = getpix(pixelReaderP);
+
+        red_index = (pixel & red_mask) >> zero_bits(red_mask);
+        grn_index = (pixel & grn_mask) >> zero_bits(grn_mask); 
+        blu_index = (pixel & blu_mask) >> zero_bits(blu_mask);
+
+        PPM_ASSIGN(xelrow[col],
+                   PPM_GETR(colors[red_index]),
+                   PPM_GETG(colors[grn_index]),
+                   PPM_GETB(colors[blu_index])
+            );
+    }
+}
+
+
+
+static void
+convertRowTrueColor(pixelReader *  const pixelReaderP,
+                    int                  const cols,
+                    pixval               const maxval,
+                    const xel *          const colors,
+                    unsigned long        const red_mask,
+                    unsigned long        const grn_mask,
+                    unsigned long        const blu_mask,
+                    xel *                const xelrow) {
+
+    unsigned int col;
+    unsigned int red_shift, grn_shift, blu_shift;
+    unsigned int red_maxval, grn_maxval, blu_maxval;
+
+    red_shift = zero_bits(red_mask);
+    grn_shift = zero_bits(grn_mask);
+    blu_shift = zero_bits(blu_mask);
+
+    red_maxval = red_mask >> red_shift;
+    grn_maxval = grn_mask >> grn_shift;
+    blu_maxval = blu_mask >> blu_shift;
+
+    for (col = 0; col < cols; ++col) {
+        unsigned long pixel;
+
+        pixel = getpix(pixelReaderP);
+
+        /* The parsing of 'pixel' used to be done with hardcoded layout
+           parameters.  See comments at end of this file.
+        */
+        PPM_ASSIGN(xelrow[col],
+                   ((pixel & red_mask) >> red_shift) * maxval / red_maxval,
+                   ((pixel & grn_mask) >> grn_shift) * maxval / grn_maxval,
+                   ((pixel & blu_mask) >> blu_shift) * maxval / blu_maxval
+            );
+
+    }
+}
+
+
+
+static void
+convertRow(pixelReader *    const pixelReaderP,
+           FILE *           const ofP,
+           int              const padright, 
+           int              const cols, 
+           xelval           const maxval,
+           int              const format, 
+           unsigned long    const red_mask, 
+           unsigned long    const green_mask, 
+           unsigned long    const blue_mask, 
+           const xel*       const colors, 
+           enum visualclass const visualclass) {
+/*----------------------------------------------------------------------------
+   Read a row from the XWD pixel input stream 'pixelReaderP' and write
+   it to the PNM output stream 'ofP'.
+
+   The row is 'cols' pixels.
+
+   After reading the 'cols' pixels, we read and discard an additional
+   'padright' pixels from the input stream, so as to read the entire
+   input line.
+-----------------------------------------------------------------------------*/
+    xel* xelrow;
+    xelrow = pnm_allocrow(cols);
+
+    switch (visualclass) {
+    case StaticGray:
+    case GrayScale:
+    case StaticColor:
+    case PseudoColor:
+        convertRowSimpleIndex(pixelReaderP, cols, colors, xelrow);
+        break;
+    case DirectColor: 
+        convertRowDirect(pixelReaderP, cols, colors,
+                         red_mask, green_mask, blue_mask,
+                         xelrow);
+        
+        break;
+    case TrueColor: 
+        convertRowTrueColor(pixelReaderP, cols, maxval, colors,
+                            red_mask, green_mask, blue_mask,
+                            xelrow);
+        break;
+            
+    default:
+        pm_error("unknown visual class");
+    }
+    {
+        unsigned int col;
+        for (col = 0; col < padright; ++col)
+            getpix(pixelReaderP);
+    }
+    pnm_writepnmrow(ofP, xelrow, cols, maxval, format, 0);
+    pnm_freerow(xelrow);
+}
+
+
+
+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:
+        pm_error("shouldn't happen");
+    }
+}
+
+
+
+int
+main(int argc, char *argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    int rows, cols, format, padright;
+    unsigned int row;
+    int bits_per_pixel;
+    int bits_per_item;
+    unsigned long red_mask, green_mask, blue_mask;
+    xelval maxval;
+    enum visualclass visualclass;
+    enum byteorder byte_order, bit_order;
+    xel *colors;  /* the color map */
+    pixelReader pixelReader;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    debug = cmdline.debug;
+    verbose = cmdline.verbose;
+
+    if (cmdline.input_filename != NULL) 
+        ifP = pm_openr(cmdline.input_filename);
+    else
+        ifP = stdin;
+
+    getinit(ifP, &cols, &rows, &padright, &maxval, &visualclass, &format, 
+            &colors, &bits_per_pixel, &bits_per_item, 
+            &red_mask, &green_mask, &blue_mask, &byte_order, &bit_order,
+            cmdline.headerdump);
+    
+    if (verbose) 
+        reportInfo(cols, rows, padright, maxval, visualclass,
+                   format, bits_per_pixel, bits_per_item,
+                   red_mask, green_mask, blue_mask, 
+                   byte_order, bit_order);
+
+    pixelReaderInit(&pixelReader, ifP, bits_per_pixel, bits_per_item,
+                    byte_order, bit_order);
+
+    pnm_writepnminit(stdout, cols, rows, maxval, format, 0);
+
+    reportOutputType(format);
+
+    for (row = 0; row < rows; ++row) {
+        convertRow(&pixelReader, stdout,
+                   padright, cols, maxval, format,
+                   red_mask, green_mask, blue_mask, colors, visualclass);
+    }
+    
+    pm_close(ifP);
+    pm_close(stdout);
+    
+    return 0;
+}
+
+
+/*
+   This used to be the way we parsed a direct/true color pixel.  I'm 
+   keeping it here in case we find out some application needs it this way.
+
+   There doesn't seem to be any reason to do this hard-coded stuff when
+   the header contains 32 bit masks that tell exactly how to extract the
+   3 colors in all cases.
+
+   We know for a fact that 16 bit TrueColor output from XFree86's xwd
+   doesn't match these hard-coded shift amounts, so we have replaced
+   this whole switch thing.  -Bryan 00.03.01
+
+   switch (bits_per_pixel) {
+                
+   case 16:
+       PPM_ASSIGN( *xP,
+                   ( ( ul & red_mask )   >> 0    ),
+                   ( ( ul & green_mask ) >> 5  ),
+                   ( ( ul & blue_mask )  >> 11) );
+       break;
+
+   case 24:
+   case 32:
+       PPM_ASSIGN( *xP, ( ( ul & 0xff0000 ) >> 16 ),
+                   ( ( ul & 0xff00 ) >> 8 ),
+                   ( ul & 0xff ) );
+       break;
+
+   default:
+       pm_error( "True/Direct is valid only with 16, 24, and 32 bits" );
+   }
+*/
diff --git a/converter/other/zeisstopnm.c b/converter/other/zeisstopnm.c
new file mode 100644
index 00000000..e94d9b44
--- /dev/null
+++ b/converter/other/zeisstopnm.c
@@ -0,0 +1,187 @@
+/* zeisstopnm.c - convert a Zeiss confocal image into a portable anymap
+**
+** Copyright (C) 1993 by Oliver Trepte, oliver@fysik4.kth.se
+**
+** Derived from the pbmplus package,
+** Copyright (C) 1989 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.
+**
+**
+** This conversion utility is based on a mail from Keith Bartels to
+** the confocal mail group (confocal@ubvm.cc.buffalo.edu) in June 1993.
+**
+** I'm including here a description of the Zeiss confocal image format. I
+** obtained this over the phone on 4-10-1991 form a Zeiss Engineer, and from
+** what I hear, it is probably not correct for the new scopes.
+** Zeiss puts its header information and the end of the file, so I call it
+** a tailer.  This is nice because most conversions programs that work with raw
+** image files will read the image simply ignore the tailer.  The file contains:
+**
+** The image data: NxN  1 byte pixels (where N is the number of pixels in a
+** scan line) in a standard raw rastering order.
+**
+** The tailer contains:
+** 256 bytes: the blue Look-Up-Table (LUT)
+** 256 bytes: the red LUT
+** 256 bytes: the green LUT
+** 8 bytes: empty
+** 2 bytes: no. of columns in the image. hi-byte, low-byte
+** 2 bytes: no. of rows in the image.
+** 2 bytes: x-position of upper left pixel  (0 for 512x512 images)
+** 2 bytes: y-position of upper left pixel  (0 for 512x512 images)
+** 16 bytes: empty
+** 32 bytes: test from upper right corner of image, ASCII.
+** 128 bytes: text from the bottom two rows of the screen, ASCII.
+** 64 bytes: reserved
+** -----------
+** 1024 bytes TOTAL
+**
+** So, image files contain NxN + 1024 bytes.
+**
+** Keith Bartels
+** keith@VISION.EE.UTEXAS.EDU
+**
+*/
+
+#include "pnm.h"
+
+int
+main( argc, argv )
+    int argc;
+    char* argv[];
+    {
+    FILE* ifp;
+    int argn, row, i;
+    register int col;
+    int rows=0, cols=0;
+    int format = 0;
+    xel* xelrow;
+    register xel* xP;
+    char* buf = NULL;
+    unsigned char *lutr, *lutg, *lutb;
+    long nread = 0;
+    unsigned char* byteP;
+    const char* const usage = "[-pgm|-ppm] [Zeissfile]";
+
+
+    pnm_init( &argc, argv );
+
+    argn = 1;
+
+    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
+	{
+	if ( pm_keymatch( argv[argn], "-pgm", 3 ) )
+	    {
+	    if ( argn >= argc )
+		pm_usage( usage );
+	    format = PGM_TYPE;
+	    }
+	else if ( pm_keymatch( argv[argn], "-ppm", 3 ) )
+	    {
+	    if ( argn >= argc )
+		pm_usage( usage );
+	    format = PPM_TYPE;
+	    }
+	else
+	    pm_usage( usage );
+	++argn;
+	}
+
+    if ( argn < argc )
+	{
+	ifp = pm_openr( argv[argn] );
+	++argn;
+	}
+    else
+	ifp = stdin;
+
+    if ( argn != argc )
+	pm_usage( usage );
+
+    /* Read the image to a buffer */
+
+    buf = pm_read_unknown_size( ifp, &nread );
+
+    /* Check the format of the file */
+
+    if (nread <=1024)
+	pm_error( "Input file not in Zeiss format (too small)" );
+
+    lutg = (unsigned char *)buf+(nread-1024+512);
+    lutr = (unsigned char *)buf+(nread-1024+256);
+    lutb = (unsigned char *)buf+(nread-1024);
+
+    cols = ((unsigned char) buf[nread-1024+768+8]) +
+	(((unsigned char) buf[nread-1024+768+9]) << 8);
+    rows = ((unsigned char) buf[nread-1024+768+10]) +
+	(((unsigned char) buf[nread-1024+768+11]) << 8);
+
+    if ( cols <= 0 )
+	pm_error( "invalid cols: %d", cols );
+    if ( rows <= 0 )
+	pm_error( "invalid rows: %d", rows );
+
+    if (cols*rows != nread-1024)
+	pm_error( "Hmm, %d rows, %d cols, %ld total image size",
+		 rows, cols, nread-1024);
+
+    /* Choose pgm or ppm */
+    /* If the LUTs all contain 0,1,2,3,4..255, it is a pgm file */
+
+    for (i=0; i<256 && format==0; i++)
+	if (lutr[i] != i || lutg[i] != i || lutb[i] != i)
+	    format = PPM_TYPE;
+
+    if (format == 0)
+	format = PGM_TYPE;
+
+    pnm_writepnminit( stdout, cols, rows, 255, format, 0 );
+    xelrow = pnm_allocrow( cols );
+    byteP = (unsigned char *) buf;
+
+    switch ( PNM_FORMAT_TYPE(format) )
+        {
+        case PGM_TYPE:
+        pm_message( "writing PGM file, %d rows %d columns", rows, cols );
+        break;
+
+        case PPM_TYPE:
+        pm_message( "writing PPM file, %d rows %d columns", rows, cols );
+        break;
+
+        default:
+        pm_error( "shouldn't happen" );
+        }
+
+    for ( row = 0; row < rows; ++row )
+    {
+	switch ( PNM_FORMAT_TYPE(format) )
+	{
+	case PGM_TYPE:
+	    for ( col = 0, xP = xelrow; col < cols; ++col, ++xP, ++byteP )
+		PNM_ASSIGN1( *xP, *byteP );
+	    break;
+
+	case PPM_TYPE:
+	    for ( col = 0, xP = xelrow; col < cols; ++col, ++xP, ++byteP )
+		PPM_ASSIGN( *xP, lutr[*byteP], lutg[*byteP], lutb[*byteP] );
+	    break;
+
+        default:
+	    pm_error( "shouldn't happen" );
+        }
+
+	pnm_writepnmrow( stdout, xelrow, cols, 255, format, 0 );
+    }
+
+    free( buf );
+    pm_close( stdout );
+
+    exit( 0 );
+}