<> <> <> <<>> DIRECTORY ColorEditOps, FS USING [StreamOpen], IO USING [Close, GetChar, EndOf, PutChar, RIS, ROS, RopeFromROS, STREAM], SampleMapOps USING [Clear, DoWithScratch, Fill, GetSample], SelectRegions USING [ApplyTRC, nullRectangle, TRCSequence, TRCSequenceRep]; ColorEditOpsImpl: CEDAR PROGRAM IMPORTS FS, IO, SampleMapOps, SelectRegions EXPORTS ColorEditOps ~ BEGIN OPEN ColorEditOps; LogApply: PUBLIC PROC [trc: REF TRC, sm: SampleMap, extent: Rectangle] RETURNS [rope: ROPE] ~ { <> stream: IO.STREAM ~ IO.ROS[]; FOR i: NAT IN [0..256) DO IO.PutChar[self: stream, char: VAL[trc[i]]]; ENDLOOP; SaveExtentOfMaskToStream[stream: stream, mask: sm, extent: extent]; rope _ IO.RopeFromROS[self: stream]; }; ApplyLog: PUBLIC PROC [changeLog: ROPE, sa: SampleArray] ~ { <> ApplyLogAction: PROC [sm: SampleMap] ~ { stream: IO.STREAM ~ IO.RIS[rope: changeLog]; trcs: SelectRegions.TRCSequence ~ NEW[SelectRegions.TRCSequenceRep[sa.n]]; trc: REF TRC ~ NEW[TRC]; extent: Rectangle; FOR i: NAT IN [0..trcs.n) DO trcs[i] _ trc; ENDLOOP; UNTIL IO.EndOf[self: stream] DO FOR i: NAT IN [0..256) DO trc[i] _ LOOPHOLE[IO.GetChar[self: stream]]; ENDLOOP; extent _ ReadExtentOfMaskFromStream[stream: stream, mask: sm]; SelectRegions.ApplyTRC[sm, sa, trcs, extent]; ENDLOOP; }; SampleMapOps.DoWithScratch[sSize: sa.sSize, fSize: sa.fSize, bitsPerSample: 1, action: ApplyLogAction]; }; extentFilePassword: CARDINAL ~ 30346; SaveExtentOfMask: PUBLIC PROC [mask: SampleMap, extent: Rectangle, fileName: ROPE] ~ { file: IO.STREAM ~ FS.StreamOpen[fileName: fileName, accessOptions: create]; SaveExtentOfMaskToStream[file, mask, extent]; IO.Close[self: file]; }; ReadExtentOfMask: PUBLIC PROC [mask: SampleMap, fileName: ROPE] RETURNS [extent: Rectangle] ~ { file: IO.STREAM ~ FS.StreamOpen[fileName: fileName]; extent _ ReadExtentOfMaskFromStream[file, mask]; }; SaveExtentOfMaskToStream: PUBLIC PROC [stream: IO.STREAM, mask: SampleMap, extent: Rectangle] ~ { PutCardinal: PROC [cardinal: CARDINAL] ~ { IO.PutChar[self: stream, char: VAL[cardinal/256]]; IO.PutChar[self: stream, char: VAL[cardinal MOD 256]]; }; bitsPerSample: [1..1] ~ mask.bitsPerSample; currentValue: CARDINAL _ 0; currentCount: CARDINAL _ 0; PutCardinal[extentFilePassword]; PutCardinal[mask.sSize]; PutCardinal[mask.fSize]; PutCardinal[extent.sMin]; PutCardinal[extent.sMax]; PutCardinal[extent.fMin]; PutCardinal[extent.fMax]; IF extent#SelectRegions.nullRectangle THEN { FOR s: CARDINAL IN [extent.sMin .. extent.sMax] DO FOR f: CARDINAL IN [extent.fMin .. extent.fMax] DO sample: CARDINAL ~ SampleMapOps.GetSample[sampleMap: mask, index: [s: s, f: f]]; SELECT TRUE FROM sample#currentValue => { PutCardinal[currentCount]; currentCount _ 1; currentValue _ 1 - currentValue; }; currentCount = CARDINAL.LAST-1 => { PutCardinal[CARDINAL.LAST]; currentCount _ 0; currentValue _ 1 - currentValue; }; ENDCASE => currentCount _ currentCount+1; ENDLOOP; ENDLOOP; }; IF currentCount#0 THEN PutCardinal[currentCount]; PutCardinal[extentFilePassword]; --Pad with the password }; ReadExtentOfMaskFromStream: PUBLIC PROC [stream: IO.STREAM, mask: SampleMap] RETURNS [extent: Rectangle] ~ { GetCardinal: PROC RETURNS [CARDINAL] ~ { hi: CARDINAL ~ LOOPHOLE[IO.GetChar[self: stream]]; lo: CARDINAL ~ LOOPHOLE[IO.GetChar[self: stream]]; RETURN [hi*256 + lo]; }; bitsPerSample: [1..1] ~ mask.bitsPerSample; currentValue: CARDINAL _ 0; currentCount: CARDINAL _ 0; IF GetCardinal[] # extentFilePassword THEN ERROR; IF GetCardinal[] # mask.sSize THEN ERROR; IF GetCardinal[] # mask.fSize THEN ERROR; extent.sMin _ GetCardinal[]; extent.sMax _ GetCardinal[]; extent.fMin _ GetCardinal[]; extent.fMax _ GetCardinal[]; SampleMapOps.Clear[mask]; IF extent=SelectRegions.nullRectangle THEN RETURN; currentCount _ GetCardinal[]; FOR s: CARDINAL IN [extent.sMin .. extent.sMax] DO f: CARDINAL _ extent.fMin; WHILE f ~> extent.fMax DO count: CARDINAL _ MIN[currentCount, extent.fMax+1-f]; IF currentValue=1 THEN SampleMapOps.Fill[dest: [sampleMap: mask, start: [s: s, f: f], size: [s: 1, f: count]], value: 1]; f _ f+count; currentCount _ currentCount - count; IF currentCount=0 THEN { currentValue _ 1-currentValue; currentCount _ GetCardinal[]; }; ENDLOOP; ENDLOOP; IF currentCount # extentFilePassword THEN ERROR; }; END.