Firebird数据库中Delphi压缩图像的JavaScript读取方法问询
图像数据处理分析与JavaScript读取方案
一、Delphi程序对图像的处理逻辑
从提供的代码来看,程序在将图像存入Firebird数据库前,对图像原始二进制数据执行了UCL库的NRV2E算法压缩——你找到的PNG相关代码是程序读取PNG文件内部IDAT块的逻辑,和数据库存储的压缩无关。具体处理流程如下:
1. 压缩流程(存入数据库时)
通过PackBuffer函数实现:
- 将原始图像数据写入内存流
- 调用
UclCompressStream,使用默认参数(压缩等级10,缓冲区大小$1000)执行NRV2E压缩 - 将压缩后的数据流重新写入原缓冲区,并更新缓冲区大小为压缩后的尺寸
2. 压缩数据的存储格式
从UclDeCompressStream的解压逻辑可反推出压缩数据的结构:
压缩数据由多个块组成,每个块格式为:
- 4字节无符号整数(小端字节序):表示当前压缩块的有效数据长度
r r字节的NRV2E压缩数据
每个压缩块解压后会生成固定长度的原始数据块,长度由ucl_output_block_size($1000)计算得出(对应代码中的变量a)
3. 解压流程(程序读取数据库时)
通过UnpackBuffer函数实现:
- 将数据库中读取的压缩数据写入内存流
- 调用
UclDeCompressStream,按上述块结构循环解压每个压缩块,拼接得到原始图像数据 - 将解压后的数据流写入缓冲区,更新缓冲区大小为原始图像尺寸
二、JavaScript正确读取的实现步骤
要在JavaScript中还原图像数据,需要实现NRV2E算法的解压,同时处理Delphi程序的块存储格式。
1. 核心步骤
- 解析压缩块结构:按顺序读取每个块的4字节长度值,再读取对应长度的压缩数据
- NRV2E解压:对每个压缩块执行NRV2E解压,得到原始数据块
- 拼接数据:将所有解压后的原始块拼接,得到完整的原始图像二进制数据
- 生成图像:将拼接后的二进制数据转为Blob,再创建URL或直接处理为图像
2. 关键注意事项
- 字节序处理:Delphi中的
Cardinal是小端字节序,JS读取4字节长度时需要转换为小端整数 - NRV2E算法实现:需要移植NRV2E的JavaScript版本,需匹配Delphi中使用的
ucl_nrv2e_decompress_asm_fast_safe_8(8位版本的NRV2E解压)
3. 示例代码框架
async function decompressUCL(data) { const view = new DataView(data); let offset = 0; const result = []; // UCL输出块大小,对应Delphi中的ucl_output_block_size($1000) const outputBlockSize = 0x1000 + 16; // NRV2E输出块大小通常为输入块+16字节冗余,需根据实际情况确认 while (offset < view.byteLength) { // 读取4字节的压缩块长度r(小端) const r = view.getUint32(offset, true); offset += 4; if (r === 0) break; // 结束标志 // 读取r字节的压缩数据 const compressedChunk = new Uint8Array(data.slice(offset, offset + r)); offset += r; // 执行NRV2E解压,得到outputBlockSize字节的原始数据 const decompressedChunk = nrv2eDecompress(compressedChunk, outputBlockSize); result.push(decompressedChunk); } // 拼接所有块,得到原始图像数据 return new Blob([...result]); } // 需实现NRV2E解压函数nrv2eDecompress,对应ucl_nrv2e_decompress_asm_fast_safe_8 function nrv2eDecompress(compressed, outputSize) { // 此处需移植NRV2E的解压逻辑,可参考UCL库的C语言实现 // 注意匹配fast_safe_8版本的解压逻辑 }
附:相关Delphi代码片段
压缩/解压核心函数
unit FIBPlusUCLStreams; interface procedure PackBuffer(var Buffer: PChar; var BufSize: LongInt); procedure UnpackBuffer(var Buffer: PChar; var BufSize: LongInt); implementation uses DIUclStreams, Classes; procedure PackBuffer(var Buffer: PChar; var BufSize: LongInt); var srcStream, dstStream: TStream; begin srcStream := TMemoryStream.Create; dstStream := TMemoryStream.Create; try srcStream.WriteBuffer(Buffer^, BufSize); srcStream.Position := 0; UclCompressStream(srcStream, dstStream); srcStream.Free; srcStream := nil; BufSize := dstStream.Size; dstStream.Position := 0; ReallocMem(Buffer, BufSize); dstStream.ReadBuffer(Buffer^, BufSize); finally if Assigned(srcStream) then srcStream.Free; dstStream.Free; end; end; procedure UnpackBuffer(var Buffer: PChar; var BufSize: LongInt); var srcStream,dstStream: TStream; begin srcStream := TMemoryStream.Create; dstStream := TMemoryStream.Create; try srcStream.WriteBuffer(Buffer^, BufSize); srcStream.Position := 0; UclDeCompressStream(srcStream, dstStream); srcStream.Free; srcStream:=nil; BufSize := dstStream.Size; dstStream.Position := 0; ReallocMem(Buffer, BufSize); dstStream.ReadBuffer(Buffer^, BufSize); finally if assigned(srcStream) then srcStream.Free; dstStream.Free; end; end;
UCL解压流实现
function UclDeCompressStream(const AInStream, AOutStream: TStream; const ABufferSize: Cardinal = $1000; const AOnProgress: TUclProgress = nil; const AUser: Pointer = nil): Boolean; label Fail; var b, s: ^Byte; a, f, r, InBytes, OutBytes: Cardinal; begin a := ucl_output_block_size(ABufferSize); InBytes := 0; OutBytes := 0; GetMem(b, a); try repeat f := AInStream.Read(r, SizeOf(r)); Result := f = 0; if Result then Break; Result := f = SizeOf(r); if not Result then Break; Result := r <= a; if not Result then Break; s := b; Inc(s, a - r); Result := Cardinal(AInStream.Read(s^, r)) = r; if not Result then Break; f := a; Result := ucl_nrv2e_decompress_asm_fast_safe_8(s, r, b, f, nil) = UCL_E_OK; if not Result then Break; Result := Cardinal(AOutStream.Write(b^, f)) = f; if not Result then Break; if Assigned(AOnProgress) then begin Inc(InBytes, r); Inc(OutBytes, f); AOnProgress(InBytes, OutBytes, AUser); end; until False; finally FreeMem(b); end; end;
内容的提问来源于stack exchange,提问作者Yurii
相关产品推荐
相关产品推荐

