Delphi - 将图像合并到新的单个文件并读取数据

时间:2014-04-21 16:31:46

标签: delphi

我正在寻找某种解决方案,以便能够将多个图像合并为一个文件,然后从该文件中逐个读取/显示这些图像;

这个想法的一个例子:

图像(jpeg,但是支持其他格式也很好。这个原理可能用于基本上将任何文件类型合并到最终文件)转换为十六进制或二进制数据,在开头(或两者,开头和结尾)会有一些标题(页眉/页脚)信息,比如让我们说文件类型,扩展名,名称,甚至可能是日期(虽然这些信息已经在文件本身,但我想要在标题中也是如此,因为 - >)以及一些锚点,所以当读取新的合并文件时,我可以识别文件的开始/结束,因此知道将哪个部分提取到某个临时位置(或者首选 - 内存),或直接显示为最初的文件类型。

对于每个文件,它不需要任何特殊的加密,因为它不是一些额外的超级安全的东西,它只是在一个文件+ exe中读取/写入该文件。

这在某种程度上是否可以像我想象的那样实现?

谢谢。

编辑: 该文件仍然需要具有一些基本的安全性。意思是,如果创建了新的文件类型,使用自定义分隔符,那很好,使用zip / rar,我至少使用密码保护......不会破坏,但对普通用户来说仍然是安全的......

2 个答案:

答案 0 :(得分:4)

我很惊讶之前没有人提到这个...为什么不只是使用SQLite?有一个免费的Google编写的加密选项,您可以使用BLOB存储您的所有图像,您可以拥有所需数量的其他字段甚至表来存储元数据,没有其他依赖项,它是小型,跨平台和单文件等。

SQLite网站吹嘘将SQLite用于应用程序文件格式的优势:

  1. 简化应用程序开发
  2. 单文档文档
  3. 高级查询语言
  4. 无障碍内容
  5. 跨平台
  6. 原子交易
  7. 增量和持续更新
  8. 易于扩展
  9. 性能
  10. 多个进程并发使用
  11. 多种编程语言
  12. 更好的应用
  13. http://sqlite.org/appfileformat.html

    我相信SQLite比任何其他解决方案更能满足您的需求,包括迄今为止最容易实施的解决方案。

    并且在个人注意事项上...请在此之后再请三次,然后再两次,然后再释放另一种专有的,未记录的,自定义的文件格式。然后再想一想,然后在决定之前看看Linus Torvalds和Richard Stallman的照片。 :-)所有进行了足够长时间编程或只是使用计算机足够长时间的人都有一个恐怖故事(或几个)关于数据卡在他们无法从中提取的文件格式的故事。始终更喜欢开放,记录完备的解决方案。它会让你的生活和其他人生活在一起。从长远来看,这更容易。

答案 1 :(得分:2)

您可以使用多种选项:

1)TIF - TIF是一种多图像格式。您可以在单个TIF文件中嵌入许多图像。您显然无法在TIF文件中嵌入另一个多图像文件。例如另一个TIF文件。您可以在此处找到有关TIF文件的更多信息(https://en.wikipedia.org/wiki/Tagged_Image_File_Format)。

2)压缩文件 - 7-zip / zip / etc - 有多个库(包括免费和开源)可以处理压缩文件,例如:https://code.google.com/p/d7zip/。您也可以使用Delphi附带的zlib库,但需要进行一些调整。

3)Solid File解决方案 - 我所知道的是Eldos,但我确信还有其他人(https://www.eldos.com/solfs/)。这是一个“欺骗”您的应用程序以使用单个文件的组件或库。该应用程序认为它正在使用普通的文件系统。

4)结构化存储 - 由J - http://msdn.microsoft.com/en-us/library/windows/desktop/aa380369%28v=vs.85%29.aspx

提供

5)您拥有自己的文件格式 - 设计自己的文件结构,为您提供所需的文件结构。这取决于是否在添加文件后更新文件。如果数据没有改变,那么简单的事情应该有效:

  • 文件名长度 - 2个字节
  • 文件名 - 由长度
  • 指定
  • 文件大小 - 4个字节
  • 下一个文件位置 - 4个字节(0表示按顺序排列的最后一个文件)
  • 文件数据 - 按长度
  • 指定

对于每个文件,此块只会重复,最后一个文件的下一个文件位置为0。

最后一个选项(没有加密)的某些代码如下所示:

procedure ReadCustomFile(const aPackageFile: string);
var
  filename: string;
  loadData: TFileStream;
  filenameLength: Word;
  imageDataLength: Integer;
  imageNext: Integer;
  I: Integer;
  imageStream: TMemoryStream;
begin
  loadData := TFileStream.Create(aPackageFile, fmOpenRead or fmShareDenyWrite);
  try
    repeat
      imageStream := TMemoryStream.Create;
      try
        loadData.Read(filenameLength, SizeOf(filenameLength));
        SetLength(filename, filenameLength);
        loadData.Read(filename[1], filenameLength);
        loadData.Read(imageDataLength, SizeOf(imageDataLength));
        loadData.Read(imageNext, SizeOf(imageNext));
        imageStream.CopyFrom(loadData, imageDataLength);
        imageStream.SaveToFile('a'+filename);
      finally
        imageStream.Free;
      end;
    until imageNext = 0;
  finally
    loadData.Free;
  end;
end;

procedure WriteCustomFile(const aPackageFile: string; const aImageFileList: array of string);
var
  filename: string;
  loadData: TFileStream;
  filenameLength: Word;
  imageDataLength: Integer;
  imageNext: Integer;
  I: Integer;
  imageStream: TMemoryStream;
begin
  loadData := TFileStream.Create(aPackageFile, fmCreate or fmExclusive);
  try
    for I := Low(aImageFileList) to High(aImageFileList) do
    begin
      filename := aImageFileList[I];
      imageStream := TMemoryStream.Create;
      try
        imageStream.LoadFromFile(filename);
        filenameLength := Length(filename);
        loadData.Write(filenameLength, SizeOf(filenameLength));
        loadData.Write(filename[1], filenameLength);
        imageDataLength := imageStream.Size;
        loadData.Write(imageDataLength, SizeOf(imageDataLength));
        if I = High(aImageFileList) then
          imageNext := 0
        else
          imageNext := loadData.Position + imageStream.Size + SizeOf(imageNext);
        loadData.Write(imageNext, SizeOf(imageNext));
        loadData.CopyFrom(imageStream, imageStream.Size);
      finally
        imageStream.Free;
      end;
    end;
  finally
    loadData.Free;
  end;
end;

这段代码会像这样调用:

WriteCustomFile('ConsolidatedFile.pkg', ['Test1.bmp','Test2.bmp']);
ReadCustomFile('ConsolidatedFile.pkg');

这很粗糙,但应该让你知道该怎么做。添加删除会使事情变得复杂,因为您需要复制流并插入所需的块。添加较少,因为它只是一个需要更改的指针。根据此文件可能获得的大小,每次要更改它时,创建一个新文件可能会更容易。