Let's assume you use something like
Code:
typedef ... pixel_t;
typedef struct {
long width;
long height;
long xstep;
long ystep;
pixel_t *origin;
void *data;
} image_t;
#define PIXEL(image, x, y) ((image).pixel[(y) * (image).ystep + (x) * (image).xstep])
with data pointing to the start of the dynamically allocated pixel data buffer, usually the same as origin, and usually xstep = 1 and ystep = width .
To rotate such an image 90 degrees:
Code:
void image_rotate_clockwise(image_t *const image)
{
if (image) {
pixel_t *const origin = image->origin;
const long width = image->width;
const long height = image->height;
const long xstep = image->xstep;
const long ystep = image->ystep;
image->origin = origin + height * ystep;
image->width = height;
image->height = width;
image->xstep = -ystep;
image->ystep = xstep;
}
}
You can just as easily flip the image (mirroring x or y), as well as crop it and scale it down with any integer factor (i.e, 1:2, 1:3, 1:4, 1:5, and so on -- but using the poor "nearest neighbor" scaling algorithm, effectively).
If you are experimenting with image manipulation, I warmly recommend the above image structure. You'll avoid unnecessary data copying, and can easily add all sorts of rotation and/or cropping as input filters.
For filter effect experiments, I've used helper functions
Code:
static inline pixel_t getpixel(const image_t *const image, const long x, const long y, const pixel_t outside)
{
if (image && x >= 0L && y >= 0L && x < image->width && y < image->height)
return image->origin[x * image->xstep + y * image->ystep];
else
return outside;
}
static inline void setpixel(image_t *const image, const long x, const long y, const pixel_t pixel)
{
if (image && x >= 0L && y >= 0L && x < image->width && y < image->height)
image->origin[x * image->xstep + y * image->ystep] = pixel;
}
The getpixel() returns the specified outside value whenever the coordinates are outside image, and setpixel() only manipulates the image pixels.
I personally prefer uint32_t or uint64_t ARGB, with the most significant quarter of the bits specifying opacity. Using bit masks you can blend and mix color values much more efficiently than when color components are separate variables.
Looking at your code, it seems you are really trying to save P6 format data when given a linear array containing RGB triplets, i.e.
Code:
typedef struct {
unsigned char red;
unsigned char green;
unsigned char blue;
} pixel_t;
/* Order is the same as in a PPM image, i.e.
* index = x + y * width
* where
* 0 <= index < width * height
* 0 <= x < width
* 0 <= y < height
*/
A normal, non-rotated PPM (P6 format) save routine should probably be something like this:
Code:
void save_p6(const pixel_t *const image,
const int width,
const int height,
FILE *const out)
{
int x, y;
fprintf(out, "P6\n%d %d\n255\n", width, height);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
putc(image[x + y * width].red, out);
putc(image[x + y * width].green, out);
putc(image[x + y * width].blue, out);
}
}
}
Now, if you wanted to save the image rotated 90 degrees clockwise, all you modify is the PPM header (since width and height will be swapped), and the loop order and direction. The pixel component access within the loop does not change at all:
Code:
void save_p6_90(const pixel_t *const image,
const int width,
const int height,
FILE *const out)
{
int x, y;
fprintf(out, "P6\n%d %d\n255\n", height, width);
for (x = 0; x < width; x++) {
for (y = height - 1; y >= 0; y--) {
putc(image[x + y * width].red, out);
putc(image[x + y * width].green, out);
putc(image[x + y * width].blue, out);
}
}
}
Questions?