Can't properly write a tiff file - c

I have a program which has the following function to write to a tiff file. However, the files produced are not recognized by any picture viewing software. What is wrong in this code, why is it not producing proper tiff files? Note that it uses the libtiff library.
long WriteGrayscaleTIFF(char *filename, long width,
long height, long scanbytes, unsigned char *data)
{
long y;
double factor;
long c;
unsigned long cmap[256]; /* output color map */
TIFF *outimage; /* TIFF image handle */
/* create a grayscale ramp for the output color map */
factor = (double)((1 << 16) - 1) / (double)((1 << 8) - 1);
for (c = 0; c < 256; c++)
cmap[c] = (long)(c * factor);
/* open and initialize output file */
if ((outimage = TIFFOpen(filename, "w")) == NULL)
return(0);
TIFFSetField(outimage, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(outimage, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(outimage, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(outimage, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(outimage, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(outimage, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
TIFFSetField(outimage, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT);
TIFFSetField(outimage, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
TIFFSetField(outimage, TIFFTAG_COLORMAP, cmap, cmap, cmap);
/* write the image data */
printf( "height = %d, width = %d!\n", height, width );
for (y = 0; y < height; y++) {
if (!TIFFWriteScanline(outimage, data, y, 0))
{
printf( "TIFFClose!\n" );
TIFFClose(outimage);
return(0);
}
data += scanbytes;
}
/* close the file */
TIFFClose(outimage);
return(1);
}

Related

RGB to YUV conversion with libav (ffmpeg) triplicates image

I'm building a small program to capture the screen (using X11 MIT-SHM extension) on video. It works well if I create individual PNG files of the captured frames, but now I'm trying to integrate libav (ffmpeg) to create the video and I'm getting... funny results.
The furthest I've been able to reach is this. The expected result (which is a PNG created directly from the RGB data of the XImage file) is this:
However, the result I'm getting is this:
As you can see the colors are funky and the image appears cropped three times. I have a loop where I capture the screen, and first I generate the individual PNG files (currently commented in the code below) and then I try to use libswscale to convert from RGB24 to YUV420:
while (gRunning) {
printf("Processing frame framecnt=%i \n", framecnt);
if (!XShmGetImage(display, RootWindow(display, DefaultScreen(display)), img, 0, 0, AllPlanes)) {
printf("\n Ooops.. Something is wrong.");
break;
}
// PNG generation
// snprintf(imageName, sizeof(imageName), "salida_%i.png", framecnt);
// writePngForImage(img, width, height, imageName);
unsigned long red_mask = img->red_mask;
unsigned long green_mask = img->green_mask;
unsigned long blue_mask = img->blue_mask;
// Write image data
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
unsigned long pixel = XGetPixel(img, x, y);
unsigned char blue = pixel & blue_mask;
unsigned char green = (pixel & green_mask) >> 8;
unsigned char red = (pixel & red_mask) >> 16;
pixel_rgb_data[y * width + x * 3] = red;
pixel_rgb_data[y * width + x * 3 + 1] = green;
pixel_rgb_data[y * width + x * 3 + 2] = blue;
}
}
uint8_t* inData[1] = { pixel_rgb_data };
int inLinesize[1] = { in_w };
printf("Scaling frame... \n");
int sliceHeight = sws_scale(sws_context, inData, inLinesize, 0, height, pFrame->data, pFrame->linesize);
printf("Obtained slice height: %i \n", sliceHeight);
pFrame->pts = framecnt * (pVideoStream->time_base.den) / ((pVideoStream->time_base.num) * 25);
printf("Frame pts: %li \n", pFrame->pts);
int got_picture = 0;
printf("Encoding frame... \n");
int ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture);
// int ret = avcodec_send_frame(pCodecCtx, pFrame);
if (ret != 0) {
printf("Failed to encode! Error: %i\n", ret);
return -1;
}
printf("Succeed to encode frame: %5d - size: %5d\n", framecnt, pkt.size);
framecnt++;
pkt.stream_index = pVideoStream->index;
ret = av_write_frame(pFormatCtx, &pkt);
if (ret != 0) {
printf("Error writing frame! Error: %framecnt \n", ret);
return -1;
}
av_packet_unref(&pkt);
}
I've placed the entire code at this gist. This question right here looks pretty similar to mine, but not quite, and the solution did not work for me, although I think this has something to do with the way the line stride is calculated.
Don't use av_image_alloc use av_frame_get_buffer.
(unrelated to your question, But using avcodec_encode_video2 is considered bad practice now and should be replaced with avcodec_send_frame and avcodec_receive_packet)
In the end, the error was not in the usage of libav but on the code that fills the pixel data from XImage to the rgb vector. Instead of using:
pixel_rgb_data[y * width + x * 3 ] = red;
pixel_rgb_data[y * width + x * 3 + 1] = green;
pixel_rgb_data[y * width + x * 3 + 2] = blue;
I should have used this:
pixel_rgb_data[3 * (y * width + x) ] = red;
pixel_rgb_data[3 * (y * width + x) + 1] = green;
pixel_rgb_data[3 * (y * width + x) + 2] = blue;
Somehow I was multiplying only the the horizontal displacement within the matrix, not the vertical displacement. The moment I changed it, it worked perfectly.

how to create bitmap in C and compile with gcc

i decided to learn C, and i try to follow this tutorial http://ricardolovelace.com/creating-bitmap-images-with-c-on-windows.html
but when i try to compile my code with gcc as this >gcc -Wall testc o app
he doesn't know type_rgb, can i define this type and how? and where in my code ?
#include <stdio.h>
struct rgb_data {
float r, g, b;
};
void save_bitmap( const char *file_name, int width, int height, int dpi, type_rgb *pixel_data);
/*
next steps of the tutorial
*/
rgb_data *pixels = new rgb_data[width * height];
for( int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
int a = y * width +x;
{
if ((x > 50 && x < 350) && (y > y && y < 350))
{
pixels[a].r = 255;
pixels[a].g = 255;
pixels[a].b = 0;
}else{
pixels[a].r = 55;
pixels[a].g = 55;
pixels[a].b = 55;
}
}
}
save_bitmap("black_border.bmp", width, height, dpi, pixels);
Bitmap file format is rather complicated. This is not the best way to learn C. It's better to start with something much simpler.
Having said that, the bitmap format starts with a bitmap header BITMAPFILEHEADER structure which is 14 bytes long, followed by BITMAPINFOHEADER structure 40 bytes long. These structures are defined in "Windows.h"
You have to write in various information in these structures and write them to file before writing the actual pixels.
You can have 1, 4, 8, 16, 24, and 32-bit bitmap. This is an example to read a 32-bit bitmap. This code assumes sizeof(short) is 2, sizeof(int) is 4.
int main()
{
int row, column;
int width = 100;
int height = 100;
int size = width * height * 4; //for 32-bit bitmap only
char header[54] = { 0 };
strcpy(header, "BM");
memset(&header[2], (int)(54 + size), 1);
memset(&header[10], (int)54, 1);//always 54
memset(&header[14], (int)40, 1);//always 40
memset(&header[18], (int)width, 1);
memset(&header[22], (int)height, 1);
memset(&header[26], (short)1, 1);
memset(&header[28], (short)32, 1);//32bit
memset(&header[34], (int)size, 1);//pixel size
unsigned char *pixels = malloc(size);
for(row = height - 1; row >= 0; row--) {
for(column = 0; column < width; column++) {
int p = (row * width + column) * 4;
pixels[p + 0] = 64; //blue
pixels[p + 1] = 128;//green
pixels[p + 2] = 192;//red
}
}
FILE *fout = fopen("32bit.bmp", "wb");
fwrite(header, 1, 54, fout);
fwrite(pixels, 1, size, fout);
free(pixels);
fclose(fout);
return 0;
}
Note the first pixel is blue, followed by green and read. The last pixel is not used in 32-bit bitmap. Also the height goes from bottom to top. This is another odd feature of bitmap. 24-bit bitmaps are more complicated because they need padding. 8-bit and lower will need an additional palette.
struct rgb_data {
float r, g, b;
};
float is not the right type for pixels. Each color goes from 0 to 255. This fits in unsigned char. You need instead
struct rgb_data {
unsigned r, g, b, alpha;
};
The alpha is the extra byte for 32-bit bitmap (which we won't use). Notice the size of this structure is 4. You can allocate this as
struct rgb_data *rgb = malloc(size);
Now you can access the pixels as follows:
int p = (row * width + column);
rgb[p].r = 255;
rgb[p].g = 0;
rgb[p].b = 0;
...
fwrite(rgb, 4, width * height, fout);

24bpp to 8bpp conversion C with raw image data

I am currently trying to convert raw binary image data (512 x 512 24bpp) to a 512 x 512 8bpp image by using 3bits for the R channel, 3 for the G channel, and 2 for the B channel. However when using my code my picture comes out grey scale? Can anyone tell me what I'm doing wrong?
/*24 bit per pixel - 8 bit per pixel transformation*/
unsigned char buf[512][512][3];
unsigned char in[512][512][3];
unsigned char out[512][512][3];
unsigned char pix[512][512];
int main(){
FILE *fp, *output;
int i, j;
/*open file*/
if((fp = fopen("LennaRGB512.data", "rb")) == NULL){
printf("error opening file\n");
}
/*read file into buffer*/
for (i = 0; i < 512; i++) {
for (j = 0; j < 512; j++) {
buf[i][j][0] = fgetc(fp); /*r*/
buf[i][j][1] = fgetc(fp); /*g*/
buf[i][j][2] = fgetc(fp); /*b*/
in[i][j][0] = buf[i][j][0];
in[i][j][1] = buf[i][j][1];
in[i][j][2] = buf[i][j][2];
}
}
fclose(fp);
output = fopen("lenna_8bpp.data", "wb");
for(i = 0; i < 512; i++){
char pix[512][512];
for(j = 0; j < 512; j++){
out[i][j][0] = (in[i][j][0] * 8) / 256;
out[i][j][1] = (in[i][j][1] * 8) / 256;
out[i][j][2] = (in[i][j][2] * 4) / 256;
pix[i][j] = (out[i][j][0] << 5) | (out[i][j][1] << 2) | out[i][j][2];
fputc(pix[i][j], output);
}
}
fclose(output);
return 0;
}
There are tons of questions on doing this with .bmp files and others but I can't find any help with manipulating the raw image data pixel by pixel.
I agree with the commenters. I think the grayscale is very likely an artifact of your viewer rather than your conversion. However, your conversion can also be improved. Try the following output loop:
unsigned char pix; /* don't need 512*512 of them. */
unsigned char r, g, b;
for(row = 0; row < 512; row++){
for(col = 0; col < 512; col++){
r = in[row][col][0] >> 5; /* keep 3 bits */
g = in[row][col][1] >> 5;
b = in[row][col][2] >> 6; /* keep 2 bits */
pix = (r << 5) | (g << 2) | b;
fputc(pix, output);
}
}
You are only processing one pixel at a time, so you only need one pix value.
For each of the r, g, and b, color components (remember to specify unsigned char throughout), use >> (right shift) to drop all the bits except the most significant. This is simpler and more clear than the *8/256 sequence. Also, I believe *8/256 only works because arithmetic is promoted to int — if it were done in chars, the *8 could cause overflow and lose data.
Edit The problem is indeed in the display. I have posted a palette and instructions on my blog since the full contents are too long for the space here. Yes, I know link-only answers are bad :( . I just saved it into the Archive in case of link rot.
You do need to open the image as Indexed, and then assign the colormap of the image.

Audio resampling bug

I'm trying to construct and use a basic audio resampler, taking WAVE file as input, resampling it to defined fs and returning resampled file. The code runs, but it generates inaudible output file that cannot be opened by Windows Media Player. I honestly don't know what causes this.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "wavfile.h"
#define FRAME_SIZE 256
void resample(float *in, float *out, int inputFrameSize, int outputFrameSize, float inputFs, float outputFs, float *index, float firstsampleofthenextframe)
{
float increment = inputFs/outputFs;
int i;
float frac;
int intp;
for (i=0;i<outputFrameSize;i++)
{
if ((*index) < inputFrameSize - 1) {
//linear interpolation
intp = (int)(*index);
frac = (*index) - (float)intp;
out[i] = frac * in[intp+1] + (1.0-frac) * in[intp];
} else { //index between inputFrameSize-2 and inputFrameSize-1
intp = (int)(*index);
frac = (*index) - (float)intp;
out[i] = frac * firstsampleofthenextframe + (1.0-frac) * in[intp];
}
//left_out[i] = 0.2*sin(0.001*3.141592635*(*index));
(*index) += increment;
}
}
int main()
{
struct wavfile_header readh;
struct wavfile_header writeh;
float left_in[FRAME_SIZE];
float right_in[FRAME_SIZE];
float left_out[FRAME_SIZE*2];
float right_out[FRAME_SIZE*2];
//float *left_out;
//float *right_out;
float indexL, indexR; //sample index used for interpolation
FILE * infile;
FILE * outfile;
fpos_t position;
int numBytes, numFrames;
int i;
int outFrameSize;
readh.num_channels = 2;
readh.sample_rate = 44100;
writeh.num_channels = 2;
writeh.sample_rate = 48000;
outFrameSize = (int)((float)FRAME_SIZE * (float)(writeh.sample_rate) / (float)(readh.sample_rate));
//left_out = (float*) malloc(sizeof(float)*outFrameSize);
//right_out = (float*) malloc(sizeof(float)*outFrameSize);
infile = wavfile_open_read("input.wav", &readh);
if(!infile) {
printf("read error");
return 1;
}
outfile = wavfile_open_write("output.wav", &writeh);
if(!outfile) {
printf("write error");
return 1;
}
//main processing loop
numBytes = readh.riff_length;
numFrames = numBytes / (2*FRAME_SIZE);
indexL = indexR = 0.f; //start from the 0th sample of the input signal
while(numFrames > 0)
{
float left_overlap, right_overlap;
short sl, sr;
for(i=0;i<FRAME_SIZE;i++) //read frame
{
short sleft, sright;
fread(&sleft ,sizeof(short),1, infile); //deinterleave samples
fread(&sright ,sizeof(short),1, infile);
fflush(infile);
left_in[i] = sleft * 0.0000305185f; // * (1/32767) - 16-bit input automatically normalized to (-1, 1)
right_in[i] = sright * 0.0000305185f; // * (1/32767) - 16-bit input automatically normalized to (-1, 1)
numBytes -= 4;
}
fgetpos (infile, &position);
//one sample ahead is needed to interpolate
fread(&sl ,sizeof(short),1, infile); //deinterleave samples [warning: bug if the input file length is an exact number of frames]
fread(&sr ,sizeof(short),1, infile);
left_overlap = sl * 0.0000305185f; // * (1/32767) - 16-bit input automatically normalized to (-1, 1)
right_overlap = sr * 0.0000305185f; // * (1/32767) - 16-bit input automatically normalized to (-1, 1)
fsetpos (infile, &position);
resample(left_in, left_out, FRAME_SIZE, outFrameSize, 44100, 48000, &indexL, left_overlap);
resample(right_in, right_out, FRAME_SIZE, outFrameSize, 44100, 48000, &indexR, right_overlap);
indexL -= (int)indexL;
indexR -= (int)indexR;
for(i=0;i<outFrameSize;i++) //read frame
{
short left, right;
//left_out[i] = 0.5;
//right_out[i] = 0.5;
left = (short)(left_out[i] * 32767.f);
right = (short)(right_out[i] * 32767.f);
fwrite(&left ,sizeof(short),1, outfile); //deinterleave samples
fwrite(&right ,sizeof(short),1, outfile);
numBytes -= 4;
}
fflush(outfile);
numFrames--;
}
/*
while(numBytes > 0)
{
//below: temp
short left, right;
//left_out[i] = 0.5;
//right_out[i] = 0.5;
left = left_out[i] * 32767;
right = right_out[i] * 32767;
fwrite(&left ,sizeof(short),1, outfile); //deinterleave samples
fwrite(&right ,sizeof(short),1, outfile);
numBytes--;
}
*/
fflush(outfile);
//free(left_out);
//free(right_out);
fclose(outfile);
fclose(infile);
return 0;
}

What is the simplest RGB image format?

I am working in C on a physics experiment, Young's interference experiment and I made a program who prints to file a huge bunch of pixels:
for (i=0; i < width*width; i++)
{
fwrite(hue(raster_matrix[i]), 1, 3, file);
}
Where hue, when given a value [0..255], gives back a char * with 3 bytes, R,G,B.
I would like to put a minimal header in my image file in order to make this raw file a valid image file.
More concise, switching from:
offset
0000 : height * width : data } my data, 24bit RGB pixels
to:
offset
0000 : dword : magic \
: /* ?? */ \
0012 : dword : height } Header <--> common image file
0016 : dword : width /
: /* ?? */ /
0040 : height * width : data } my data, 24bit RGB pixels
You probably want to use the PPM format which is what you're looking for: a minimal header followed by raw RGB.
TARGA (file name extension .tga) may be the simplest widely supported binary image file format if you don't use compression and don't use any of its extensions. It's even simpler than Windows .bmp files and is supported by ImageMagick and many paint programs. It has been my go-to format when I just need to output some pixels from a throwaway program.
Here's a minimal C program to generate an image to standard output:
#include <stdio.h>
#include <string.h>
enum { width = 550, height = 400 };
int main(void) {
static unsigned char pixels[width * height * 3];
static unsigned char tga[18];
unsigned char *p;
size_t x, y;
p = pixels;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
*p++ = 255 * ((float)y / height);
*p++ = 255 * ((float)x / width);
*p++ = 255 * ((float)y / height);
}
}
tga[2] = 2;
tga[12] = 255 & width;
tga[13] = 255 & (width >> 8);
tga[14] = 255 & height;
tga[15] = 255 & (height >> 8);
tga[16] = 24;
tga[17] = 32;
return !((1 == fwrite(tga, sizeof(tga), 1, stdout)) &&
(1 == fwrite(pixels, sizeof(pixels), 1, stdout)));
}
The recently created farbfeld format is quite minimal, though there is not much software supporting it (at least so far).
Bytes │ Description
8 │ "farbfeld" magic value
4 │ 32-Bit BE unsigned integer (width)
4 │ 32-Bit BE unsigned integer (height)
(2+2+2+2)*width*height │ 4*16-Bit BE unsigned integers [RGBA] / pixel, row-major
Here's a minimal example that writes your image file with a minimal PPM header. Happily, I was able to get it to work with the exact for loop you've provided:
#include <math.h> // compile with gcc young.c -lm
#include <stdio.h>
#include <stdlib.h>
#define width 256
int main(){
int x, y, i; unsigned char raster_matrix[width*width], h[256][3];
#define WAVE(x,y) sin(sqrt( (x)*(x)+(y)*(y) ) * 30.0 / width)
#define hue(i) h[i]
/* Setup nice hue palette */
for (i = 0; i <= 85; i++){
h[i][0] = h[i+85][1] = h[i+170][2] = (i <= 42)? 255: 40+(85-i)*5;
h[i][1] = h[i+85][2] = h[i+170][0] = (i <= 42)? 40+i*5: 255;
h[i][2] = h[i+85][0] = h[i+170][1] = 40;
}
/* Setup Young's Interference image */
for (i = y = 0; y < width; y++) for (x = 0; x < width; x++)
raster_matrix[i++] = 128 + 64*(WAVE(x,y) + WAVE(x,width-y));
/* Open PPM File */
FILE *file = fopen("young.ppm", "wb"); if (!file) return -1;
/* Write PPM Header */
fprintf(file, "P6 %d %d %d\n", width, width, 255); /* width, height, maxval */
/* Write Image Data */
for (i=0; i < width*width; i++)
fwrite(hue(raster_matrix[i]), 1, 3, file);
/* Close PPM File */
fclose(file);
/* All done */
return 0;
}
The header code is based on the specs at http://netpbm.sourceforge.net/doc/ppm.html. For this image, the header is just a string of fifteen bytes: "P6 256 256 255\n".

Resources