RasterfileConvertersImpl.mesa
Copyright Ó 1991, 1992 by Xerox Corporation. All rights reserved.
Spreitze, September 11, 1991 2:58 pm PDT
Willie-s, April 2, 1992 7:51 pm PST
DIRECTORY Basics, Commander, CommanderOps, Convert, FS, Imager, ImagerColor, ImagerError, ImagerDither, ImagerDitherContext, ImagerInterpress, ImagerPixel, ImagerSample, InterpressInterpreter, IO, RasterfileConverters, Real, RefText, Rope, SF;
RasterfileConvertersImpl:
CEDAR
PROGRAM
IMPORTS Basics, Commander, CommanderOps, Convert, FS, Imager, ImagerColor, ImagerError, ImagerDitherContext, ImagerInterpress, ImagerPixel, ImagerSample, InterpressInterpreter, IO, Real, RefText, Rope
EXPORTS RasterfileConverters
= BEGIN
ROPE: TYPE ~ Rope.ROPE;
Error: PUBLIC ERROR [explanation: ROPE] ~ CODE;
WriteRasterfile:
PUBLIC
PROC [filename:
ROPE, rsm: ImagerSample.RasterSampleMap, ime: ImagerDither.MapEntries] ~ {
out: IO.STREAM ~ FS.StreamOpen[filename, create];
size: SF.Vec ~ rsm.GetSize[];
lineBits, lineBytes: INT;
rBuf: REF TEXT ¬ RefText.ObtainScratch[256];
gBuf: REF TEXT ¬ RefText.ObtainScratch[256];
bBuf: REF TEXT ¬ RefText.ObtainScratch[256];
maxIndex, nIndex: NAT ¬ 0;
ub: Basics.UnsafeBlock;
PutInt[out, 59a66a95h];
PutInt[out, size.f];
PutInt[out, size.s];
IF rsm.GetBitsPerSample[] # 8 THEN ERROR;
PutInt[out, 8];
lineBytes ¬ ((size.f+1)/2) * 2;
PutInt[out, lineBytes*size.s];
PutInt[out, 1--RT¬STANDARD--];
PutInt[out, 1--RMT¬EQUAL¬RGB--];
FOR ime ¬ ime, ime.rest
WHILE ime#
NIL
DO
rBuf[ime.first.mapIndex] ¬ VAL[ime.first.red];
gBuf[ime.first.mapIndex] ¬ VAL[ime.first.green];
bBuf[ime.first.mapIndex] ¬ VAL[ime.first.blue];
maxIndex ¬ MAX[maxIndex, ime.first.mapIndex];
nIndex ¬ nIndex.SUCC;
ENDLOOP;
IF maxIndex # nIndex.PRED THEN Error["Colormap to output has gaps"];
PutInt[out, nIndex*3];
out.PutBlock[rBuf, 0, nIndex];
out.PutBlock[gBuf, 0, nIndex];
out.PutBlock[bBuf, 0, nIndex];
lineBits ¬ rsm.GetBitsPerLine[];
IF lineBits/8 # lineBytes THEN Error["Unimplemented sample map layout"];
ub ¬ rsm.GetUnsafeBlock[];
TRUSTED {IO.UnsafePutBlock[out, ub]};
out.Close[];
RefText.ReleaseScratch[rBuf];
RefText.ReleaseScratch[gBuf];
RefText.ReleaseScratch[bBuf];
RETURN};
ReadRasterfile:
PROC [filename:
ROPE, wantImage, wantCo, wantIme:
BOOL]
RETURNS [size:
SF.Vec, rsm: ImagerSample.RasterSampleMap, co: ImagerColor.ColorOperator, ime: ImagerDither.MapEntries] ~ {
in: IO.STREAM ~ FS.StreamOpen[filename];
magic: INT ~ GetInt[in];
IF magic # 59a66a95h THEN Error[IO.PutFR["%g not a rasterfile (magic number is %xh instead of 59a66a95h)", [rope[filename]], [integer[magic]] ]];
{width: INT ~ GetInt[in];
height: INT ~ GetInt[in];
depth: INT ~ GetInt[in];
length: INT ¬ GetInt[in];
type: INT ¬ GetInt[in];
maptype: INT ¬ GetInt[in];
maplength: INT ¬ GetInt[in];
lineBits, bytesRead: INT;
ub: Basics.UnsafeBlock;
IF width<0 OR height<0 OR depth<0 THEN Error["negative width, height, or depth"];
size ¬ [s: height, f: width];
IF maplength<0 OR length<0 THEN Error["negative image or colormap length"];
IF type#1 AND type#0 THEN Error[IO.PutFR1["unsupported type (%g)", [integer[type]] ]];
lineBits ¬ (((width * depth) + 15) / 16) * 16;
IF length=0
THEN length ¬ (lineBits/8) * height
ELSE IF length # (lineBits/8) * height THEN Error[IO.PutFLR["image length (%g) inconsistent with width, height, depth (%g, %g, %g)",
LIST[ [integer[length]], [integer[width]], [integer[height]], [integer[depth]]] ]];
IF maptype#1 AND maptype#0 THEN Error[IO.PutFR1["unsupported colormap type (%g)", [integer[maptype]] ]];
IF (maptype=1) # (maplength>0) THEN Error["malformed rasterfile (colormap length inconsistent with type)"];
IF maptype=1
THEN {
n: CARD ~ maplength/3;
mapStart: INT ~ IO.GetIndex[in];
rBuf: REF TEXT ¬ RefText.ObtainScratch[256];
gBuf: REF TEXT ¬ RefText.ObtainScratch[256];
bBuf: REF TEXT ¬ RefText.ObtainScratch[256];
Map:
PROC [i:
CARD]
RETURNS [color: ImagerColor.ConstantColor] ~ {
IF i >= n THEN RETURN [Imager.white];
RETURN [ImagerColor.ColorFromRGB[[R: rBuf[i].ORD/255.0, G: gBuf[i].ORD/255.0, B: bBuf[i].ORD/255.0]]]};
IF n*3 # CARD[maplength] THEN Error["malformed rasterfile (colormap length not a multiple of 3)"];
IF n # in.GetBlock[rBuf, 0, n] THEN Error["rasterfile eof in red colormap entries"];
IF n # in.GetBlock[gBuf, 0, n] THEN Error["rasterfile eof in green colormap entries"];
IF n # in.GetBlock[bBuf, 0, n] THEN Error["rasterfile eof in blue colormap entries"];
IF wantIme
THEN {
ime ¬ NIL;
FOR i:
CARD
IN [0..n)
DO
ime ¬ CONS[[i, rBuf[i].ORD, gBuf[i].ORD, bBuf[i].ORD], ime];
ENDLOOP;
ime ¬ ime}
ELSE ime ¬ NIL;
IF wantCo
THEN co ¬ ImagerColor.NewColorOperatorMap[2**depth - 1, Map]
ELSE co ¬ NIL;
RefText.ReleaseScratch[rBuf];
RefText.ReleaseScratch[gBuf];
RefText.ReleaseScratch[bBuf];
}
ELSE {co ¬ NIL; ime ¬ NIL};
IF wantImage
THEN {
rsm ¬ ImagerSample.NewSampleMap[box: [min: [0, 0], max: [s: height, f: width]], bitsPerSample: depth, bitsPerLine: lineBits];
ub ¬ rsm.GetUnsafeBlock[];
IF ub.count # length THEN Error[IO.PutFR["raster sample map created with inconsistent format (count %g # length %g)", [cardinal[ub.count]], [integer[length]] ]];
TRUSTED {bytesRead ¬ IO.UnsafeGetBlock[in, ub]};
IF bytesRead#length THEN Error[IO.PutFR["wrong number of image bytes read (%g instead of %g)", [integer[bytesRead]], [integer[length]] ]];
}
ELSE rsm ¬ NIL;
in.Close[];
RETURN}};
RasterfileToIp:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF ¬
NIL, msg:
ROPE ¬
NIL]
--Commander.CommandProc-- ~ {
argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd];
rsm: ImagerSample.RasterSampleMap;
pSize: SF.Vec;
co: ImagerColor.ColorOperator;
pm: ImagerPixel.PixelMap;
master: ImagerInterpress.Ref;
ppi: REAL;
PaintPage:
PROC [context: Imager.Context] ~ {
Imager.DrawPixels[context, pm, co, [0, 0], [slow: down, fast: right], [x: 0, y: pSize.s] ];
RETURN};
IF argv.argc#5 OR NOT argv[2].Equal["←"] THEN RETURN [$Failue, "Usage: RasterfileToIp <ip name> ← <rasterfile name> <pixels per inch>"];
ppi ¬ Convert.RealFromRope[argv[4]];
[, rsm, co, ] ¬ ReadRasterfile[argv[3],
TRUE,
TRUE,
FALSE !
Error => CommanderOps.Failed[explanation]
];
pSize ¬ rsm.GetSize[];
pm ¬ ImagerPixel.MakePixelMap[rsm];
master ¬ ImagerInterpress.Create[argv[1]];
master.DoPage[PaintPage, Imager.metersPerInch/ppi];
master.Close[];
cmd.out.PutFL["%g ← %g pixel, %g inch by %g pixel, %g inch image.\n",
LIST[ [rope[argv[1]]],
[integer[pSize.f]], [real[pSize.f/ppi]],
[integer[pSize.s]], [real[pSize.s/ppi]]] ];
RETURN};
DitherLikeRasterfile:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF ¬
NIL, msg:
ROPE ¬
NIL]
--Commander.CommandProc-- ~ {
argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd];
ime: ImagerDither.MapEntries;
master: InterpressInterpreter.Master;
ppi, widthI, heightI: REAL;
widthP, heightP, lineBits: INT;
iSize: SF.Vec;
rsm: ImagerSample.RasterSampleMap;
context: Imager.Context;
Log: InterpressInterpreter.LogProc ~ {
cmd.out.PutF["Interpress message: class=%g, code=%g, explanation=%g\n", [integer[class]], [atom[ImagerError.AtomFromErrorCode[code]]], [rope[explanation]] ];
RETURN};
IF (argv.argc#6 AND argv.argc#8) OR NOT argv[2].Equal["←"] THEN RETURN [$Failue, "Usage: DitherLikeRasterfile <rasterfile image output> ← <IP image input> <rasterfile colormap[&size] input> <ppi> [<width inches> <height inches>]"];
master ¬ InterpressInterpreter.Open[argv[3], Log];
[iSize,,,ime] ¬ ReadRasterfile[argv[4],
FALSE,
FALSE,
TRUE !
Error => CommanderOps.Failed[explanation]
];
ppi ¬ Convert.RealFromRope[argv[5]];
IF argv.argc>6
THEN {
widthI ¬ Convert.RealFromRope[argv[6]];
heightI ¬ Convert.RealFromRope[argv[7]];
widthP ¬ Real.Round[widthI*ppi];
heightP ¬ Real.Round[heightI*ppi]}
ELSE {
widthP ¬ iSize.f; widthI ¬ widthP/ppi;
heightP ¬ iSize.s; heightI ¬ heightP/ppi};
lineBits ¬ ((widthP+1)/2)*16;
IF lineBits # widthP*8 THEN RETURN [$Failure, "Not an even number of pixels per scan line."];
rsm ¬ ImagerSample.NewSampleMap[box: [min: [0, 0], max: [s: heightP, f: widthP]], bitsPerSample: 8, bitsPerLine: lineBits];
context ¬ ImagerDitherContext.Create[deviceSpaceSize: [s: heightP, f: widthP], scanMode: [slow: down, fast: right], surfaceUnitsPerInch: [ppi, ppi], pixelUnits: FALSE];
ImagerDitherContext.SetSampleMap[context, rsm];
ImagerDitherContext.SetDitherMap[context, ime];
master.DoPage[1, context, Log];
master.Close[];
WriteRasterfile[argv[1], rsm, ime !
Error => CommanderOps.Failed[explanation]
];
RETURN};
GetInt:
PROC [in:
IO.
STREAM]
RETURNS [
INT] ~ {
buf: Basics.FWORD;
nRead: INT;
TRUSTED {nRead ¬ in.UnsafeGetBlock[[base: LOOPHOLE[@buf], count: BYTES[Basics.FWORD]]]};
IF nRead # 4 THEN IO.EndOfStream[in];
RETURN [Basics.Int32FromF[buf]]};
PutInt:
PROC [out:
IO.
STREAM, i:
INT] ~ {
buf: Basics.FWORD ¬ Basics.FFromInt32[i];
TRUSTED {out.UnsafePutBlock[[base: LOOPHOLE[@buf], count: BYTES[Basics.FWORD]]]};
RETURN};
Commander.Register["RasterfileToIp", RasterfileToIp, "<ip name> ← <rasterfile name> <pixels per inch> --- make Interpress file with a sampled color"];
Commander.Register["DitherLikeRasterfile", DitherLikeRasterfile, "<rasterfile image output> ← <IP image input> <rasterfile colormap[&size] input> <ppi> [<width inches> <height inches>] --- dither an IP file against the colormap in a rasterfile, producing another rasterfile"];
END.