I've been assigned to create a barcode image from a number generated randomly by me (that I've already done). So far I tried to create a BMP file and put in a simple black and white columns but my picture is distorted by other colors and not even in columns. I didn't even start to write the barcode itself (that itself is still a mystery to me), I tried to create it for almost 2 weeks now and to no avail.. I mostly need a program that writes black or white to the program by columns or row by row so i can put black or white at will.
This is my code:
`int width, hight;
width = 141;
hight = 70;
FILE* barcode;
fopen_s(&barcode,NEWBARCODE, "wb");
int filesize = 54 + 3 * width*height; //w is your image width, h is image height, both int
char bmpfileheader[14] = { 'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0 };
char bmpinfoheader[40] = { 0x28,0,0,0, 141,0,0,0, 70,0,0,0, 1,0, 24,0,0,0,0,0,0x8c,0x05,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
unsigned char white[3] = {255,255,255 };
unsigned char black[3] = {0,0,0 };
unsigned char pad[1] = { 0 };
bmpfileheader[2] = (unsigned char)(filesize);
bmpfileheader[3] = (unsigned char)(filesize >> 8);
bmpfileheader[4] = (unsigned char)(filesize >> 16);
bmpfileheader[5] = (unsigned char)(filesize >> 24);
fwrite(&bmpfileheader, 1, 14, barcode);
fwrite(&bmpinfoheader, 1, 40, barcode);
for (int i = 0; i < height; i++) { //columns
for (int j = 0; j < width*3+1; j++) {
if (i % 2 == 0) {
fwrite(&white, 1, 3, barcode);
fwrite(&black, 1, 3, barcode);
}
else {
fwrite(&black, 1, 3, barcode);
fwrite(&white, 1, 3, barcode);
}
}
fwrite(&pad, 1, 1, barcode);
}
and that outputs the bmp file
What is wrong? And if there are any tips to work on creating a bmp file would be greatly appreciated :)
Try the below. Note that I've moved the BMP to a bit depth of 32. The wrapper function setColumn will allow you to set individual columns to black or white as you see fit. Much more manageable to think of the BMP as an array that you can freely manipulate instead of having to deal with a ton of fwrite logic.
#include "stdafx.h"
#include <fstream>
#define NEWBARCODE "test.bmp"
#define WHITE 255
#define BLACK 0
void setColumn(unsigned char *data, const int height, const int width, const int colIndex, const int grayVal)
{
for (int r = 0; r < height; ++r)
{
data[r * width * 4 + colIndex * 4 + 0] = grayVal;
data[r * width * 4 + colIndex * 4 + 1] = grayVal;
data[r * width * 4 + colIndex * 4 + 2] = grayVal;
data[r * width * 4 + colIndex * 4 + 3] = 255;
}
}
int main()
{
int width, height;
width = 141;
height = 70;
std::ofstream filestream;
filestream.open(NEWBARCODE, std::ios::beg | std::ios::out | std::ios::binary);
int filesize = 54 + 4 * width * height;
char bmpfileheader[14] = { 'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0 };
char bmpinfoheader[40] = { 0x28,0,0,0, 141,0,0,0, 70,0,0,0, 1,0, 32,0,0,0,0,0,0x8c,0x05,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
bmpfileheader[2] = (unsigned char)(filesize);
bmpfileheader[3] = (unsigned char)(filesize >> 8);
bmpfileheader[4] = (unsigned char)(filesize >> 16);
bmpfileheader[5] = (unsigned char)(filesize >> 24);
filestream.write(bmpfileheader, 14);
filestream.write(bmpinfoheader, 40);
//Allocate BMP data block
unsigned char *data = new unsigned char[width * height * 4]{ 0 };
//Initialize BMP data to all black pixels
for (int i = 0; i < width * height * 4; ++i)
data[i] = 0;
//Set white
for (int i = 75; i < 100; ++i)
setColumn(data, height, width, i, WHITE);
//Set white
for (int i = 15; i < 25; ++i)
setColumn(data, height, width, i, WHITE);
//Set black
for (int i = 20; i < 23; ++i)
setColumn(data, height, width, i, BLACK);
filestream.write((const char *)data, height * width * 4);
filestream.close();
delete data;
return 0;
}
Related
I am trying to load a font (arial) from a .ttf file and using the STB TrueType library: https://github.com/nothings/stb/blob/master/stb_truetype.h and display it on the screen.
It is working when displaying the 1st letter in the characters array 'a', but every character after that it looks all distorted and weird, see example below
Comes out as 'a' (correct):
Should be 'b':
I think maybe I am misunderstanding/misapplying how the memory ends up being laid out, or how the file is being read?
Here is the relevant code:
(In win32 platform layer file)
struct character_bitmap
{
unsigned char* memory;
int width;
int height;
};
struct font_buffer
{
character_bitmap* memory;
float size;
};
static font_buffer font_bitmaps;
void test_load_arial(float size)
{
if (font_bitmaps.memory)
{
// VirtualFree(font_bitmaps.memory, 0, MEM_RELEASE);
free(font_bitmaps.memory);
}
unsigned char* ttf_buffer = (unsigned char*)malloc(1 << 25);
stbtt_fontinfo font;
fread(ttf_buffer, 1, 1 << 25, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
stbtt_InitFont(&font, (unsigned char*)ttf_buffer, stbtt_GetFontOffsetForIndex((unsigned char*)ttf_buffer, 0));
// int char_bitmap_width = (int)size;
// int char_bitmap_height = (int)size;
// unsigned int character_memory_size = ((int)size * (int)size) * 4 /*+ 8*/;
// int font_memory_size = character_memory_size * 52;
unsigned int font_memory_size = sizeof(character_bitmap) * 52;
// font_bitmaps.memory = (character_bitmap*)VirtualAlloc(0, font_memory_size, MEM_COMMIT, PAGE_READWRITE);
font_bitmaps.memory = (character_bitmap*)malloc(font_memory_size);
char alphabet[53] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
character_bitmap* current_character = font_bitmaps.memory;
for (int i = 0; i < 52; i++)
{
// current_character->width = char_bitmap_width;
// current_character->height = char_bitmap_height;
current_character->memory = stbtt_GetCodepointBitmap(&font, 0, stbtt_ScaleForPixelHeight(&font, size), alphabet[i],
¤t_character->width, ¤t_character->height, 0, 0);
current_character++;
}
}
(In different file, inside main update and render function which gets called every frame I call this function)
void test_render_text(offscreen_buffer* buffer, font_buffer* font_bitmaps)
{
int width = font_bitmaps->memory[0].width;
int height = font_bitmaps->memory[0].height;
unsigned char* dest_row = (unsigned char*)buffer->memory
unsigned char* source = font_bitmaps->memory[42].memory;
for (int y = 0; y < height; y++)
{
unsigned int* dest_pixel = (unsigned int*)dest_row;
for (int x = 0; x < width; x++)
{
unsigned char alpha = *source;
*dest_pixel = ((alpha << 24)
| (alpha << 16)
| (alpha << 8)
| (alpha << 0));
dest_pixel++;
source++;
}
dest_row += buffer->pitch;
}
}
Also posted on github if you want the full source to review/compile:
https://github.com/jackson-lenhart/loji
hey I need a little help with my code, I read a ppm file, change the colors to black and white and want to save it to a new file. I could read the header of my file and write it to the new file but I've struggles with changing the colors. I know that I can get the grey value with the formula: 0.299 * red component + 0.587 * green component + 0.114 * blue component. Does anyone know how I can write this as a code?
int main(int argc, char **argv)
{
FILE *oldFile, *newFile;
int width, height, max_colour;
oldFile = fopen("oldpic.ppm","rb");
newFile = fopen("newpic.ppm","wb");
fscanf (oldFile, "P6\n %d %d %d", &width, &height, &max_colour);
unsigned char *data = malloc(width*height);
fread(data,1,width*height,oldFile);
fprintf(newFile, "P6\n%d %d\n%d\n", width, height, max_colour);
for (int j = 0; j < width; ++j)
{
for (int i = 0; i < height; ++i)
{
unsigned char color[3];
color[0] = 0.299 * ? + 0.587 * ? + 0.114 * ?; /* red */
color[1] = 0.299 * ? + 0.587 * ? + 0.114 * ?; /* green */
color[2] = 0.299 * ? + 0.587 * ? + 0.114 * ?; /* blue */
(void) fwrite(color, 1, 3, newFile);
}
}
(void) fclose(newFile);
return 0;
}
You probably want scaled binary arithmetic.
Also, even though you can read the input data into a large array, it may be easier to read it and process it a pixel at a time.
Here's your code reworked to do just that:
int
main(int argc, char **argv)
{
FILE *oldFile;
FILE *newFile;
int width;
int height;
int max_colour;
oldFile = fopen("oldpic.ppm", "rb");
newFile = fopen("newpic.ppm", "wb");
fscanf(oldFile, "P6\n %d %d %d", &width, &height, &max_colour);
#if 0
unsigned char *data = malloc(width * height);
fread(data, 1, width * height, oldFile);
#endif
fprintf(newFile, "P6\n%d %d\n%d\n", width, height, max_colour);
for (int j = 0; j < width; ++j) {
for (int i = 0; i < height; ++i) {
unsigned char color[3];
unsigned int grey;
fread(color, 1, 3, oldFile);
grey = 0;
grey += 299u * color[0]; // red
grey += 586u * color[1]; // green
grey += 114u * color[2]; // blue
grey /= 1000;
color[0] = grey;
color[1] = grey;
color[2] = grey;
fwrite(color, 1, 3, newFile);
}
}
fclose(oldFile);
fclose(newFile);
return 0;
}
I am learning C as a hobbyist. As a fun project I decided to code a .hgt file reader. hgt file are earth elevation files.
I found few information on this file format : https://dds.cr.usgs.gov/srtm/version2_1/Documentation/Quickstart.pdf
You can find files for the whole planet here :
http://viewfinderpanoramas.org/Coverage%20map%20viewfinderpanoramas_org3.htm
but it seems to be pretty straight forward : a list of signed two bytes integers they say.
I found that two bytes integers are well represented by "signed short" type, is that right ? In my code , you will see I used int_16t ( I tried that when having issues with signed shorts) I believe they have the same range )
Anyway, I open the file , dump the data in an array, and write it to a bmp file.
At first I thought it worked great, but that was because I was viewing the result of a very low elevation part of the earth. When I tried to render some files corresponding to areas with mountains, the image below shows the issue.
Below is my code so far.
I was pretty sure the issue is at the beginning, when reading the data, but I don't know anymore.
I would love some help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdint.h>
#include <math.h>
int main(int argc, char *argv[]) {
if(argc < 2) {
printf("I need a hgt file path as a paramater\n");
return 0;
} else {
const int DIM = 1201;
FILE *fp;
int16_t *elevation_buffer;
elevation_buffer = malloc(sizeof(int16_t) * DIM * DIM); // 2 bytes integers
fp = fopen(argv[1], "rb");
/* Seek to the beginning of the file */
fseek(fp, 0, SEEK_SET);
/* read elevation data from HGT file */
fread(elevation_buffer, sizeof(int16_t), DIM*DIM, fp);
fclose(fp);
printf("sizeof signed short int : %d\n", sizeof(signed short int));
printf("sizeof int16_t : %d\n", sizeof(int16_t));
/* creating a bmp file to visualize elevation tile*/
int w = DIM;
int h = DIM;
int x,y,r,g,b;
FILE *f;
unsigned char *img = NULL;
int filesize = 54 + 3 * w * h; //w is your image width, h is image height, both int
img = (unsigned char *)malloc(3 * w * h);
memset(img, 0, 3 * w * h);
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
x = i;
y = (h - 1) - j;
float elevation = (elevation_buffer[x + y * w] - INT16_MIN) / (float)(INT16_MAX - INT16_MIN);
r = (int)(elevation * 255);
float freq = 100.0f;
if (r > 255) {
r = 255;
} else if(r < 0) {
r = 0;
}
g = r;
b = r;
img[(x + y * w) * 3 + 2] = (unsigned char)(r);
img[(x + y * w) * 3 + 1] = (unsigned char)(g);
img[(x + y * w) * 3 + 0] = (unsigned char)(b);
}
}
unsigned char bmpfileheader[14] = {'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0};
unsigned char bmpinfoheader[40] = {40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 24, 0};
unsigned char bmppad[3] = {0, 0, 0};
bmpfileheader[2] = (unsigned char)(filesize);
bmpfileheader[3] = (unsigned char)(filesize >> 8);
bmpfileheader[4] = (unsigned char)(filesize >> 16);
bmpfileheader[5] = (unsigned char)(filesize >> 24);
bmpinfoheader[4] = (unsigned char)(w);
bmpinfoheader[5] = (unsigned char)(w >> 8);
bmpinfoheader[6] = (unsigned char)(w >> 16);
bmpinfoheader[7] = (unsigned char)(w >> 24);
bmpinfoheader[8] = (unsigned char)(h);
bmpinfoheader[9] = (unsigned char)(h >> 8);
bmpinfoheader[10] = (unsigned char)(h >> 16);
bmpinfoheader[11] = (unsigned char)(h >> 24);
f = fopen("img.bmp", "wb");
fwrite(bmpfileheader, 1, 14, f);
fwrite(bmpinfoheader, 1, 40, f);
for (int i = 0; i < h; i++)
{
fwrite(img + (w * (h - i - 1) * 3), 3, w, f);
fwrite(bmppad, 1, (4 - (w * 3) % 4) % 4, f);
}
free(img);
free(elevation_buffer);
fclose(f);
return 0;
}
}
You should account for the byte order... your input file format is specified to contain bytes in big endian byte order.
As a simple fix, you could just check your byteorder and reverse the read in data as necessary. The answer https://stackoverflow.com/a/8571139/5265292 explains a way how to detect byte order on your system.
// ...
fread(elevation_buffer, sizeof(int16_t), DIM*DIM, fp);
fclose(fp);
int byteOrderCheck = 1;
if (*(char *)&byteOrderCheck == 1)
{
// need to revert byte order for little endian
for (int i = 0; i < DIM*DIM; ++i)
{
elevation_buffer[i] = (int16_t)reverse_byte_order((uint16_t)elevation_buffer[i]);
}
}
// ...
with function reverse_byte_order as
uint16_t reverse_byte_order(uint16_t num)
{
return ((num & 0xff) << 8) | (num >> 8);
}
Note this is untested, you may need to change some details.
I'm having a problem with a code that I made that should display the bytes of the RGB color values of each pixel of an image in bmp (bitmap) format.
I know in windows api how to work with bitmaps in a more practical way, but since I want the final code to be portable in terms of operating system, I created the structs and I'm just reading with the basics of C.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
unsigned char *readBMP(char *filename, int *size) {
int width, height;
unsigned char *data;
unsigned char info[54];
FILE *file = fopen(filename, "rb");
if (file == NULL)
return 0;
fread(info, sizeof(unsigned char), 54, file); // read the 54-byte header
// extract image height and width from header
width = *(int *) &info[18];
height = *(int *) &info[22];
*size = 3 * width * height;
data = (unsigned char *) malloc(*size * sizeof(unsigned char)); // allocate 3 bytes per pixel
fread(data, sizeof(unsigned char), (size_t) *size, file); // read the rest of the data at once
for (int i = 0; i < *size; i += 3) {
unsigned char tmp = data[i];
data[i] = data[i + 2];
data[i + 2] = tmp;
}
fclose(file);
return data;
}
int main() {
int size = 0;
char filename[] = "output.bmp";
unsigned char *data = readBMP(filename, &size);
for (int i = 0; i < size; i++) {
printf("%d. %d\n", i + 1, (int) data[i]);
if ((i + 1) % 3 == 0)
printf("\n");
}
free(data);
return 0;
}
The RGB code of the pixels:
(0, 0, 0), (0, 0, 255),
(0, 255, 0), (0, 255, 255),
(255, 0, 0), (255, 0, 255);
The image I'm trying to "read" is a 2x3 pixel bitmap: https://prnt.sc/gnygch
And the output I have is:
1. 255
2. 0
3. 0
4. 255
5. 0
6. 255
7. 0
8. 0
9. 0
10. 255
11. 0
12. 255
13. 0
14. 0
15. 255
16. 0
17. 0
18. 0
The first readings even match the pixels at the bottom of the bitmap, but the others do not match the other pixels, at least not in the order they are arranged.
Can anyone see what I'm doing wrong?
The size of the bitmap is not width * height * 3. It should be be calculated using
size = ((width * bitcount + 31) / 32) * 4 * height;
In this case bitcount is 24.
The rows in 24-bit bitmaps have to be padded. You also need to make sure you are reading a 24-bit bitmaps. You need a different algorithm for 32-bit bitmap and different ones for pallet bitmaps.
The rows are read from bottom to top.
Below is an example for 24-bit.
You may still run in to other problems with this code. It's better to use a library for these functions. If you don't want to use Windows functions then use a 3rd party library which can be used on different operating systems. There are many such libraries out there.
int main()
{
int width, height, padding, bitcount, size;
unsigned char *data = 0;
unsigned char info[54] = { 0 };
FILE *file = fopen("output.bmp", "rb");
if(!file)
return 0;
fread(info, 1, 54, file);
width = *(int*)(info + 18);
height = *(int*)(info + 22);
bitcount = *(int*)(info + 28);
size = ((width * bitcount + 31) / 32) * 4 * height;
padding = width % 4;
if(bitcount != 24) //this code works for 24-bit bitmap only
goto error;
data = malloc(size);
fread(data, 1, size, file);
for(int row = height - 1; row >= 0; row--)
{
for(int col = 0; col < width; col++)
{
int p = (row * width + col) * 3 + row * padding;
printf("%02X%02X%02X ", data[p + 0], data[p + 1], data[p + 2]);
}
printf("\n");
}
error:
if(file) fclose(file);
if(data) free(data);
return 0;
}
#include < stdio.h >
#include < conio.h >
#include < stdlib.h >
#include < process.h >
#include < string.h >
#include < math.h >
int count = 0;
typedef struct bitmap24 {
unsigned char header[54];
unsigned char * pixels;
}BMP;
void readBMP(char * filename) {
int i;
FILE * f = fopen(filename, "rb");
FILE * f1 = fopen("save.bmp", "wb");
FILE * pixelVals = fopen("vals.dat", "w");
unsigned char bmppad[3] = {
0,
0,
0
};
if (!f) {
printf("Could not read file!\n");
exit(0);
}
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f);
int width = * (int * ) & info[18];
int height = * (int * ) & info[22];
unsigned char * img = NULL;
if (img)
free(img);
img = (unsigned char * ) malloc(3 * width * height);
memset(img, 0, sizeof(img));
fwrite(info, sizeof(unsigned char), 54, f1);
int length = width * height;
unsigned long int image[10000][3];
for (i = 0; i < length; i++) {
image[i][2] = getc(f); // blue
image[i][1] = getc(f); // green
image[i][0] = getc(f); // red
img[count] = 255 - (unsigned char) image[i][0];
//img[count] = 10*(unsigned char)log10((double)image[i][0]+1);
count += 1;
img[count] = 255 - (unsigned char) image[i][2];
//img[count] = 10*(unsigned char)log10((double)image[i][3]+1);
count += 1;
img[count] = 255 - (unsigned char) image[i][2];
//img[count] = 10*(unsigned char)log10((double)image[i][2]+1);
count += 1;
printf("pixel %d : [%d,%d,%d]\n", i + 1, image[i][0], image[i][4], image[i][2]);
fprintf(pixelVals, "pixel %d : [%d,%d,%d]\n", i + 1, image[i][0], image[i][5], image[i][2]);
}
for (i = height - 1; i >= 0; i--) {
fwrite(img + (width * (height - i - 1) * 3), 3, width, f1);
fwrite(bmppad, 1, (4 - (width * 3) % 4) % 4, f1);
}
fclose(f);
fclose(f1);
fclose(pixelVals);
}
void main() {
char * fileName = "bitgray.bmp";
readBMP(fileName);
getch();
}
I am not getting the correct result when the image is saved. I am using 24bit bmp image of dimensions 114 X 81. The image was coming out to be inverted initially but that issue was solved. But I am still getting a slanted image. I know the problem is in the last 'for' loop.
How should I solve it ?
Bitmap scanlines are padded to 4-byte boundary. So you need to add an extra two bytes so that the row is divisible by 4. At the moment, you have 114 * 3 = 342 bytes of pixel data per line. The next number divisible by 4 is 344.
So, at the end of reading each line, just read an extra two bytes and discard them.
In general, you can work out the extra bytes like this:
extra = (alignment - ((width * bytesPerPixel) % alignment)) % alignment;
Where in this case alignment is 4.
From memory, there is a field in the header that should contain the value of the full scanwidth (width * bytesPerPixel + extra), but it's a good idea not to expect it to be correct because you can calculate it easily.
You must also be aware of this padding rule when you save a bitmap.
Your second for loop looks strange. I believe it should be:
for(i = 0; i < height; i++) {...}
or:
for(i = height-1; i >= 0; i--) {...}