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

bus*_*ard 4 c++ arrays png bitmap

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

从字节数组创建PNG

我有一个变量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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

到现在为止还挺好.因为我在图像之前有数组我创建了一个函数aufrunden来舍入到下一个int数,因为我想创建一个方形图像.

int aufrunden (double h)
{
int i =h;
if (h-i == 0)
  {
  return i;
  }
else
  {
  i = h+1;
  return i;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

double h;
h= sqrt(a/3.0);
int i = aufrunden(h);
FILE *imageFile;                           
int height=i,width=i;
Run Code Online (Sandbox Code Playgroud)

现在可能会发生,阵列很a=24长.aufrunden使图像3x3所以它有27个值...意味着它缺少1个像素的值.或者更糟糕的是它只是a=23很长.还创建了一个3x3图像.

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

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

Mar*_*ell 7

如果,看起来,你有 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"); 
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


Gle*_*son 6

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

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

这是一个简单的PPM图像:

P3 2 3 255
0 0 0       255 255 255
255 0 0     0 255 255
100 100 100 200 200 200
Run Code Online (Sandbox Code Playgroud)

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

如果您需要更大的强度范围(最大65535),请使用更大的数字以获得最大强度(例如1024).

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

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

在此输入图像描述

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

convert image.ppm -scale 400x result.png
Run Code Online (Sandbox Code Playgroud)

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

pnmtopng image.ppm > result.png
Run Code Online (Sandbox Code Playgroud)

  • @busssard如果您想查看一些实际代码来为您提供线索,您可以在此处查看我的答案并进行调整...http://stackoverflow.com/a/22580958/2836621 (2认同)

Mar*_*ell 5

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

  1. 如果用二进制编写,你就有P3了你真正需要的地方P6

  2. 您正在int为您的数据使用类型,而您需要unsigned char为 8 位数据使用。

  3. 你交换了宽度和高度。

  4. 您使用的PGM是用于便携式灰度地图的扩展程序,而您的数据是彩色的,因此您需要使用PPM用于便携式像素地图的扩展程序。

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

#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);
}
Run Code Online (Sandbox Code Playgroud)

如果你然后运行它,你可以将结果图像转换为一个漂亮的大 PNG

convert image.ppm -scale 400x result.png
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

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


Pro*_*ysX 5

下面的代码将采用像素颜色的整数数组作为输入并将其写入.bmp位图文件,或者相反,读取位.bmp图文件并将其图像内容存储为数组int。它只需要<fstream>图书馆。path例如,输入参数可以是C:/path/to/your/image.bmp和 ,data其格式为data[x+y*width]=(red<<16)|(green<<8)|blue;,其中redgreenblue是范围内的整数0-255,像素位置是(x,y)

#include <string>
#include <fstream>
using namespace std;
typedef unsigned int uint;
int* read_bmp(const string path, uint& width, uint& height) {
    ifstream file(path, ios::in|ios::binary);
    if(file.fail()) println("\rError: File \""+filename+"\" does not exist!");
    uint w=0, h=0;
    char header[54];
    file.read(header, 54);
    for(uint i=0; i<4; i++) {
        w |= (header[18+i]&255)<<(8*i);
        h |= (header[22+i]&255)<<(8*i);
    }
    const int pad=(4-(3*w)%4)%4, imgsize=(3*w+pad)*h;
    char* img = new char[imgsize];
    file.read(img, imgsize);
    file.close();
    int* data = new int[w*h];
    for(uint y=0; y<h; y++) {
        for(uint x=0; x<w; x++) {
            const int i = 3*x+y*(3*w+pad);
            data[x+(h-1-y)*w] = (img[i]&255)|(img[i+1]&255)<<8|(img[i+2]&255)<<16;
        }
    }
    delete[] img;
    width = w;
    height = h;
    return data;
}
void write_bmp(const string path, const uint width, const uint height, const int* const 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 };
    for(uint i=0; i<4; i++) {
        header[ 2+i] = (char)((filesize>>(8*i))&255);
        header[18+i] = (char)((width   >>(8*i))&255);
        header[22+i] = (char)((height  >>(8*i))&255);
    }
    char* img = new char[filesize];
    for(uint i=0; i<54; i++) img[i] = header[i];
    for(uint y=0; y<height; y++) {
        for(uint x=0; x<width; x++) {
            const int color = data[x+(height-1-y)*width];
            const int i = 54+3*x+y*(3*width+pad);
            img[i  ] = (char)( color     &255);
            img[i+1] = (char)((color>> 8)&255);
            img[i+2] = (char)((color>>16)&255);
        }
        for(uint p=0; p<pad; p++) img[54+(3*width+p)+y*(3*width+pad)] = 0;
    }
    ofstream file(path, ios::out|ios::binary);
    file.write(img, filesize);
    file.close();
    delete[] img;
}
Run Code Online (Sandbox Code Playgroud)

代码片段的灵感来自/sf/answers/3344994761/

对于.png图像,请使用lodepng.cpplodepng.h

#include <string>
#include <vector>
#include <fstream>
#include "lodepng.h"
using namespace std;
typedef unsigned int uint;
int* read_png(const string path, uint& width, uint& height) {
    vector<uchar> img;
    lodepng::decode(img, width, height, path, LCT_RGB);
    int* data = new int[width*height];
    for(uint i=0; i<width*height; i++) {
        data[i] = img[3*i]<<16|img[3*i+1]<<8|img[3*i+2];
    }
    return data;
}
void write_png(const string path, const uint width, const uint height, const int* const data) {
    uchar* img = new uchar[3*width*height];
    for(uint i=0; i<width*height; i++) {
        const int color = data[i];
        img[3*i  ] = (color>>16)&255;
        img[3*i+1] = (color>> 8)&255;
        img[3*i+2] =  color     &255;
    }
    lodepng::encode(path, img, width, height, LCT_RGB);
    delete[] img;
}
Run Code Online (Sandbox Code Playgroud)