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))); }
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))); }
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)); }
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))); }
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))); }
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); }