private CompressedFrame CalculateFrameChanges(Frame[] frames, FrameType type, int frameNumber) { int x_inc = 0; int y_inc = 0; switch (type) { case FrameType.TransitionalLeft: x_inc = -1; break; case FrameType.TransitionalRight: x_inc = 1; break; case FrameType.TransitionalTop: y_inc = -1; break; case FrameType.TransitionalBottom: y_inc = 1; break; } var currentFrame = frames[frameNumber]; var prevFrame = frames[frameNumber - 1]; var changesPos = new List<Tuple<int, int>>(); for (int y = 0; y < FrameHeight; y++) { if (y + y_inc >= 0 && y + y_inc < FrameHeight) { var line = currentFrame.Lines[y + y_inc]; var prevLine = prevFrame.Lines[y]; for (int x = 0; x < FrameWidth; x++) { if (x + x_inc >= 0 && x + x_inc < FrameWidth) { if (line[x + x_inc] != prevLine[x]) changesPos.Add(new Tuple<int, int>(x + x_inc, y + y_inc)); } } } } var frameChanges = new List<FrameChange>(); var markedChanges = new bool[FrameHeight, FrameWidth]; if (type == FrameType.TransitionalLeft || type == FrameType.TransitionalRight) { int x = type == FrameType.TransitionalLeft ? FrameWidth - 1 : 0; var chars = new List<char>(); for (int y = 0; y < FrameHeight; y++) { markedChanges[y, x] = true; chars.Add(currentFrame.Lines[y][x]); } frameChanges.Add(new FrameChange { Type = FrameChangeType.Vertical, X = x, Y = 0, Chars = chars, Length = FrameHeight }); } else if (type == FrameType.TransitionalTop || type == FrameType.TransitionalBottom) { int y = type == FrameType.TransitionalTop ? FrameHeight - 1 : 0; var chars = new List<char>(); for (int x = 0; x < FrameWidth; x++) { markedChanges[y, x] = true; chars.Add(currentFrame.Lines[y][x]); } frameChanges.Add(new FrameChange { Type = FrameChangeType.Horizontal, X = 0, Y = y, Chars = chars, Length = FrameWidth }); } foreach (var changePos in changesPos) { if (!markedChanges[changePos.Item2, changePos.Item1]) { int lineXInd = FrameWidth; for (int x = changePos.Item1 + 1; x < FrameWidth; x++) if (changesPos.FirstOrDefault(pos => pos.Item1 == x && pos.Item2 == changePos.Item2) == null) { lineXInd = x; break; } int lineYInd = FrameHeight; for (int y = changePos.Item2 + 1; y < FrameHeight; y++) if (changesPos.FirstOrDefault(pos => pos.Item1 == changePos.Item1 && pos.Item2 == y) == null) { lineYInd = y; break; } var frameChange = new FrameChange { X = changePos.Item1, Y = changePos.Item2 }; if (lineXInd - changePos.Item1 >= lineYInd - changePos.Item2) { if (lineXInd - changePos.Item1 == 1) { frameChange.Type = FrameChangeType.One; frameChange.Length = 1; frameChange.Chars = new List<char>() { currentFrame.Lines[changePos.Item2][changePos.Item1], }; markedChanges[changePos.Item2, changePos.Item1] = true; } else { frameChange.Type = FrameChangeType.Horizontal; frameChange.Length = lineXInd - changePos.Item1; frameChange.Chars = new List<char>(); for (int x = 0; x < frameChange.Length; x++) { frameChange.Chars.Add(currentFrame.Lines[changePos.Item2][changePos.Item1 + x]); markedChanges[changePos.Item2, changePos.Item1 + x] = true; } } } else { frameChange.Type = FrameChangeType.Vertical; frameChange.Length = lineYInd - changePos.Item2; frameChange.Chars = new List<char>(); for (int y = 0; y < frameChange.Length; y++) { frameChange.Chars.Add(currentFrame.Lines[changePos.Item2 + y][changePos.Item1]); markedChanges[changePos.Item2 + y, changePos.Item1] = true; } } frameChanges.Add(frameChange); } } return new CompressedFrame { FrameChanges = frameChanges, FrameType = type }; }
private byte[] GetCompressedFrameBytes(HuffmanTree tree, Frame frame, CompressedFrame compressedFrame) { int transBitPos = 0; var transZipBytes = new byte[frame.Bytes.Length * 10]; Utils.AddInt(transZipBytes, ref transBitPos, frame.RepeatCount, 7); Utils.AddInt(transZipBytes, ref transBitPos, (int)compressedFrame.FrameType, 3); Utils.AddInt(transZipBytes, ref transBitPos, compressedFrame.FrameChanges.Count, 7); for (int i = 0; i < compressedFrame.FrameChanges.Count; i++) { var change = compressedFrame.FrameChanges[i]; Utils.AddInt(transZipBytes, ref transBitPos, (int)change.Type, 2); Utils.AddInt(transZipBytes, ref transBitPos, GetPos(change.X, change.Y), 10); if (change.Type == FrameChangeType.One) Utils.AddIntReversed(transZipBytes, ref transBitPos, tree.CompressedBytes[change.Chars[0]]); else { Utils.AddInt(transZipBytes, ref transBitPos, change.Length, change.Type == FrameChangeType.Horizontal ? 7 : 4); //HuffmanRle.Encode(tree, change.Chars.Select(c => (byte)c).ToArray(), ref transBitPos, transZipBytes, 5, 4); for (int j = 0; j < change.Chars.Count; j++) Utils.AddIntReversed(transZipBytes, ref transBitPos, tree.CompressedBytes[change.Chars[j]]); /*if (i == 0 && compressedFrame.FrameType != FrameType.Basic && compressedFrame.FrameType != FrameType.Transitional) HuffmanRle.Encode(tree, change.Chars.Select(c => (byte)c).ToArray(), ref transBitPos, transZipBytes, 5, 4); else for (int j = 0; j < change.Chars.Count; j++) Utils.AddIntReversed(transZipBytes, ref transBitPos, tree.CompressedBytes[change.Chars[j]]);*/ } } return transZipBytes.Take((transBitPos + 7) / 8).ToArray(); }
private Dictionary<FrameType, CompressedFrame> CalculateChangesForDifferentChangeTypes(Frame[] frames, int frameNumber) { var changes = new Dictionary<FrameType, CompressedFrame>(); changes.Add(FrameType.Transitional, CalculateFrameChanges(Frames, FrameType.Transitional, frameNumber)); changes.Add(FrameType.TransitionalLeft, CalculateFrameChanges(Frames, FrameType.TransitionalLeft, frameNumber)); changes.Add(FrameType.TransitionalRight, CalculateFrameChanges(Frames, FrameType.TransitionalRight, frameNumber)); changes.Add(FrameType.TransitionalTop, CalculateFrameChanges(Frames, FrameType.TransitionalTop, frameNumber)); changes.Add(FrameType.TransitionalBottom, CalculateFrameChanges(Frames, FrameType.TransitionalBottom, frameNumber)); return changes; }