2012-03-30 82 views
3

我有一个简单的程序,可以将数据从PNG读取到二维数组中。我想将这些数据保存到.RAW文件中,以便Raw StudioIrfanview可以查看我的程序输出到my_out.raw的原始图像。目前,如果我只是将原始二进制数据写入my_out.raw文件,那么这两个应用程序都不能真正读取文件,即查看图像。我需要对下面的程序做些什么才能看到图像?将字节数组保存为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; 
} 
+0

你能改写你的文章,以便清楚你的问题是什么? – 2012-03-30 03:31:11

+0

@George Skoptsov编辑完成后请让我知道是否需要进一步澄清。 – 2012-03-30 03:36:33

回答

4

其旨在与像原始Studio和Irfraview有照相机的图像处理程序来使用的“原始”文件不是原始二进制转储没有标题的图像数据。相反,“原始”绰号是指图像在相机中应用了最少量的图像处理。例如,图像数据可能仍然是来自相机的拜耳模式CFA的单通道单色图像,或者未应用白平衡,色彩矩阵等。无论哪种方式,图像数据是仍然采用标准的二进制图像文件格式进行格式化,包括标题,数据打包方法等。例如格式包括Adobe的DNG文件格式(基于TIFF格式)或相机制造商自己的专有格式,例如Canon的CR2,尼康的NEF等

所以,如果你想要这些原始文件处理程序读取你的“原始”文件图像数据,你必须读取它们支持的原始文件格式的二进制数据规格,然后正确地重新格式化原始PNG图像数据。