fwrite with BMP file returning 0 and segmentation fault - fwrite

I'm trying to read a simple bmp file then invert the color then save it back to the file system using fread and fwrite binary mode.
So I did
BMP_Image * img;
BMP_Header * hdr;
fread(hdr,sizeof(BMP_Header),1, fptr);
img->width = hdr->width;
img->height = hdr->height;
img->bytes_per_pixel = hdr->bits*BIT_TO_BYTE;
img->header = *hdr;
img->data_size = hdr->size;
to get the header information where BMP_Header is a struct
Then read the image data and put into array
fread(data, sizeof(char), img->data_size - 54, fptr);
Then I subtract each element in my image data by 255
int i = 0;
for(i = 0;i<img->data_size;i++){
data[i] = 255 - data[i];
}
Now when I want to write the file back to the file system, I couldn't get it to work properly. I know you'd have to do fwrite 2 times. First writing the header, then writing the image data.
I have so far:
fwrite(header, 1 ,dataSize, fptr_out);
which gives me sgmentation fault and 0 byte bmp file.
Here are the typedefs of my BMP_Header and BMP_image struct
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef int int32_t;
typedef struct {
uint16_t type; // Magic identifier
uint32_t size; // File size in bytes
uint16_t reserved1; // Not used
uint16_t reserved2; // Not used
uint32_t offset; // Offset to image data in bytes
uint32_t header_size; // Header size in bytes
int32_t width; // Width of the image
int32_t height; // Height of image
uint16_t planes; // Number of color planes
uint16_t bits; // Bits per pixel
uint32_t compression; // Compression type
uint32_t imagesize; // Image size in bytes
int32_t xresolution; // Pixels per meter
int32_t yresolution; // Pixels per meter
uint32_t ncolours; // Number of colors
uint32_t importantcolours; // Important colors
} BMP_Header;
typedef struct {
BMP_Header header;
int data_size;
int width;
int height;
int bytes_per_pixel; // This amount should be equals to number of bits/8
char *data;
} BMP_Image;

Related

Using STM32 FMC HAL driver with parallel DAC

Im trying to generate sinusoidal signal with STM32f767 and DAC8412. DAC have 12 bit data bus and 2 bit address to select one of the four analog outputs. I've configuried FMC in CubeIDE for a SRAM memory with 16 bit data and 2 bit addres. I was able to create buffer with 4096 integer values of sin(). Then i've tried to write them to addres 0x60000000, but it only writes 4 values. After that, program goes to HardFault_Handler().
#define SRAM_BANK_ADDR ((uint32_t)0x60000000)
#define RESOLUTION_T ((uint32_t)0x1000)
#define RESOLUTION_Y ((uint32_t)0x1000)
uint32_t aTxBuffer[RESOLUTION_T];
uint32_t address = SRAM_BANK_ADDR;
Thats how i try to send data to DAC:
for (uint32_t i = 0; i<RESOLUTION_T; i++ )
{
*(__IO uint32_t*) address = aTxBuffer[i];
}
Thats how i fill buffer:
static void Fill_Buffer(uint32_t *pBuffer, uint32_t res_T, uint32_t res_Y)
{
uint32_t tmpIndex = 0;
double sinVal;
/* Put in global buffer different values */
for (tmpIndex = 0; tmpIndex < res_T; tmpIndex++ )
{
sinVal = round((sin(M_TWOPI*tmpIndex/res_T)+1)*res_Y/2);
pBuffer[tmpIndex] = sinVal;
}
}

Cairo: Draw an array of pixels

I'm just starting to explore Cairo, but right now I really want to use it for something very simple.
I have a very low-tech bitmap, i.e., a 3*X*Y array of numbers. I'd like to use Cairo to make this into a bitmap and write to a file. I'm looking through tutorials and I'm not seeing a way to use it for comparatively low-level functions like this.
I don't think I need guidance on how to use the tool once I know what the tool is.
I didn't actually test this, but the following should give you lots of useful hints:
#include <cairo.h>
#include <stdint.h>
#define WIDTH 42
#define HEIGHT 42
uint8_t data[WIDTH][HEIGHT][3];
cairo_surface_t* convert()
{
cairo_surface_t *result;
unsigned char *current_row;
int stride;
result = cairo_image_surface_create(CAIRO_FORMAT_RGB24, WIDTH, HEIGHT);
if (cairo_surface_status(result) != CAIRO_STATUS_SUCCESS)
return result;
cairo_surface_flush(result);
current_row = cairo_image_surface_get_data(result);
stride = cairo_image_surface_get_stride(result);
for (int y = 0; y < HEIGHT; y++) {
uint32_t *row = (void *) current_row;
for (int x = 0; x < WIDTH; x++) {
uint32_t r = data[x][y][0];
uint32_t g = data[x][y][1];
uint32_t b = data[x][y][2];
row[x] = (r << 16) | (g << 8) | b;
}
current_row += stride;
}
cairo_surface_mark_dirty(result);
return result;
}

Compress multipage tiff

For faster loading of images in MATLAB I am using multi-page TIFF files which for me work much faster than MATLAB's simple imread. But my problem is that the size of the TIFF file is way bigger than normal images ( like ten times more ) so I'm looking in compression options. I have tried some of those options ( with the code I attached below ) some of them don't work and produce empty files and the rest kill the speed.
Is there any way to have both size and speed?
Thank you
P.S: I put my codes here. If I'm doing sth wrong please tell me.
#include <stdio.h>
#include <time.h>
#include "tiffio.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace std;
#define XSIZE 1280
#define YSIZE 720
#define NPAGES 1000
#define CHANNEL 3
int main (int argc, char **argv)
{
uint32 image_width, image_height;
float xres, yres;
uint16 spp, bpp, photo, res_unit;
TIFF *out;
int i, j;
uint16 page;
Mat img;
int COMPRESSION_TAG = atoi(argv[1]);
unsigned char *array = new unsigned char [XSIZE * YSIZE*3];
char name[20];
out = TIFFOpen("myfile.tif", "w");
image_width = XSIZE;
image_height = YSIZE;
spp = CHANNEL; /* Samples per pixel */
bpp = 8; /* Bits per sample */
photo = PHOTOMETRIC_MINISBLACK;
for (page = 0; page < NPAGES; page++)
{
sprintf(name, "5_29%03d.jpg", page);
img = imread(name);
array = img.data;
TIFFSetField(out, TIFFTAG_IMAGEWIDTH, image_width );
TIFFSetField(out, TIFFTAG_IMAGELENGTH, image_height);
TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bpp);
TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, spp);
TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photo);
TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT);
TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_TAG);
/* It is good to set resolutions too (but it is not nesessary) */
xres = yres = 100;
res_unit = RESUNIT_INCH;
TIFFSetField(out, TIFFTAG_XRESOLUTION, xres);
TIFFSetField(out, TIFFTAG_YRESOLUTION, yres);
TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, res_unit);
/* We are writing single page of the multipage file */
TIFFSetField(out, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
/* Set the page number */
TIFFSetField(out, TIFFTAG_PAGENUMBER, page, NPAGES);
for (j = 0; j < image_height; j++)
TIFFWriteScanline(out, &array[3*j * image_width], j, 0);
TIFFWriteDirectory(out);
}
TIFFClose(out);
return 0;
}

Encoding images to video with ffmpeg

I am trying to encode series of images to one video file. I am using code from api-example.c, its works, but it gives me weird green colors in video. I know, I need to convert my RGB images to YUV, I found some solution, but its doesn't works, the colors is not green but very strange, so thats the code:
// Register all formats and codecs
av_register_all();
AVCodec *codec;
AVCodecContext *c= NULL;
int i, out_size, size, outbuf_size;
FILE *f;
AVFrame *picture;
uint8_t *outbuf;
printf("Video encoding\n");
/* find the mpeg video encoder */
codec = avcodec_find_encoder(CODEC_ID_MPEG2VIDEO);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
c= avcodec_alloc_context();
picture= avcodec_alloc_frame();
/* put sample parameters */
c->bit_rate = 400000;
/* resolution must be a multiple of two */
c->width = 352;
c->height = 288;
/* frames per second */
c->time_base= (AVRational){1,25};
c->gop_size = 10; /* emit one intra frame every ten frames */
c->max_b_frames=1;
c->pix_fmt = PIX_FMT_YUV420P;
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
f = fopen(filename, "wb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
/* alloc image and output buffer */
outbuf_size = 100000;
outbuf = malloc(outbuf_size);
size = c->width * c->height;
#pragma mark -
AVFrame* outpic = avcodec_alloc_frame();
int nbytes = avpicture_get_size(PIX_FMT_YUV420P, c->width, c->height);
//create buffer for the output image
uint8_t* outbuffer = (uint8_t*)av_malloc(nbytes);
#pragma mark -
for(i=1;i<77;i++) {
fflush(stdout);
int numBytes = avpicture_get_size(PIX_FMT_YUV420P, c->width, c->height);
uint8_t *buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:#"10%d", i]];
CGImageRef newCgImage = [image CGImage];
CGDataProviderRef dataProvider = CGImageGetDataProvider(newCgImage);
CFDataRef bitmapData = CGDataProviderCopyData(dataProvider);
buffer = (uint8_t *)CFDataGetBytePtr(bitmapData);
avpicture_fill((AVPicture*)picture, buffer, PIX_FMT_RGB8, c->width, c->height);
avpicture_fill((AVPicture*)outpic, outbuffer, PIX_FMT_YUV420P, c->width, c->height);
struct SwsContext* fooContext = sws_getContext(c->width, c->height,
PIX_FMT_RGB8,
c->width, c->height,
PIX_FMT_YUV420P,
SWS_FAST_BILINEAR, NULL, NULL, NULL);
//perform the conversion
sws_scale(fooContext, picture->data, picture->linesize, 0, c->height, outpic->data, outpic->linesize);
// Here is where I try to convert to YUV
/* encode the image */
out_size = avcodec_encode_video(c, outbuf, outbuf_size, outpic);
printf("encoding frame %3d (size=%5d)\n", i, out_size);
fwrite(outbuf, 1, out_size, f);
free(buffer);
buffer = NULL;
}
/* get the delayed frames */
for(; out_size; i++) {
fflush(stdout);
out_size = avcodec_encode_video(c, outbuf, outbuf_size, NULL);
printf("write frame %3d (size=%5d)\n", i, out_size);
fwrite(outbuf, 1, outbuf_size, f);
}
/* add sequence end code to have a real mpeg file */
outbuf[0] = 0x00;
outbuf[1] = 0x00;
outbuf[2] = 0x01;
outbuf[3] = 0xb7;
fwrite(outbuf, 1, 4, f);
fclose(f);
free(outbuf);
avcodec_close(c);
av_free(c);
av_free(picture);
printf("\n");
Please give me advice how to fix that problem.
You can see article http://unick-soft.ru/Articles.cgi?id=20. But it is article on Russian, but it includes code samples and VS Example.
Has anyone found a fix for this? I am seeing the green video problem on the decode side. That is, when I decode incoming PIX_FMT_YUV420 packets and then swsscale them to PIX_FMT_RGBA.
Thanks!
EDIT:
The green images are probably due to an arm optimization backfiring. I used this to fix the problem in my case:
http://ffmpeg-users.933282.n4.nabble.com/green-distorded-output-image-on-iPhone-td2231805.html
I guess the idea is to not specify any architecture (the config will you a warning about the architecture being unknown but you can continue to 'make' anyway). That way, the arm optimizations are not used. There maybe a slight performance hit (if any), but atleast it works! :)
I think the problem is most likely that you are using PIX_FMT_RGB8 as your input pixel format. This does not mean 8 bits per channel like the commonly used 24-bit RGB or 32-bit ARGB. It means 8 bits per pixel, meaning that all three color channels are housed in a single byte. I am guessing that this is not the format of your image since it is quite uncommon, so you need to use PIX_FMT_RGB24 or PIX_FMT_RGB32 depending on whether or not your input image has an alpha channel. See this documentation page for info on the pixel formats.

Writing BMP files (Platform Independent)

I have a structure such as
typedef struct FT_Bitmap_
{
int rows;
int width;
int pitch;
unsigned char* buffer;
short num_grays;
char pixel_mode;
char palette_mode;
void* palette;
} FT_Bitmap;
defining my bitmap data
I want to create a valid bmp file from this structure. How can I do that?
Take a look at:
http://en.wikipedia.org/wiki/BMP_file_format
Write out the header, the palette and the data.
Just take care when you write the bitmap data. It's "upside-down" - the first pixel in data is the left-bottom corner pixel.
First declare three types of initializers you will mostly use:
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
As for the structs, i suggest you using three, each for the element of the BMP:
typedef struct BITMAPINFOHEADER
{
dword bmp_size;
word bmp_app1;
word bmp_app2;
dword bmp_offset;
} BMP;
typedef struct DIB_HEADER
{
dword dib_size;
dword dib_w;
dword dib_h;
word dib_planes;
word dib_bits;
dword dib_compression;
dword dib_rawsize;
dword dib_xres;
dword dib_yres;
dword dib_palette;
dword dib_important;
} DIB;
typedef struct PIXEL_ARRAY
{
byte B;
byte G;
byte R;
} PIX;
Then you can manipulate the image in many ways. You can make an 1D/2D array to contain the data or just manipulate the bmp directly. The following code makes 500x460 colored blank bmp directly:
void new (char NAME[] , byte RED , byte GREEN , byte BLUE)
{
char build_name[256];
const char* id = "BM";
int i, j;
char debug[128];
FILE* fp;
dword rsize = (500 * sizeof(PIX) + 3) / 4 * 4;
dword pad = rsize - 500 * sizeof(PIX);
dword rawsize = rsize * 460 * sizeof(PIX);
byte zero[3] = {0};
dword size = (2) + sizeof(BMP) + sizeof(DIB) + sizeof(PIX);
BMP bmp[] = { 2+sizeof(BMP)+sizeof(DIB)+(sizeof(rawsize)/4), 0, 0, 2+sizeof(BMP)+sizeof(DIB) }; //2+ [!]
DIB dib[] = { sizeof(DIB), 500, 460, 1, 24, 0, (sizeof(rawsize)/4), 2835, 2835, 0, 0 };
PIX pix;
pix.R = RED;
pix.G = GREEN;
pix.B = BLUE;
sprintf(build_name, "%s.bmp", NAME);
fp = fopen(build_name, "wb");
if(!fp) strcpy(debug, "Access Denied.");
else strcpy(debug, "Saved.");
fwrite(id, 1, 2, fp);
fwrite(&bmp, 1, sizeof(bmp), fp);
fwrite(&dib, 1, sizeof(dib), fp);
for(i = 0; i < 460; i++)
{
for(j = 0; j < 500; j++)
{
fwrite(&pix, sizeof(pix), 1, fp);
}
if (pad) fwrite(zero, 1, pad, fp);
}
fclose(fp);
}
The point is using fseek() to locate the pixel and fwrite() to write pixels directly.