C ++从数组中创建png /位图

时间:2016-03-29 15:18:52

标签: c++ arrays bitmap png

所以我找到了关于我的问题的这个链接,但它是针对c#

Create a PNG from an array of bytes

我有一个变量int数组。 我会称之为“pix []” 现在它可以是3到256之间的任何大小,之后可能更大。

我现在要做的是将其转换为像素图像。 我仍然是一个noobin c ++,请原谅我。 我试图下载一些使libpng更容易使用的库,但它们似乎不起作用(ubuntu,code :: blocks) 所以我有以下问题:

1)如何创建新的位图(哪个libaries,哪个命令)?

2)如何用“pix []”中的信息填充它?

3)我如何保存?

如果是问题的重新发布我也对链接​​感到高兴;)

这是我到目前为止所做的工作,感谢您的帮助。

int main(){
 FILE *imageFile;
 int x,y,pixel,height=2,width=3;

 imageFile=fopen("image.pgm","wb");
 if(imageFile==NULL){
  perror("ERROR: Cannot open output file");
  exit(EXIT_FAILURE);
 }

 fprintf(imageFile,"P3\n");           // P3 filetype
 fprintf(imageFile,"%d %d\n",width,height);   // dimensions
 fprintf(imageFile,"255\n");          // Max pixel
  int pix[100] {200,200,200, 100,100,100, 0,0,0, 255,0,0, 0,255,0, 0,0,255};


       fwrite(pix,1,18,imageFile);


fclose(imageFile);
}

我还没有完全明白它的作用。我可以打开输出图像,但它不是数组的正确表示。

如果我改变了一些东西,例如制作一个二维数组,那么图像查看器会告诉我“预期的整数”并且不会向我显示图像。

到目前为止一切顺利。 因为我在图像之前有数组我创建了一个函数aufrunden来舍入到下一个int数,因为我想创建一个方形图像。

int aufrunden (double h)
{
int i =h;
if (h-i == 0)
  {
  return i;
  }
else
  {
  i = h+1;
  return i;
  }
}

此功能用于创建图像。 如果图像大于数组提供的信息(a是数组的长度)

double h;
h= sqrt(a/3.0);
int i = aufrunden(h);
FILE *imageFile;                           
int height=i,width=i;

现在可能会发生,数组长a=24aufrunden使图像为3x3,因此它有27个值...意味着它缺少1个像素的值。 或者更糟糕的是它只有a=23长。还创建一个3x3图像。

fwrite(pix,1,18,imageFile);在这些像素中写什么信息?如果剩余值仅为0,那将是最好的。

*编辑没关系,我只会在数组末尾添加0,直到填满整个广场...抱歉

4 个答案:

答案 0 :(得分:6)

考虑使用Netpbm格式(pbm,pgm或ppm)。

这些图像是非常简单的文本文件,您可以在没有任何特殊库的情况下编写。然后使用某些第三方软件(如ImageMagick,GraphicsMagick或pnmtopng)将图像转换为PNG格式。这是一篇描述Netpbm format的维基文章。

这是一个简单的PPM图片:

P3 2 3 255
0 0 0       255 255 255
255 0 0     0 255 255
100 100 100 200 200 200

第一行包含" P3" ("幻数将其标识为文本-PPM),2(宽度),3(高度),255(最大强度)。 第二行包含顶行的两个RGB像素。 第三行和第四行各包含第2行和第3行的两个RGB像素。

如果您需要更大的强度范围(最多65535),请使用较大的数字表示最大强度(例如1024)。

Mark Setchell编辑超越这一点 - 所以我是一个有罪的派对!

图像看起来像这样(放大六个像素时):

enter image description here

要转换和放大的ImageMagick命令是这样的:

convert image.ppm -scale 400x result.png

如果ImageMagick有点重量级,或者难以安装,您可以更简单地使用NetPBM工具(来自here),这样(它是一个预编译的二进制文件)

pnmtopng image.ppm > result.png

答案 1 :(得分:4)

如果看起来像是Magick ++并且很乐意使用它,你可以用C / C ++编写代码:

////////////////////////////////////////////////////////////////////////////////
// sample.cpp
// Mark Setchell
//
// ImageMagick Magick++ sample code
//
// Compile with:
// g++ sample.cpp -o sample $(Magick++-config --cppflags --cxxflags --ldflags --libs)
////////////////////////////////////////////////////////////////////////////////
#include <Magick++.h> 
#include <iostream> 

using namespace std; 
using namespace Magick; 

int main(int argc,char **argv) 
{ 
   unsigned char pix[]={200,200,200, 100,100,100, 0,0,0, 255,0,0, 0,255,0, 0,0,255};

   // Initialise ImageMagick library
   InitializeMagick(*argv);

   // Create Image object and read in from pixel data above
   Image image; 
   image.read(2,3,"RGB",CharPixel,pix);

   // Write the image to a file - change extension if you want a GIF or JPEG
   image.write("result.png"); 
}

enter image description here

答案 2 :(得分:3)

你离我不远 - 尝试做得好!据我所知,你只有几个错误:

  1. 如果以二进制文字书写,您的P3实际上需要P6

  2. 您使用的是int类型的数据,而您需要将unsigned char用于8位数据。

  3. 你的宽度和高度互换了。

  4. 您使用的PGM扩展程序适用于便携式灰色地图,而您的数据是彩色的,因此您需要使用PPM扩展程序,即for Portable Pix Map。

  5. 因此,工作代码如下所示:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(){
       FILE *imageFile;
       int x,y,pixel,height=3,width=2;
    
       imageFile=fopen("image.ppm","wb");
       if(imageFile==NULL){
          perror("ERROR: Cannot open output file");
          exit(EXIT_FAILURE);
       }
    
       fprintf(imageFile,"P6\n");               // P6 filetype
       fprintf(imageFile,"%d %d\n",width,height);   // dimensions
       fprintf(imageFile,"255\n");              // Max pixel
    
       unsigned char pix[]={200,200,200, 100,100,100, 0,0,0, 255,0,0, 0,255,0, 0,0,255};
       fwrite(pix,1,18,imageFile);
       fclose(imageFile);
    }
    

    如果你再运行它,你可以将生成的图像转换为带有

    的漂亮的大PNG
    convert image.ppm -scale 400x result.png
    

    enter image description here

    如果您随后需要16位数据,则​​可以将255更改为65535,并存储在unsigned short数组而不是unsigned char中,当您来到fwrite(),你需要写两倍的字节数。

答案 3 :(得分:1)

下面的代码将采用像素颜色的整数数组作为输入,并将其写入.bmp位图文件。它仅需要<fstream>库。输入参数path可以是C:/path/to/your/image.bmp,而data的格式为data[x+y*width]=(red<<16)|(green<<8)|blue;,其中redgreenblue0-255范围内的整数,像素位置为(x,y)

#include <fstream>
void write_bitmap(const string path, const int width, const int height, const int* data) {
    const int pad=(4-(3*width)%4)%4, filesize=54+(3*width+pad)*height; // horizontal line must be a multiple of 4 bytes long, header is 54 bytes
    char header[54] = { 'B','M', 0,0,0,0, 0,0,0,0, 54,0,0,0, 40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0,24,0 };
    char padding[3] = { 0,0,0 };
    for(int i=0; i<4; i++) {
        header[ 2+i] = (unsigned char)((filesize>>(8*i))&255);
        header[18+i] = (unsigned char)((width   >>(8*i))&255);
        header[22+i] = (unsigned char)((height  >>(8*i))&255);
    }
    unsigned char* img = new unsigned char[3*width*height];
    for(int i=0; i<width*height; i++) {
        const int color = data[i];
        img[3*i  ] = (unsigned char)( color     &255);
        img[3*i+1] = (unsigned char)((color>> 8)&255);
        img[3*i+2] = (unsigned char)((color>>16)&255);
    }
    ofstream file(path, ios::out|ios::binary);
    file.write(header, 54);
    for(int i=height-1; i>=0; i--) {
        file.write((char*)(img+3*width*i), 3*width);
        file.write(padding, pad);
    }
    file.close();
    delete[] img;
}

该代码段的灵感来自Writing BMP image in pure c/c++ without other libraries