image scaling with C - c

I'm trying to read an image file and scale it by multiplying each byte by a scale its pixel levels by some absolute factor. I'm not sure I'm doing it right, though -
void scale_file(char *infile, char *outfile, float scale)
{
// open files for reading
FILE *infile_p = fopen(infile, 'r');
FILE *outfile_p = fopen(outfile, 'w');
// init data holders
char *data;
char *scaled_data;
// read each byte, scale and write back
while ( fread(&data, 1, 1, infile_p) != EOF )
{
*scaled_data = (*data) * scale;
fwrite(&scaled_data, 1, 1, outfile);
}
// close files
fclose(infile_p);
fclose(outfile_p);
}
What gets me is how to do each byte multiplication (scale is 0-1.0 float) - I'm pretty sure I'm either reading it wrong or missing something big. Also, data is assumed to be unsigned (0-255). Please don't judge my poor code :)
thanks

char *data;
char *scaled_data;
No memory was allocated for these pointers - why do you need them as pointers? unsigned char variables will be just fine (unsigned because it makes more sense for byte data).
Also, what happens when the scale shoots the value out of the 256-range? Do you want saturation, wrapping, or what?

change char *scaled_data; to char scaled_data;
change *scaled_data = (*data) * scale; to scaled_data = (*data) * scale;
That would get you code that would do what you are trying to do, but ....
This could only possibly work on an image file of your own custom format. There is no standard image format that just dumps pixels in bytes in a file in sequential order. Image files need to know more information, like
The height and width of the image
How pixels are represented (1 byte gray, 3 bytes color, etc)
If pixels are represented as an index into a palette, they have the palette
All kinds of other information (GPS coordinates, the software that created it, the date it was created, etc)
The method of compression used for the pixels
All of this is called Meta-data
In addition (as alluded to by #5), pixel data is usually compressed.

You're code is equivalent to saying "I want to scale down my image by dividing the bits in half"; it doesn't make any sense.
Images files are complex formats with headers and fields and all sorts of fun stuff that needs to be interpreted. Take nobugz's advice and check out ImageMagick. It's a library for doing exactly the kind of thing you want.

why you think you are wrong, i see nothing wrong in your algorithm except for not being efficient and char *data; and char *scaled_data; should be unsigned char data; and unsigned char scaled_data;

My understanding of a bitmap (just the raw data) is that each pixle is represented by three numbers one each for RGB; multiplying each by a number <=1 would just make the image darker. If you're trying to make the image wider, you could maby just output each pixle twice (to double the size), or just output every other pixel (to halve the size), but that depends on how its rasterized.

Related

C (OSDev) - How could I shift the contents of a 32-bit framebuffer upwards efficiently?

I'm working on writing a hobby operating system. Currently a large struggle that I'm having is attempting to scroll the framebuffer upwards.
It's simply a 32-bit linear framebuffer.
I have access to a few tools that could be helpful:
some of the mem* functions from libc: memset, memcpy, memmove, and memcmp
direct access to the framebuffer
the width, height, and size in bytes, of said framebuffer
a previous attempt that managed to scroll it up a few lines, albeit EXTREMELY slowly, it took roughly 25 seconds to scroll the framebuffer up by 5 pixels
speaking of which, my previous attempt:
for (uint64_t i = 0; i != atoi(numLines); i++) {
for (uint64_t j = 0; j != bootboot.fb_width; j++) {
for (uint64_t k = 1; k != bootboot.fb_size; k++) {
((uint32_t *)&fb)[k - 1] = ((uint32_t *)&fb)[k];
}
}
}
A few things to note about the above:
numLines is a variable passed into the function, it's a char * that contains the number of lines to scroll up by, in a string. I eventually want this to be the number of actual text lines to scroll up by, but for now treating this as how many pixels to scroll up by is sufficient.
the bootboot struct is provided by the bootloader I use, it contains a few variables that could be of use: fb_width (the width of the framebuffer), fb_height (the height of the framebuffer), and fb_size (the size, in bytes, of the framebuffer)
the fb variable that I'm using the address of is also provided by the bootloader I use, it is a single byte that is placed at the first byte of the framebuffer, hence the need to cast it into a uint32_t * before using it.
Any and all help would be appreciated.
If I read the code correctly, what's happening with the triple nested loops is:
For every line to scroll,
For every pixel that the framebuffer is wide,
For every pixel in the entire framebuffer,
Move that pixel backwards by one.
Essentially you're moving each pixel one pixel distance at a time, so it's no wonder it takes so long to scroll the framebuffer. The total number of pixel moves is (numLines * fb_width * fb_size), so if your framebuffer is 1024x768, that's 5*1024*1024*768 moves, which is 4,026,531,840 moves. That's basically 5000 times the amount of work required.
Instead, you'll want to loop over the framebuffer only once, calculate that pixel's start and its end pointer, and only do the move once. Or you can calculate the source, destination, and size of the move once and then use memmove. Here's my attempt at this (with excessive comments):
// Convert string to integer
uint32_t numLinesInt = atoi(numLines);
// The destination of the move is just the top of the framebuffer
uint32_t* destination = (uint32_t*)&fb;
// Start the move from the top of the framebuffer plus however
// many lines we want to scroll.
uint32_t* source = (uint32_t*)&fb +
(numLinesInt * bootboot.fb_width);
// The total number of pixels to move is the size of the
// framebuffer minus the amount of lines we want to scroll.
uint32_t pixelSize = (bootboot.fb_height - numLinesInt)
* bootboot.fb_width;
// The total number of bytes is that times the size of one pixel.
uint32_t byteSize = pixelSize * sizeof(uint32_t);
// Do the move
memmove(destination, source, byteSize);
I haven't tested this, and I'm making a number of assumptions about how your framebuffer is laid out, so please make sure it works before using it. :)
(P.S. Also, if you put atoi(numLines) inside the end condition of the for loop, atoi will be called every time through the loop, instead of once at the beginning like you intended.)
Currently a large struggle that I'm having is attempting to scroll the framebuffer upwards.
The first problem is that the framebuffer is typically much slower to access than RAM (especially reads); so you want to do all the drawing in a buffer in RAM and then blit it efficiently (with a smaller number of much larger writes).
Once you have a buffer in RAM, you can make the buffer bigger than the screen. E.g. for a 1024 x 768 video mode you might have a 1024 x 1024 buffer. In that case small amounts of scrolling can often be done using the same "blit it efficiently" function; but sometimes you'll have to scroll the buffer in RAM.
To scroll the buffer in RAM you can cheat - treat it as a circular buffer and map a second copy into virtual memory immediately after the first. This allows you to (e.g.) copy 768 lines starting from the middle of the first copy without caring about hitting the end of the first buffer. The end result is that you can scroll the buffer in RAM without moving any data or changing the "blit it efficiently" function.
As a bonus, this also minimizing "tearing" artifacts. E.g. often you want to scroll the pixel data up and add more pixel data to the bottom, then blit it (without the user seeing an intermediate "half finished" frame).

Faster way to copy a region from a bitmap in C

I am using the following way to copy a region from a bitmap in rgb565 pixel format:
void bmpcpy(size_t left, size_t top, size_t right, size_t bottom) {
size_t index = 0;
do {
do {
bmpCopy[index] = bmpSrc[(top * BMP_WIDTH) + left];
index++;
} while (++left < right);
} while (++top < bottom);
}
Is there a faster way to do the copy?
There might be faster ways using memcpy or accelerated graphics APIs, but first notice that your code is flawed:
bmpCopy and bmpSrc are not defined, it is unlikely they should be global variables.
bmpCopy is assumed to have a straddle value of right - left, not necessarily correct because of alignment constraints.
left is not reset for each row.
the width and height of the region are assumed to be non zero.
Depending on the type of bmpSrc, the parity and amplitude of width and the alignment of the source and destination pointers, it might be more efficient to copy multiple pixels at a time using a larger type.

Not at all able to understand the concept of storing pixel data in an array

(Assignment that has already been submitted) What I turned in did not even compile. This is not for points, its purely for understanding (peek the due date) I was able to complete the rest of the assignment however since I couldnt figure out how to save pixel data relative to height/ width.Ive literally spent the last 5 hours trying to understand this but it just isnt clicking.
How would I save the individual pixel rgb values. When the image is being read in, how can I tell the program # height 1, width 1 , read that green = 200, blue = ..., red = ....? Also if anyone knows what maxVal is referring to that would be helpful
typdef struct
{
unsigned char green;
unsigned char blue;
unsigned char red;
}pixelD;
typedef struct
{
pixelD * pixel;
} Color;
imageData
Image * ReadImage(char *filename)
{
//* items were added by instructor. I dont see how the magicNum array
would be useful here
/* These lines are useful:
* char magicNum[128];
* int width, height, maxval;
int imgSize = (width * height * sizeof(pixel));
* fscanf(f_in, "%s\n%d %d\n%d\n", magicNum, &width, &height, &maxval);
pixel = malloc(imgSize);
fread()????? this is supposedly the key?
Assignment: You will begin manipulation of images
1) Write a struct to store an image.
== 2.1 Image struct ==
Your Image struct will need a width, a height, and a buffer to store image data. As
we discussed in class, image data is a 2D array of pixel data. A pixel contains 3 unsigned chars: one for red, one for green, and one for blue. There are multiple ways
to store this data, and they are all correct
The steps you need to perform are:
Read the height and Width
Calculate the size of the buffer in which to save the data
Allocate the space for the buffer
Read the data and put it in the buffer.
The comments in ReadImage get you most of the way to solving this. Just put them in order and define the variable names.

How to write a bitstream

I'm thinking about writing some data into a bit stream using C. There are two ways come in mind. One is to concatenate variable bit-length symbols into a contiguous bit sequence, but in this way my decoder will probably have a hard time separating those symbols from this continuous bit stream. Another way is to distribute same amount of bits for which symbol and in that way the decoder can easily recover the original data, but there may be a waste of bits since the symbols have different values which in turn cause many bits in the bit stream being zero(this waste bits I guess).
Any hint what I should do?
I'm new to programming. Any help will be appreciated.
Sounds like your trying to do something similiar to a Huffman compression scheme? I would just go byte-by-byte (char)and keep track of the offset within the byte where I read off the last symbol.
Assuming none of your symbols would be bigger than char. It would look something like this:
struct bitstream {
char *data;
int data_size; // size of 'data' array
int last_bit_offset; // last bit in the stream
int current_data_offset; // position in 'data', i.e. data[current_data_offset] is current reading/writing byte
int current_bit_offset; // which bit we are currently reading/writing
}
char decodeNextSymbol(bitstream *bs) {
}
int encodeNextSymbol(bitstream *bs, char symbol) {
}
The matching code for decodeNextSymbol and encodeNextSymbol would have to use the C bitwise operations ('&' (bitwise AND), and '|' (bitwise OR) for example. I would then come up with a list of all my symbols, starting with the shortest first, and do a while loop that matches the shortest symbol. For example, if one of your symbols is '101', then if the stream is '1011101', it would match the first '101' and would continue to match the rest of the stream '1101' You would also have to handle the case where your symbol values overflow from one byte to the next.

Bitmap point processing

would appreciate some brainstorming help for one of my assignments. I am to write a program that does basic point processing of a .bmp image. Program will open a .bmp file for reading and writing and will not change any part of the header, but the pixel values in the file according to command line arguments:
-fromrow x, where x specifies the bottommost row to process
-torowx, where x specifies the topmost row to process
-fromcol x, where x specifies the leftmost column to process
-tocol x, where x specifies the rightmost column to process
-op x, where x is one of the following:
- 1 = threshold the image (any pixel value in the specifies range over 127 is changed to 255, and pixel values 127 or less is changed to 0)
- 2 = negative (any pixel value p in the specified range is changed to 255-p)
To process image data, you will need to make use of the following:
- each pixel value is an unsigned char
- the number of rows in the image is stored as an int at position (byte address) 22 in the file
- the number of columns in the image is stored as an int at position (byte address) 18 in the file
- the position at which the pixel data starts is an int stored at position (byte address) 10 in the file
- pixel information is stored row by row, starting from the bottommost row in the image (row 0) and progressing upwards. within a row; pixel information is stored left to right. padding is added to the end of each row to make row length a multiple of 4 bytes (if the row has 479 columns, there is one extra padding at the end of the row before the next row starts)
I'm a bit lost as to how to begin, but I figure I should make a struct bitmap first like so?
struct bitmap {
unsigned int startrow;
unsigned int endrow;
unsigned int startcol;
unsigned int endcol;
}
Can anyone help walk me through what I would need to do for the byte addresses that the assignment references? Any other brainstorming advice would be greatly appreciated as well. Thanks!
You can read raw bytes by opening a file in binary mode:
FILE *fid = fopen("blah.bmp", "rb");
You can then read some amount of data thus:
int num_actually_read = fread(p, sizeof(*p), num_to_read, fid);
where p is a pointer to some buffer. In this case, you probably want p to be of type uint8_t *, because you're dealing with raw bytes mostly.
Alternatively, you can jump around in a file thus:
fseek(fid, pos, SEEK_SET);
I hope this is enough to get you going.
You will need a pointer to point to the byte addresses 22 and 18 of the file. Once you point to those addresses, you will need to dereference the pointer to get the row and column values. Then you have to point your pointer to address 10 and then traverse the pixels one by one.

Resources