I use the complexplanet.cpp Example from libNoise to create a *.raw File containing the Heights of the Terrain. The Problem is that the Data is singed and bigendian.
I could solve the bigendian Problem but when i try to convert to unsiged 16Bit the Values are wrong.
I used G'mic commandline tool for converting
Before conversion:
and after:
Maybe i should change the way the raw File is generated?
Here the Code:
int x, y;
uint8* pLineBuffer = new uint8[GRID_WIDTH * 2];
std::ofstream os;
os.open("terrain.raw", std::ios::out | std::ios::binary);
for (y = 0; y < GRID_HEIGHT; y++) {
float* pSource = elevGrid.GetSlabPtr(y);
uint8* pDest = pLineBuffer;
for (x = 0; x < GRID_WIDTH; x++) {
int16 elev = (int16)(floor(*pSource));
*pDest++ = (uint8)(((uint16)elev & 0xff00) >> 8);
*pDest++ = (uint8)(((uint16)elev & 0x00ff));
++pSource;
}
os.write((char*)pLineBuffer, GRID_WIDTH * 2);
}
os.close();
delete[] pLineBuffer;
Maybe someone understand how this works. I got lost by the casting to uint16 than uint8 and than...
Related
This was solved by changing the buffer from int16_t to int8_t since I was trying to write 8bit audio.
I'm trying to fill a buffer for a mono wave file with two different frequencies but failing at it. I'm using CLion in Ubuntu 18.04.
I know, the buffer size is equal to duration*sample_rate so I'm creating a int16_t vector with that size. I tried filling it with one note first.
for(int i = 0; i < frame_total; i++)
audio[i] = static_cast<int16_t>(128 + 127 * sin(i));
which generated a nice long beeep. And then I changed it with:
for(int i = 0; i < frame_total; i++)
audio[i] = static_cast<int16_t>(128 + 127 * sin(i*2));
which generated a higher beeeep, but when trying to do the following:
for(int i = 0; i < frame_total/2; i++)
audio[i] = static_cast<int16_t>(128 + 127 * sin(i*2));
for(int i = frame_total/2; i < frame_total; i++)
audio[i] = static_cast<int16_t>(128 + 127 * sin(i));
I expect it to write the higher beep in the first half of the audio, and fill the another fall with the "normal" beep. The *.wav file just plays the first note the entire time.
#define FORMAT_AUDIO 1
#define FORMAT_SIZE 16
struct wave_header{
// Header
char riff[4];
int32_t file_size;
char wave[4];
// Format
char fmt[4];
int32_t format_size;
int16_t format_audio;
int16_t num_channels;
int32_t sample_rate;
int32_t byte_rate;
int16_t block_align;
int16_t bits_per_sample;
// Data
char data[4]
int32_t data_size;
};
void write_header(ofstream &music_file ,int16_t bits, int32_t samples, int32_t duration){
wave_header wav_header{};
int16_t channels_quantity = 1;
int32_t total_data = duration * samples * channels_quantity * bits/8;
int32_t file_data = 4 + 8 + FORMAT_SIZE + 8 + total_data;
wav_header.riff[0] = 'R';
wav_header.riff[1] = 'I';
wav_header.riff[2] = 'F';
wav_header.riff[3] = 'F';
wav_header.file_size = file_data;
wav_header.wave[0] = 'W';
wav_header.wave[1] = 'A';
wav_header.wave[2] = 'V';
wav_header.wave[3] = 'E';
wav_header.fmt[0] = 'f';
wav_header.fmt[1] = 'm';
wav_header.fmt[2] = 't';
wav_header.fmt[3] = ' ';
wav_header.format_size = FORMAT_SIZE;
wav_header.format_audio = FORMAT_AUDIO;
wav_header.num_channels = channels_quantity;
wav_header.sample_rate = samples;
wav_header.byte_rate = samples * channels_quantity * bits/8;
wav_header.block_align = static_cast<int16_t>(channels_quantity * bits / 8);
wav_header.bits_per_sample = bits;
wav_header.data[0] = 'd';
wav_header.data[1] = 'a';
wav_header.data[2] = 't';
wav_header.data[3] = 'a';
wav_header.data_size = total_data;
music_file.write((char*)&wav_header, sizeof(wave_header));
}
int main(int argc, char const *argv[]) {
int16_t bits = 8;
int32_t samples = 44100;
int32_t duration = 4;
ofstream music_file("music.wav", ios::out | ios::binary);
int32_t frame_total = samples * duration;
auto* audio = new int16_t[frame_total];
for(int i = 0; i < frame_total/2; i++)
audio[i] = static_cast<int16_t>(128 + 127 * sin(i*2));
for(int i = frame_total/2; i < frame_total; i++)
audio[i] = static_cast<int16_t>(128 + 127 * sin(i));
write_header(music_file, bits, samples, duration);
music_file.write(reinterpret_cast<char*>(audio),sizeof(int16_t)*frame_total);
return 0;
}
There are two major issues with your code.
The first one is that you may be writing an invalid header depending on your compiler settings and environment.
The reason is that the wave_header struct is not packed in memory, and may contain padding between members. Therefore, when you do:
music_file.write((char*)&wav_header, sizeof(wave_header));
It may write something that isn't a valid WAV header. Even if you are lucky enough to get exactly what you wanted, it is a good idea to fix it, because it may change at any moment and surely it isn't portable.
The second issue is that the call to write the actual wave:
music_file.write(reinterpret_cast<char*>(audio),sizeof(char)*frame_total);
Is writing exactly half the amount of data you are expecting. The actual size of the data pointed by audio is sizeof(int16_t) * frame_total.
This explains why you are only hearing the first part of the wave you wrote.
This was solved by changing the buffer (audio) from int16_t to int8_t since I was trying to write 8bit audio.
I have the most strange problem here... I'm using the same code(copy-paste) from Linux in Windows to READ and WRITE and BMP image. And from some reason in Linux every thing works perfectly fine, but when I'm coming to Windows 10 from some I can't open that images and I've receive an error message how said something like this:
"It looks like we don't support this file format."
Do you have any idea what should I do? I will put the code below.
EDIT:
I've solved the padding problem and now it's write the images but they are completely white, any idea why? I've update the code also.
struct BMP {
int width;
int height;
unsigned char header[54];
unsigned char *pixels;
int size;
int row_padded;
};
void writeBMP(string filename, BMP image) {
string fileName = "Output Files\\" + filename;
FILE *out = fopen(fileName.c_str(), "wb");
fwrite(image.header, sizeof(unsigned char), 54, out);
unsigned char tmp;
for (int i = 0; i < image.height; i++) {
for (int j = 0; j < image.width * 3; j += 3) {
// Convert (B, G, R) to (R, G, B)
tmp = image.pixels[j];
image.pixels[j] = image.pixels[j + 2];
image.pixels[j + 2] = tmp;
}
fwrite(image.pixels, sizeof(unsigned char), image.row_padded, out);
}
fclose(out);
}
BMP readBMP(string filename) {
BMP image;
string fileName = "Input Files\\" + filename;
FILE *f = fopen(fileName.c_str(), "rb");
if (f == NULL)
throw "Argument Exception";
fread(image.header, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width from header
image.width = *(int *) &image.header[18];
image.height = *(int *) &image.header[22];
image.row_padded = (image.width * 3 + 3) & (~3);
image.pixels = new unsigned char[image.row_padded];
unsigned char tmp;
for (int i = 0; i < image.height; i++) {
fread(image.pixels, sizeof(unsigned char), image.row_padded, f);
for (int j = 0; j < image.width * 3; j += 3) {
// Convert (B, G, R) to (R, G, B)
tmp = image.pixels[j];
image.pixels[j] = image.pixels[j + 2];
image.pixels[j + 2] = tmp;
}
}
fclose(f);
return image;
}
In my point of view this code should be cross-platform... But it's not... why?
Thanks for help
Check the header
The header must start with the following two signature bytes: 0x42 0x4D. If it's something different a third party application will think that this file doesn't contain a bmp picture despite the .bmp file extension.
The size and the way pixels are stored is also a little bit more complex than what you expect: you assume that the number of bits per pixels is 24 and no no compression is used. This is not guaranteed. If it's not the case, you might read more data than available, and corrupt the file when writing it back.
Furthermore, the size of the header depends also on the BMP version you are using, which you can detect using the 4 byte integer at offset 14.
Improve your code
When you load a file, check the signature, the bmp version, the number of bits per pixel and the compression. For debugging purpose, consider dumping the header to check it manually:
for (int i=0; i<54; i++)
cout << hex << image.header[i] << " ";`
cout <<endl;
Furthermore, when you fread() check that the number of bytes read correspond to the size you wanted to read, so to be sure that you're not working with uninitialized buffer data.
Edit:
Having checked the dump, it appears that the format is as expected. But verifying the padded size in the header with the padded size that you have calculated it appears that the error is here:
image.row_padded = (image.width * 3 + 3) & (~3); // ok size of a single row rounded up to multiple of 4
image.pixels = new unsigned char[image.row_padded]; // oops ! A little short ?
In fact you read row by row, but you only keep the last one in memory ! This is different of your first version, where you did read the full pixels of the picture.
Similarly, you write the last row repeated height time.
Reconsider your padding, working with the total padded size.
image.row_padded = (image.width * 3 + 3) & (~3); // ok size of a single row rounded up to multiple of 4
image.size_padded = image.row_padded * image.height; // padded full size
image.pixels = new unsigned char[image.size_padded]; // yeah !
if (fread(image.pixels, sizeof(unsigned char), image.size_padded, f) != image.size_padded) {
cout << "Error: all bytes couldn't be read"<<endl;
}
else {
... // process the pixels as expected
}
...
This is my first question at Stack overflow. I'm new to Image processing and to C++, I'm working with bitmap files now. While creating a Bitmap file using C++, the file can not be opened using any viewers. I used a hex editor to view the file and there were random data in Image size field in the info header. After editing it in the hex editor, the bitmap is view-able. I don't know what is wrong with the code.
The header (bitmap.h) I created is as follows
#include<iostream>
#include<fstream>
using namespace std;
struct BmpSignature
{
unsigned char data[2];
BmpSignature(){ data[0] = data[1] = 0; }
};
struct BmpHeader
{
unsigned int fileSize; // this field gives out the size of the full Image includong the headers. it is of 4 byte in width
unsigned short reserved1; // this field is reserved. it is 2 byte in width
unsigned short reserved2; //This field is also reserved. it is 2 byte in width
unsigned int dataOffset; // this gives the starting location of the starting of the image data array
};
struct BmpInfoHeader
{
unsigned int size; // this field gives the size of the Bitmap info Header. This is 4 byte in width
unsigned int width; // this gives the width of the image
unsigned int height; // this gives the height of the image
unsigned short planes; //this gives the number of planes in the image
unsigned short bitCount; // this gives the number of bits per pixels in the image. for ex. like 24 bits, 8 bits
unsigned short compression; // gives info whether the image is compressed or not
unsigned int ImageSize; // gives the actual size of the image
unsigned int XPixelsPerM; // give the number of pixels in the X direction. It is usually 2834
unsigned int YPixelsPerM;// give the number of pixels in the Y direction. It is usually 2834
unsigned int ColoursUsed; // this field gives the number of Colours used in the Image
unsigned int ColoursImp; // gives the number of Important colours in the image. if all colours are important it is usually 0
};
the cpp file I created is as follows (Create_Bitmap.cpp)
#include"bitmap.h"
#include<cmath>
#include<fstream>
using namespace std;
int main()
{
ofstream fout;
fout.open("D:/My Library/test1.bmp", ios::out |ios::binary);
BmpHeader header;
BmpInfoHeader infoheader;
BmpSignature sign;
infoheader.size = 40;
infoheader.height = 15;
infoheader.width = 15;
infoheader.planes = 1;
infoheader.bitCount = 8;
infoheader.compression = 0;
infoheader.ImageSize = 0;
infoheader.XPixelsPerM = 0;
infoheader.YPixelsPerM = 0;
infoheader.ColoursUsed = 0;
infoheader.ColoursImp = 0;
unsigned char* pixelData;
int pad=0;
for (int i = 0; i < infoheader.height * infoheader.width; i++)
{
if ((i) % 16 == 0) pad++;
}
int arrsz = infoheader.height * infoheader.width + pad;
pixelData = new unsigned char[arrsz];
unsigned char* offsetData;
offsetData = new unsigned char[4 * 256];
int xn = 0;
int yn = 4 * 256;
for (int i = 0; i < yn; i+=4)
{
offsetData[i] = xn;
offsetData[i+1] = xn;
offsetData[i+2] = xn;
offsetData[i+3] = 0;
xn++;
}
int num = 0;
for (int i = 0; i < arrsz; i++)
{
pixelData[i] = i;
}
sign.data[0] = 'B'; sign.data[1] = 'M';
header.fileSize = 0;
header.reserved1 = header.reserved2 = 0;
header.dataOffset = 0;
fout.seekp(0, ios::beg);
fout.write((char*)&sign, sizeof(sign));
fout.seekp(2, ios::beg);
fout.write((char*)&header, sizeof(header));
fout.seekp(14, ios::beg);
fout.write((char*)&infoheader, sizeof(infoheader));
fout.seekp(54, ios::beg);
fout.write((char*)offsetData, yn);
fout.write((char*)pixelData, arrsz);
fout.close();
delete[] pixelData;
delete[] offsetData;
return 0;
}
I have attached the screenshot of the created bmp file in a hex editor with the image size field selected
Bitmap Image opened in Hex Editor
Upon replacing the contents in the field using hex editor the Bitmap file can be viewed with an Image Viewer. I don't know what is wrong in this code
So you want to write in BMP format? Remember that compiler may insert padding in C++ POD structs. You may need use some compiler pragma to pack the struct. Also make sure you use little-endian for all integers, but that should be OK since you are on Windows, assuming an x86.
So, as the title states, I'm having trouble exporting a .bmp (24-bit bmp) with C++. I am doing it as a school project type thing, and I need some help. To learn how .BMPs work I looked at the wikipedia page, and I got some help from here, but I still can't figure it out. Here is what I have:
//Export the map as a .bmp
void PixelMap::exportMap(const char* fileName)
{
//Size of the file in bytes
int fileSize = 54 + (3 * width * height);
//The sections of the file
unsigned char generalHeader[14] = {'B','M',0,0, 0,0,0,0, 0,0,54,0, 0,0};
unsigned char DIBHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0,24,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
unsigned char pixelArray[] = "";
//Set the binary portion of the generalHeader, mainly just file size
generalHeader[2] = (unsigned char)(fileSize);
generalHeader[3] = (unsigned char)(fileSize << 8);
generalHeader[4] = (unsigned char)(fileSize << 16);
generalHeader[5] = (unsigned char)(fileSize << 24);
//The binary variable portion of the DIB header
DIBHeader[4] = (unsigned char)(width);
DIBHeader[5] = (unsigned char)(width << 8);
DIBHeader[6] = (unsigned char)(width << 16);
DIBHeader[7] = (unsigned char)(width << 24);
DIBHeader[8] = (unsigned char)(height);
DIBHeader[9] = (unsigned char)(height << 8);
DIBHeader[10] = (unsigned char)(height << 16);
DIBHeader[11] = (unsigned char)(height << 24);
int picSize = 3 * width * height;
DIBHeader[20] = (unsigned char)(picSize);
DIBHeader[21] = (unsigned char)(picSize << 8);
DIBHeader[22] = (unsigned char)(picSize << 16);
DIBHeader[23] = (unsigned char)(picSize << 24);
//Loop through all width and height places to add all pixels
int counter = 0;
for(short j = height; j >= 0; j--)
{
for(short i = 0; i < width; i++)
{
//Add all 3 RGB values
pixelArray[counter] = pixelColour[i, j].red;
counter++;
pixelArray[counter] = pixelColour[i, j].green;
counter++;
pixelArray[counter] = pixelColour[i, j].blue;
counter++;
}
}
//Open it
ofstream fileWorking(fileName);
//Write the sections
fileWorking << generalHeader;
fileWorking << DIBHeader;
fileWorking << pixelArray;
//NO MEMORY LEAKS 4 ME
fileWorking.close();
}
This is part of a class called 'PixelMap,' basically a frame buffer or surface. The PixelMap has the variables 'width,' 'height,' and the struct array 'pixelColour.' (The struct containing 3 chars called 'red' 'green' and 'blue') If you would like to see the class, here it is. (It's just a skeleton, trying to get the .bmp down first)
//This is a pixel map, mainly for exporting BMPs
class PixelMap
{
public:
//The standard pixel variables
int width;
int height;
Colour pixelColour[];
//The constructor will set said variables
PixelMap(int Width, int Height);
//Manipulate pixels
void setPixel(int X, int Y, char r, char g, char b);
//Export the map
void exportMap(const char* fileName);
};
(Colour is the struct)
So my problem here is that when I try to run this, I get this:
So pixelArray, the array of colours to be exported gets corrupted. I assume this has to do with not being properly given a size, but I try to assign it's proper value (3 * width * height (3 being RGB)) but it says that it needs to be a constant value.
Any help with this issue is greatly appreciated!
Instead of
unsigned char pixelArray[] = "";
you could use:
std::vector<unsigned char> pixelArray(3*width*height,0);
This declares a vector with 3*width*height elements, initialized to 0. You can access the elements using the same syntax you've used for the array version (except, as pointed out in comments, you'll have to take care to write the binary values correctly to the output file).
I have to convert a 24bpp image to a 1bpp image or 8bpp image based on color table. The caller expects a unsigned char* in either case (which would be further processed or maybe for now debug output by sending the BITMAPINFOHEADER.biBitCount to its proper value, 8 or 1).
I have code to extract the color index into the palette (colorIndexArray is from color conversion or dithering algorithms)... I can get the info for an 8bpp bitmap...
But my problem is, I don't know how to put this info into a 1bpp bitmap
typedef struct {
unsigned int size;
unsigned char* pixels;
} ColorIndexArray;
unsigned char* convertImage(const ColorIndexArray& colorIndexArray, unsigned int paletteSize)
{
unsigned char* outputImage;
if (paleteSize > 2)
{
outputImage = (unsigned char*)LocalAlloc(LPTR, colorIndexArray.size);
for (int i=0; i<colorIndexArray.size; i++)
*(outputImage+i) = colorIndexArray.pixels[i];
// this works great
}
else // monochrome, caller has palette colors likely b/w (or purple/magenta or anything), must be 1bpp
{
outputImage = (unsigned char*)LocalAlloc(LPTR, colorIndexArray.size / 8);
// how can i place the unsigned char* info (which is already
// determined based on desired algorithm, representing index in
// color table) into the output image inside a single bit ?
// (obviously its value for a monochrome image would be 0 or 1 but
// it is saved as unsigned char* at the algorithm output)
// And how do I advance the pointer ?
// Will it be type safe ? Aligned to byte ? or do I have to fill
// with something at the end to make multiple of 8 bits ?
}
return outputImage;
}
Trying this after comment suggestion:
#include <GdiPlus.h>
....
else {
Gdiplus::Bitmap monoBitmap(w, h, PixelFormat1bppIndexed);
Gdiplus::BitmapData monoBitmapData;
Gdiplus::Rect rect(0, 0, w, h);
monoBitmap.LockBits(&rect, Gdiplus::ImageLockModeWrite, PixelFormat1bppIndexed, &monoBitmapData);
outputImage = (unsigned char*)monoBitmapData.Scan0;
for (unsigned int y = 0; y < h; y++)
{
for (unsigned int x = 0; x < w; x++)
{
if (colorIndexArray.pixels[x + y * w])
outputImage[y*monoBitmapData.Stride + x / 8] |= (unsigned char)(0x80 >> (x % 8));
}
}
monoBitmap.UnlockBits(&monoBitmapData);
}
return outputImage;
(Also need to allocate the memory for outputImage)
Based on the example suggested by Hans Passant (thank you also for pointing out how important the stride is), I wrote this little conversion
unsigned long stride = (((w + 31) & ~31) >> 3);
outputImage = (unsigned char*)LocalAlloc(LPTR, stride * h);
for (unsigned int y = 0; y < h; y++)
{
unsigned char* b = (unsigned char*)LocalAlloc(LPTR, stride);
for (unsigned int x = 0; x < w; x++)
if (colorIndexArray.pixels[x + y * w])
b[x / 8] |= (unsigned char)(0x80 >> (x % 8));
CopyMemory(outputImage + stride * y, b, stride);
}