Example #1
0
        private byte[] EncodeColorInternal(Bitmap image, IProgressContext progress = null)
        {
            var paddedSize = _paddedSize?.Invoke(image.Size) ?? Size.Empty;
            var size       = paddedSize.IsEmpty ? image.Size : paddedSize;

            // If we have quantization enabled
            IEnumerable <Color> colors;

            if (_quantizer != null)
            {
                var scopedProgresses = progress?.SplitIntoEvenScopes(2);

                var(indices, palette) = QuantizeImage(image, paddedSize, scopedProgresses?[0]);

                // Recompose indices to colors
                var setMaxProgress = scopedProgresses?[1]?.SetMaxValue(image.Width * image.Height);
                colors = indices.ToColors(palette).AttachProgress(setMaxProgress, "Encode indices");
            }
            else
            {
                // Decompose image to colors
                var setMaxProgress = progress?.SetMaxValue(image.Width * image.Height);
                colors = image.ToColors(paddedSize, _swizzle?.Invoke(size)).AttachProgress(setMaxProgress, "Encode colors");
            }

            // Save color data
            return(_colorEncoding().Save(colors, new EncodingSaveContext(image.Size, _taskCount)));
        }
Example #2
0
        private Bitmap DecodeIndexInternal(byte[] data, byte[] paletteData, Size imageSize, IProgressContext progress)
        {
            ContractAssertions.IsTrue(IsIndexed, nameof(IsIndexed));

            var progresses = progress.SplitIntoEvenScopes(2);

            var paddedSize = _paddedSize?.Invoke(imageSize) ?? Size.Empty;

            var paletteEncoding = _paletteEncoding();
            var indexEncoding   = _indexEncoding();

            // Load palette
            var valueCount     = data.Length * 8 / paletteEncoding.BitsPerValue;
            var setMaxProgress = progresses?[0]?.SetMaxValue(valueCount * paletteEncoding.ColorsPerValue);
            var palette        = paletteEncoding
                                 .Load(paletteData, new EncodingLoadContext(imageSize, _taskCount))
                                 .AttachProgress(setMaxProgress, "Decode palette colors")
                                 .ToList();

            // Load indices
            valueCount     = data.Length * 8 / indexEncoding.BitsPerValue;
            setMaxProgress = progresses?[1]?.SetMaxValue(valueCount * indexEncoding.ColorsPerValue);
            var colors = indexEncoding
                         .Load(data, palette, new EncodingLoadContext(imageSize, _taskCount))
                         .AttachProgress(setMaxProgress, "Decode colors");

            return(colors.ToBitmap(imageSize, _swizzle?.Invoke(paddedSize.IsEmpty ? imageSize : paddedSize)));
        }
Example #3
0
        private Bitmap DecodeIndexInternal(byte[] data, byte[] paletteData, Size imageSize, IProgressContext progress)
        {
            ContractAssertions.IsTrue(IsIndexed, nameof(IsIndexed));

            var progresses = progress?.SplitIntoEvenScopes(2);

            // Prepare information and instances
            var paddedSize  = GetPaddedSize(imageSize);
            var swizzle     = GetPixelRemapper(_indexEncoding, paddedSize);
            var finalSize   = GetFinalSize(paddedSize, swizzle);
            var colorShader = _shadeColorsFunc?.Invoke();

            // Load palette
            var paletteColorCount = paletteData.Length * 8 / _paletteEncoding.BitsPerValue * _paletteEncoding.ColorsPerValue;

            var setMaxProgress     = progresses?[0]?.SetMaxValue(paletteColorCount * _paletteEncoding.ColorsPerValue);
            var paletteEnumeration = _paletteEncoding
                                     .Load(paletteData, new EncodingLoadContext(new Size(1, paletteColorCount), _taskCount))
                                     .AttachProgress(setMaxProgress, "Decode palette colors");

            // Apply color shader on palette
            var palette = colorShader != null?paletteEnumeration.Select(colorShader.Read).ToArray() : paletteEnumeration.ToArray();

            // Load indices
            setMaxProgress = progresses?[1]?.SetMaxValue(finalSize.Width * finalSize.Height);
            var colors = _indexEncoding
                         .Load(data, palette, new EncodingLoadContext(finalSize, _taskCount))
                         .AttachProgress(setMaxProgress, "Decode colors");

            return(colors.ToBitmap(imageSize, paddedSize, swizzle, _anchor));
        }
Example #4
0
        private Bitmap DecodeIndexInternal(byte[] data, byte[] paletteData, Size imageSize, IProgressContext progress)
        {
            ContractAssertions.IsTrue(IsIndexed, nameof(IsIndexed));

            var progresses = progress.SplitIntoEvenScopes(2);

            var paddedSize = _paddedSize?.Invoke(imageSize) ?? Size.Empty;

            var paletteEncoding = _paletteEncoding();
            var indexEncoding   = _indexEncoding(imageSize);

            // Load palette
            var valueCount     = data.Length * 8 / paletteEncoding.BitsPerValue;
            var setMaxProgress = progresses?[0]?.SetMaxValue(valueCount * paletteEncoding.ColorsPerValue);
            var palette        = paletteEncoding
                                 .Load(paletteData, _taskCount)
                                 .AttachProgress(setMaxProgress, "Decode palette colors")
                                 .ToList();

            // Load indices
            // TODO: Size is currently only used for block compression with native libs,
            // TODO: Those libs should retrieve the actual size of the image, not the padded dimensions
            // Yes, this even applies for index encodings, just in case
            valueCount     = data.Length * 8 / indexEncoding.BitsPerValue;
            setMaxProgress = progresses?[1]?.SetMaxValue(valueCount * indexEncoding.ColorsPerValue);
            var colors = indexEncoding
                         .Load(data, palette, _taskCount)
                         .AttachProgress(setMaxProgress, "Decode colors");

            return(colors.ToBitmap(imageSize, _swizzle?.Invoke(paddedSize.IsEmpty ? imageSize : paddedSize)));
        }
Example #5
0
        private byte[] EncodeColorInternal(Bitmap image, IProgressContext progress = null)
        {
            // Prepare information and instances
            var paddedSize  = GetPaddedSize(image.Size);
            var swizzle     = GetPixelRemapper(_colorEncoding, paddedSize);
            var finalSize   = GetFinalSize(paddedSize, swizzle);
            var colorShader = _shadeColorsFunc?.Invoke();

            // If we have quantization enabled
            IEnumerable <Color> colors;

            if (_quantizer != null)
            {
                var scopedProgresses = progress?.SplitIntoEvenScopes(2);

                // HINT: Color shader is applied by QuantizeImage
                var(indices, palette) = QuantizeImage(image, paddedSize, swizzle, scopedProgresses?[0]);

                // Recompose indices to colors
                var setMaxProgress = scopedProgresses?[1]?.SetMaxValue(finalSize.Width * finalSize.Height);
                colors = indices.ToColors(palette).AttachProgress(setMaxProgress, "Encode indices");
            }
            else
            {
                // Decompose image to colors
                var setMaxProgress = progress?.SetMaxValue(finalSize.Width * finalSize.Height);
                colors = image.ToColors(paddedSize, swizzle, _anchor).AttachProgress(setMaxProgress, "Encode colors");

                // Apply color shader
                if (colorShader != null)
                {
                    colors = colors.Select(colorShader.Write);
                }
            }

            // Save color data
            return(_colorEncoding.Save(colors, new EncodingSaveContext(finalSize, _taskCount)));
        }
Example #6
0
        public void Save(Stream output, IList <IArchiveFileInfo> files, IProgressContext progress)
        {
            // Prepare progressbar
            var splittedProgress = progress.SplitIntoEvenScopes(2);

            // Group files by directory
            var castedFiles = files.Cast <B123ArchiveFileInfo>();

            // Build directory, file, and name tables
            BuildTables(castedFiles, out var directoryEntries, out var directoryHashes, out var fileEntries, out var nameStream);

            // -- Write file --

            using var bw           = new BinaryWriterX(output);
            bw.BaseStream.Position = _headerSize;

            _header.dataOffset = (int)(_headerSize +
                                       directoryEntries.Count * _directoryEntrySize +
                                       directoryHashes.Count * _directoryHashSize +
                                       fileEntries.Count * _fileEntrySize +
                                       nameStream.Length + 3) & ~3;

            // Write file data
            var fileOffset = 0u;
            var fileIndex  = 1;

            foreach (var fileEntry in fileEntries)
            {
                splittedProgress[0].ReportProgress($"Write file data {fileIndex}/{fileEntries.Count}", fileIndex++, fileEntries.Count);

                bw.BaseStream.Position = _header.dataOffset + fileOffset;
                var writtenSize = fileEntry.SaveFileData(bw.BaseStream, null);

                fileEntry.Entry.fileOffset = fileOffset;
                fileEntry.Entry.fileSize   = (uint)writtenSize;

                fileOffset = (uint)(bw.BaseStream.Position - _header.dataOffset);
            }

            bw.BaseStream.Position = _headerSize;

            // Write directory entries
            _header.directoryCount         = directoryEntries.Count;
            _header.directoryEntriesCount  = (short)directoryEntries.Count;
            _header.directoryEntriesOffset = _headerSize;

            splittedProgress[1].ReportProgress("Write directory entries", 0, 4);
            bw.WriteMultiple(directoryEntries);

            // Write directory hashes
            _header.directoryHashCount  = (short)directoryHashes.Count;
            _header.directoryHashOffset = (int)bw.BaseStream.Position;

            splittedProgress[1].ReportProgress("Write directory hashes", 1, 4);
            bw.WriteMultiple(directoryHashes);

            // Write file entry hashes
            _header.fileCount         = fileEntries.Count;
            _header.fileEntriesCount  = fileEntries.Count;
            _header.fileEntriesOffset = (int)bw.BaseStream.Position;

            splittedProgress[1].ReportProgress("Write file entries", 2, 4);
            bw.WriteMultiple(fileEntries.Select(x => x.Entry));

            // Write name table
            _header.nameOffset     = (int)bw.BaseStream.Position;
            _header.tableChunkSize = (int)((_header.nameOffset + nameStream.Length + 3) & ~3) - _headerSize;

            splittedProgress[1].ReportProgress("Write file & directory names", 3, 4);
            nameStream.Position = 0;
            nameStream.CopyTo(bw.BaseStream);
            bw.WriteAlignment(4);

            // Write header
            bw.BaseStream.Position = 0;
            bw.WriteType(_header);

            splittedProgress[1].ReportProgress("Done", 4, 4);
        }