You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 01:35:24