I'm trying to decompress an lz4-compressed png image with the Swift Compression package, but the code exits with a zero size. My code is as follows, and the decompressed file is expected to be 240Kb.
[UPDATE 2] I've stumbled upon this in the Apple's doc:
The frame is documented here so that you can easily wrap another LZ4 encoder/decoder to produce/consume the same data stream if necessary. An LZ4 encoded buffer is a sequence of blocks, each of which begins with a header. There are three possible headers:
A compressed block header consists of the octets 0x62, 0x76, 0x34, and 0x31, followed by the size in bytes of the decoded (plaintext) data represented by the block and the size (in bytes) of the encoded data stored in the block. Both size fields are stored as (possibly unaligned) 32-bit little-endian values. The compressed block header is followed immediately by the actual LZ4-encoded data stream.
An end of stream header consists of the octets 0x62, 0x76, 0x34, and 0x24 and marks the end of the LZ4 frame. No further data may be written or read beyond this header.
So I added the header and footer accordingly and it works. BUT —there's always a 'but'—, how can I know "the size in bytes of the decoded (plaintext) data" prior to uncompress?
[UPDATE 1]
I give one LZ4 file for you to test, and code usage for decompressing it from the main bundle.
LZ4 file compressed with the sw "LZ4 command line interface 64-bits v1.8.0, by Yann Collet" widely available on the Internet
https://drive.google.com/file/d/1eQ204LJs_xsHRwJ_jUcl1Up9NFo8monO/view?usp=sharing
LZ4 decompression usage
if let url = Bundle.main.url(forResource: "TestImage300.png", withExtension: "lz4") {
if let compressed = try? Data(contentsOf: url) {
if let decompressed = compressed.lz4Decompress() {
if let image = UIImage(data: decompressed) {
self.sourceImages.append(image)
print("Unittest: Decompressed image as \(image)")
}
}
}
}
LZ4 Data extension code for decompression:
import Foundation
import Compression
extension Data {
func lz4Decompress() -> Data? {
let destinationBufferSize: size_t = 480000
let destinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: destinationBufferSize)
let sourceBufferSize = count
let decompressed = withUnsafeBytes { (sourceBuffer: UnsafePointer<UInt8>) -> Data? in
let size = compression_decode_buffer(
destinationBuffer, destinationBufferSize,
sourceBuffer, sourceBufferSize,
nil, // scratch buffer automatically handled
COMPRESSION_LZ4
)
if size == 0 {
print("Error ")
return nil
}
print("Original compressed size: \(sourceBufferSize) | Decompressed size: \(size)")
return Data(bytesNoCopy: destinationBuffer, count: size, deallocator: .free)
}
return decompressed
}
}
let intArray: [Int8] = [-16, 1, 1, 39, 0, 19, 11, -30, 7, 10, 29, 14, 0, 0, 0, 0, 96, 9, 6, 0, 1, 2, 0, 17, 14, 6, 0, 2, 2, 0, 18, 14, 7, 0, 65, 0, 0, 0, -51, 6, 0, 0, 2, 0, 0, 43, 0, 16, 2, 9, 0, -1, 13, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 10, 4, 0, 64, 33, -105, 58, 115, 0, 12, 2, 0, 80, 0, 0, 0, 0, 0]
let uintArray = intArray.map { UInt8(bitPattern: $0) }
// For Visibility the uintArray unsigned is [240, 1, 1, 39, 0, 19, 11, 226, 7, 10, 29, 14, 0, 0, 0, 0, 96, 9, 6, 0, 1, 2, 0, 17, 14, 6, 0, 2, 2, 0, 18, 14, 7, 0, 65, 0, 0, 0, 205, 6, 0, 0, 2, 0, 0, 43, 0, 16, 2, 9, 0, 255, 13, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 10, 4, 0, 64, 33, 151, 58, 115, 0, 12, 2, 0, 80, 0, 0, 0, 0, 0]
var encodedData = Data.init(bytes:uintArray)
let decodedCapacity = 205
let decodedDestinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: decodedCapacity)
let decodedData = encodedData.withUnsafeBytes {
(encodedSourceBuffer: UnsafePointer<UInt8>) -> Data? in
let decodedCharCount = compression_decode_buffer(decodedDestinationBuffer,
decodedCapacity,
encodedSourceBuffer,
encodedData.count,
nil,
COMPRESSION_LZ4_RAW)
if decodedCharCount == 0 {
fatalError("Decoding failed.")
}
print("Before: \(encodedSourceBuffer) | After: \(decodedCharCount)")
return Data(bytesNoCopy: decodedDestinationBuffer, count: decodedCharCount, deallocator: .free)
}
You should use COMPRESSION_LZ4_RAW in a case you dont have headers defined in the compression
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With