C - เส้นตรง
วิธีการพื้นฐานใน C ที่ทำงานกับไฟล์ ppm อัลกอริทึมพยายามวางเส้นแนวตั้งด้วยความยาวบรรทัดที่เหมาะสมเพื่อเติมพิกเซลทั้งหมด สีพื้นหลังและสีของเส้นถูกคำนวณเป็นค่าเฉลี่ยของภาพต้นฉบับ (ค่ามัธยฐานของแต่ละช่องสี):
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define SIGN(x) ((x > 0) ? 1 : (x < 0) ? -1 : 0)
#define MIN(x, y) ((x > y) ? y : x)
#define MAX(x, y) ((x > y) ? x : y)
typedef struct {
size_t width;
size_t height;
unsigned char *r;
unsigned char *g;
unsigned char *b;
} image;
typedef struct {
unsigned char r;
unsigned char g;
unsigned char b;
} color;
void init_image(image *data, size_t width, size_t height) {
data->width = width;
data->height = height;
data->r = malloc(sizeof(data->r) * data->width * data->height);
data->g = malloc(sizeof(data->g) * data->width * data->height);
data->b = malloc(sizeof(data->b) * data->width * data->height);
}
#define BUFFER_LEN 1024
int load_image(const char *filename, image* data) {
FILE *f = fopen(filename, "r");
char buffer[BUFFER_LEN]; /* read buffer */
size_t max_value;
size_t i;
fgets(buffer, BUFFER_LEN, f);
if (strncmp(buffer, "P3", 2) != 0) {
printf("File begins with %s instead of P3\n", buffer);
return 0;
}
fscanf(f, "%u", &data->width);
fscanf(f, "%u", &data->height);
fscanf(f, "%u", &max_value);
assert(max_value==255);
init_image(data, data->width, data->height);
for (i = 0; i < data->width * data->height; i++) {
fscanf(f, "%hhu", &(data->r[i]));
fscanf(f, "%hhu", &(data->g[i]));
fscanf(f, "%hhu", &(data->b[i]));
}
fclose(f);
printf("Read %zux%zu pixels from %s.\n", data->width, data->height, filename);
}
int write_image(const char *filename, image *data) {
FILE *f = fopen(filename, "w");
size_t i;
fprintf(f, "P3\n%zu %zu\n255\n", data->width, data->height);
for (i = 0; i < data->width * data->height; i++) {
fprintf(f, "%hhu %hhu %hhu ", data->r[i], data->g[i], data->b[i]);
}
fclose(f);
}
unsigned char average(unsigned char *data, size_t data_len) {
size_t i;
size_t j;
size_t hist[256];
for (i = 0; i < 256; i++) hist[i] = 0;
for (i = 0; i < data_len; i++) hist[data[i]]++;
j = 0;
for (i = 0; i < 256; i++) {
j += hist[i];
if (j >= data_len / 2) return i;
}
return 255;
}
void set_pixel(image *data, size_t x, size_t y, unsigned char r, unsigned char g, unsigned char b) {
data->r[x + data->width * y] = r;
data->g[x + data->width * y] = g;
data->b[x + data->width * y] = b;
}
color get_pixel(image *data, size_t x, size_t y) {
color ret;
ret.r = data->r[x + data->width * y];
ret.g = data->g[x + data->width * y];
ret.b = data->b[x + data->width * y];
return ret;
}
void fill(image *data, unsigned char r, unsigned char g, unsigned char b) {
size_t i;
for (i = 0; i < data->width * data->height; i++) {
data->r[i] = r;
data->g[i] = g;
data->b[i] = b;
}
}
void line(image *data, size_t x1, size_t y1, size_t x2, size_t y2, unsigned char r, unsigned char g, unsigned char b) {
size_t x, y, t, pdx, pdy, ddx, ddy, es, el;
int dx, dy, incx, incy, err;
dx=x2-x1;
dy=y2-y1;
incx=SIGN(dx);
incy=SIGN(dy);
if(dx<0) dx=-dx;
if(dy<0) dy=-dy;
if (dx>dy) {
pdx=incx;
pdy=0;
ddx=incx;
ddy=incy;
es=dy;
el=dx;
} else {
pdx=0;
pdy=incy;
ddx=incx;
ddy=incy;
es=dx;
el=dy;
}
x=x1;
y=y1;
err=el/2;
set_pixel(data, x, y, r, g, b);
for(t=0; t<el; t++) {
err -= es;
if(err<0) {
err+=el;
x+=ddx;
y+=ddy;
} else {
x+=pdx;
y+=pdy;
}
set_pixel(data, x, y, r, g, b);
}
}
color average_line(image *data, size_t x1, size_t y1, size_t x2, size_t y2) {
size_t x, y, t, pdx, pdy, ddx, ddy, es, el;
int dx, dy, incx, incy, err;
color ret;
color px;
size_t i;
size_t j;
size_t hist_r[256];
size_t hist_g[256];
size_t hist_b[256];
size_t data_len = 0;
for (i = 0; i < 256; i++) {
hist_r[i] = 0;
hist_g[i] = 0;
hist_b[i] = 0;
}
dx=x2-x1;
dy=y2-y1;
incx=SIGN(dx);
incy=SIGN(dy);
if(dx<0) dx=-dx;
if(dy<0) dy=-dy;
if (dx>dy) {
pdx=incx;
pdy=0;
ddx=incx;
ddy=incy;
es=dy;
el=dx;
} else {
pdx=0;
pdy=incy;
ddx=incx;
ddy=incy;
es=dx;
el=dy;
}
x=x1;
y=y1;
err=el/2;
px = get_pixel(data, x, y);
hist_r[px.r]++;
hist_g[px.g]++;
hist_b[px.b]++;
data_len++;
for(t=0; t<el; t++) {
err -= es;
if(err<0) {
err+=el;
x+=ddx;
y+=ddy;
} else {
x+=pdx;
y+=pdy;
}
px = get_pixel(data, x, y);
hist_r[px.r]++;
hist_g[px.g]++;
hist_b[px.b]++;
data_len++;
}
j = 0;
for (i = 0; i < 256; i++) {
j += hist_r[i];
if (j >= data_len / 2) {
ret.r = i;
break;
}
}
j = 0;
for (i = 0; i < 256; i++) {
j += hist_g[i];
if (j >= data_len / 2) {
ret.g = i;
break;
}
}
j = 0;
for (i = 0; i < 256; i++) {
j += hist_b[i];
if (j >= data_len / 2) {
ret.b = i;
break;
}
}
return ret;
}
void lines(image *source, image *dest, size_t L, float m, float M) {
size_t i, j;
float dx;
float mx, my;
float mm = MAX(MIN(source->width * source->height / L, M), m);
unsigned char av_r = average(source->r, source->width * source->height);
unsigned char av_g = average(source->g, source->width * source->height);
unsigned char av_b = average(source->b, source->width * source->height);
fill(dest, av_r, av_g, av_b);
dx = (float)source->width / L;
mx = 0;
my = mm / 2;
for (i = 0; i < L; i++) {
color avg;
mx += dx;
my += (source->height - mm) / 8;
if (my + mm / 2 > source->height) {
my = mm / 2 + ((size_t)(my + mm / 2) % (size_t)(source->height - mm));
}
avg = average_line(source, mx, my - mm / 2, mx, my + mm / 2);
line(dest, mx, my - mm / 2, mx, my + mm / 2, avg.r, avg.g, avg.b);
}
}
int main(int argc, char *argv[]) {
image source;
image dest;
size_t L;
float m;
float M;
load_image(argv[1], &source);
L = atol(argv[2]);
m = atof(argv[3]);
M = atof(argv[4]);
init_image(&dest, source.width, source.height);
lines(&source, &dest, L, m, M);
write_image(argv[5], &dest);
}
L = 5,000, m = 10, M = 50
L = 5,000, m = 10, M = 50
L = 100000, m = 10, M = 50