草庐IT

c++ - 将字节数组保存为 RAW 文件格式

coder 2024-02-20 原文

我有一个简单的程序,可以将数据从 PNG 文件读取到二维数组中。我想将该数据保存到 .RAW 文件中,以便 Raw StudioIrfanview可以查看我的程序输出到 my_out.raw 的原始图像。目前,如果我只是将原始二进制数据写入 my_out.raw 文件,则两个应用程序都无法真正读取该文件,即查看图像。我需要对下面的程序做什么才能看到图像?

读取PNG文件的代码是:

// MAIN.cpp
#include "pngfilereader.h"
#include <string>
#include <vector>

#include <fstream>

int main (int argc, char *argv[])
{
  PNGFileReader pngfr;
  if (!pngfr.decompress_png_to_raw(std::string("/home/matt6809/Downloads"
    "/City.png"))) {
    std::cout << "File decompression error: " << std::endl;
  } else {
    std::ofstream out;
    out.open("./my_out.raw", std::ios_base::out);
    std::vector<std::vector<unsigned char> > data;
    pngfr.get_image_data(data);
    typedef std::vector<std::vector<unsigned char> >::iterator row_it;
    typedef std::vector<unsigned char>::iterator col_it;

    for(row_it rit= data.begin(); rit != data.end(); ++rit) {
      for(col_it cit = rit->begin(); cit != rit->end(); ++cit) {
        out << (*cit);
      }   
    }   
    out << std::endl;
  }
  return 0;
}


#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <png.h>
#include <iostream>
#include <vector>
#include <string>

class PNGFileReader
{
  public:
    PNGFileReader();
    ~PNGFileReader();
    // Public exposed API:
    bool compress_raw_to_png(uint8_t data, int size);
    bool decompress_png_to_raw(const std::string &path);

    // Getters
    long unsigned int get_image_width();
    long unsigned int get_image_height();
    void get_image_data(std::vector<std::vector<unsigned char> > &data);

  private:
    // Helper functions:
    bool read_png(const std::string &path);
    bool create_png_structs(FILE *fp);
    bool free_data();
    bool alloc_data();

    // Member variables:
    png_structp m_pPNG;
    png_infop m_pPNGInfo;
    png_infop m_pPNGEndInfo;
    png_bytepp m_Data;
    long unsigned int m_ImageWidth;
    long unsigned int m_ImageHeight;

    // Enums
    enum PNGBOOL {NOT_PNG, PNG};
    enum PNGERRORS {ERROR, SUCCESS};
};


#include "pngfilereader.h"
#include <stdexcept>

PNGFileReader::PNGFileReader() :
  m_pPNG(NULL),
  m_pPNGInfo(NULL),
  m_pPNGEndInfo(NULL),
  m_Data(NULL),
  m_ImageWidth(0),
  m_ImageHeight(0)
{
}

PNGFileReader::~PNGFileReader()
{
  for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
    if (m_Data[i]) {
      delete m_Data[i];
      m_Data[i] = NULL;
    }   
  }
  if (m_Data) {
    delete m_Data;
    m_Data = NULL;
  }
}

// Public Exposed API
bool PNGFileReader::compress_raw_to_png(uint8_t m_Data, int size)
{
  return PNGFileReader::SUCCESS;
}

bool PNGFileReader::decompress_png_to_raw(const std::string &path)
{
  return read_png(path);
}

// Getters
long unsigned int PNGFileReader::get_image_width()
{
  return m_ImageWidth;
}

long unsigned int PNGFileReader::get_image_height()
{
  return m_ImageHeight;
}

void PNGFileReader::get_image_data(
  std::vector<std::vector<unsigned char> > &data)
{
  for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
    std::vector<unsigned char> v;
    data.push_back(v);
    for (unsigned long int j = 0; j < m_ImageWidth; ++j) {
      std::vector<unsigned char> *vp = &data[i];
      vp->push_back(m_Data[i][j]);
    } 
  }
}

// Private Methods
bool PNGFileReader::read_png(const std::string &path)
{
  /* 
   * Open up the file to read (path) in binary mode
   * first so that if anything goes wrong with libpng
   * we won't have much to undo
   */
  const char *c_path = path.c_str();
  FILE *fp = fopen(c_path, "rb");
  if (!fp)
    return PNGFileReader::ERROR;

  /*
   * Read the first BYTES_TO_READ bytes from file
   * then determine if it is a png file or 
   * not. If png_sig_cmp == 0 all is okay
   */
  enum {BYTES_TO_READ = 8};
  unsigned char sig[BYTES_TO_READ];
  if (!fread(sig, 1, BYTES_TO_READ, fp)) {
    fclose(fp);
    return PNGFileReader::ERROR;
  }

  bool is_png = !png_sig_cmp(sig, 0, BYTES_TO_READ);
  if (!is_png) {
    fclose(fp);
    return PNGFileReader::ERROR;   
  }

  if (!this->create_png_structs(fp)) {
    fclose(fp);
    return PNGFileReader::ERROR;
  }

  /*
   * For error handling purposes. Set a long pointer
   * back to this function to handle all error related
   * to file IO
   */
  if (setjmp(png_jmpbuf(m_pPNG)))
  {
    png_destroy_read_struct(&m_pPNG, &m_pPNGInfo, &m_pPNGEndInfo);
    fclose(fp);
    return PNGFileReader::ERROR;
  }

  /* 
   * Set up the input code for FILE openend in binary mode,
   * and tell libpng we have already read BYTES_TO_READ btyes from 
   * signature
   */
  png_init_io(m_pPNG, fp);
  png_set_sig_bytes(m_pPNG, BYTES_TO_READ);

  /*
   * Using the lowlevel interface to lib png ...
   */
  png_read_info(m_pPNG, m_pPNGInfo);
  m_ImageHeight = png_get_image_height(m_pPNG, m_pPNGInfo);
  m_ImageWidth = png_get_rowbytes(m_pPNG, m_pPNGInfo);
  this->alloc_data();
  png_read_image(m_pPNG, m_Data);

  png_read_end(m_pPNG, NULL);
  png_destroy_read_struct(&m_pPNG, &m_pPNGInfo, &m_pPNGEndInfo);
  fclose(fp);

  return PNGFileReader::SUCCESS;
}

bool PNGFileReader::create_png_structs(FILE *fp)
{
  /* 
   * Create the pointer to main libpng struct, as well as
   * two info structs to maintain information after, and
   * prior to all operations on png m_Data. Only necessary
   * to release resource after function succeeds.
   */
  m_pPNG = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
    NULL, NULL);
  if (!m_pPNG)
  {
    fclose(fp);
    return PNGFileReader::ERROR;
  }
  m_pPNGInfo = png_create_info_struct(m_pPNG);
  if (!m_pPNGInfo)
  {
    png_destroy_read_struct(&m_pPNG, (png_infopp)NULL,(png_infopp)NULL);
    fclose(fp);
    return PNGFileReader::ERROR;
  }
  m_pPNGEndInfo = png_create_info_struct(m_pPNG);
  if (!m_pPNGEndInfo)
  {
    png_destroy_read_struct(&m_pPNG, &m_pPNGInfo, (png_infopp)NULL);
    fclose(fp);
    return PNGFileReader::ERROR;
  }
  return PNGFileReader::SUCCESS;
}

bool PNGFileReader::free_data()
{
  if (m_ImageHeight == 0 || m_ImageWidth == 0)
    return PNGFileReader::ERROR;

  for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
    if (m_Data[i]) {
      delete m_Data[i];
      m_Data[i] = NULL;
    }
  }
  if (m_Data) {
    delete m_Data;
    m_Data = NULL;
  }
  return PNGFileReader::SUCCESS;
}

bool PNGFileReader::alloc_data()
{
  if (m_ImageHeight == 0 || m_ImageWidth == 0)
    return PNGFileReader::ERROR;

  if (m_Data != NULL)
    this->free_data();

  m_Data = new png_bytep[m_ImageHeight]();           
  for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
    m_Data[i] = NULL;
  }
  try {
    for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
      m_Data[i] = new png_byte[m_ImageWidth];
    }
  }
  catch (std::bad_alloc e) {
    for (unsigned long int i = 0; i < m_ImageHeight; ++i) {
      if (m_Data[i]) {
        delete m_Data[i];
        m_Data[i] = NULL;
      }
    }
    if (m_Data) {
      delete m_Data;
      m_Data = NULL;
    }
    throw e;
  }

  return PNGFileReader::SUCCESS;
}

最佳答案

旨在与 Raw Studio 和 Irfraview 等相机图像处理程序一起使用的“原始”文件不是没有标题的图像数据的原始二进制转储。相反,“原始”绰号指的是图像在相机内应用了最少量的图像处理。例如,图像数据可能仍然是来自相机的拜耳模式 CFA 的单 channel 单色图像,或者没有应用白平衡、颜色矩阵等,等等。无论哪种方式,图像数据都是仍然以标准二进制图像文件格式格式化,包括标题、数据打包方法等。示例包括 Adob​​e 的 DNG 文件格式(基于 TIFF)等格式,或相机制造商自己的专有格式,如佳能的 CR2,尼康NEF等

因此,如果您希望这些原始文件处理程序读取您的“原始”文件图像数据,您必须阅读二进制数据规范以及它们支持的原始文件格式,然后重新格式化原始 PNG 图像数据正确。

关于c++ - 将字节数组保存为 RAW 文件格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9936557/

有关c++ - 将字节数组保存为 RAW 文件格式的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  6. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  7. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  8. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  9. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  10. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

随机推荐