在 c 中使用 libpng 编写正弦波
Writing sine wave using libpng in c
使用 libpng。我写了一段代码(大部分是从复制粘贴过来的)。我的尝试是写一个带有波形的 png,但是在我微不足道的正弦波中有些地方出了问题:
生成此 png 的代码:
#include <stdio.h>
#include <math.h>
#include <stddef.h>
#include "png.h"
#include <stdlib.h>
//#define _USING_MATH_DEFINES
#define ERROR 1
int width, height;
png_byte color_type;
png_byte bit_depth;
png_bytep *row_pointers;
void read_png_file(char *filename) {
FILE *fp = fopen(filename, "rb");
if(!fp) abort();
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png) abort();
png_infop info = png_create_info_struct(png);
if(!info) abort();
if(setjmp(png_jmpbuf(png))) abort();
png_init_io(png, fp);
png_read_info(png, info);
width = png_get_image_width(png, info);
height = png_get_image_height(png, info);
color_type = png_get_color_type(png, info);
bit_depth = png_get_bit_depth(png, info);
printf("width: %d height: %d\n", width, height);
if(bit_depth == 16)
png_set_strip_16(png);
if(color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png);
if(png_get_valid(png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png);
if(color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_PALETTE)
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
if(color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
png_read_update_info(png, info);
row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
for(int y = 0; y < height; y++) {
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info));
//printf("%d\n", row_pointers[y]);
}
png_read_image(png, row_pointers);
fclose(fp);
}
void write_png_file(char *filename) {
int y;
FILE *fp = fopen(filename, "wb");
if(!fp) abort();
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) abort();
png_infop info = png_create_info_struct(png);
if (!info) abort();
if (setjmp(png_jmpbuf(png))) abort();
png_init_io(png, fp);
png_set_IHDR(
png,
info,
width, height,
8,
PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT
);
png_set_expand(png);
png_write_info(png, info);
png_write_image(png, row_pointers);
png_write_end(png, NULL);
for(int y = 0; y < height; y++) {
free(row_pointers[y]);
}
free(row_pointers);
fclose(fp);
}
void process_png_file() {
const int midY = ceil(height/2);
printf("midY: %d\n", midY);
int countY = -midY+height;
printf("countY: %d\n", countY);
png_byte color[] = {255,255,255};
png_byte color_white[] = {0,0,0};
for(int y = 0; y < height; y++) {
png_bytep row = row_pointers[y];
//printf("debug proc\n");
for(int x = 0; x < width; x++) {
png_bytep px = &(row[x * 4]);
for(int i = 0; i < 3; ++i){
if (y == ceil((midY-sin(x*300)))){
//printf("y: %d ceil: %d\n",y, ceil(sin(x)));
px[i] = color[i];
}
else {
px[i] = color_white[i];
}
}
}
}
}
int main(int argc, char *argv[]) {
if(argc != 3) abort();
read_png_file(argv[1]);
process_png_file();
write_png_file(argv[2]);
return 0;
}
在函数处理中,这可能是问题开始的地方:
for(int x = 0; x < width; x++) {
png_bytep px = &(row[x * 4]);
for(int i = 0; i < 3; ++i){
if (y == ceil((midY-sin(x*300)))){ //this part
//printf("y: %d ceil: %d\n",y, ceil(sin(x)));
px[i] = color[i];
}
else {
px[i] = color_white[i];
}
}
}
我希望它的振幅更大。
虽然我希望代码更短,但它似乎需要像 https://github.com/mikolalysenko/lena/blob/master/lena.png 这样的虚拟 png,这就是 png 的大小看起来相同的原因。你可以删除 read_png_file() 因为我们只是在处理写作内容(我不知道该怎么做,所以它是复制意大利面)。
sin
函数接受一个以弧度为单位的参数。一个完整的波只有 6.28 弧度(pi 乘以 2)。由于 x
是从左边开始的像素数,每个像素跳过 300 弧度,这意味着每个像素实际上跳过 47.75 个完整的波,这看起来与每个像素向后 0.25 个波相同。因此图像中的波浪只有 4 像素宽(每个波浪)。
我建议尝试每像素 0.1 弧度左右。这将使波浪宽度约为 62.8 像素,因此它们实际上足够大,可以看到。将 sin(x*300)
更改为 sin(x*0.1)
。
正弦波中的 Y 值仅介于 -1 和 1 之间。由于您使用 Y 值确定要绘制的像素,因此波浪只有 2 个像素高。我建议您将其乘以 50 左右,使您的波浪高 100 像素,因此它们实际上足够大可以看到。将 sin(whatever)
更改为 sin(whatever)*50
.
使用 libpng。我写了一段代码(大部分是从
生成此 png 的代码:
#include <stdio.h>
#include <math.h>
#include <stddef.h>
#include "png.h"
#include <stdlib.h>
//#define _USING_MATH_DEFINES
#define ERROR 1
int width, height;
png_byte color_type;
png_byte bit_depth;
png_bytep *row_pointers;
void read_png_file(char *filename) {
FILE *fp = fopen(filename, "rb");
if(!fp) abort();
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png) abort();
png_infop info = png_create_info_struct(png);
if(!info) abort();
if(setjmp(png_jmpbuf(png))) abort();
png_init_io(png, fp);
png_read_info(png, info);
width = png_get_image_width(png, info);
height = png_get_image_height(png, info);
color_type = png_get_color_type(png, info);
bit_depth = png_get_bit_depth(png, info);
printf("width: %d height: %d\n", width, height);
if(bit_depth == 16)
png_set_strip_16(png);
if(color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png);
if(png_get_valid(png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png);
if(color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_PALETTE)
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
if(color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
png_read_update_info(png, info);
row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
for(int y = 0; y < height; y++) {
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info));
//printf("%d\n", row_pointers[y]);
}
png_read_image(png, row_pointers);
fclose(fp);
}
void write_png_file(char *filename) {
int y;
FILE *fp = fopen(filename, "wb");
if(!fp) abort();
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) abort();
png_infop info = png_create_info_struct(png);
if (!info) abort();
if (setjmp(png_jmpbuf(png))) abort();
png_init_io(png, fp);
png_set_IHDR(
png,
info,
width, height,
8,
PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT
);
png_set_expand(png);
png_write_info(png, info);
png_write_image(png, row_pointers);
png_write_end(png, NULL);
for(int y = 0; y < height; y++) {
free(row_pointers[y]);
}
free(row_pointers);
fclose(fp);
}
void process_png_file() {
const int midY = ceil(height/2);
printf("midY: %d\n", midY);
int countY = -midY+height;
printf("countY: %d\n", countY);
png_byte color[] = {255,255,255};
png_byte color_white[] = {0,0,0};
for(int y = 0; y < height; y++) {
png_bytep row = row_pointers[y];
//printf("debug proc\n");
for(int x = 0; x < width; x++) {
png_bytep px = &(row[x * 4]);
for(int i = 0; i < 3; ++i){
if (y == ceil((midY-sin(x*300)))){
//printf("y: %d ceil: %d\n",y, ceil(sin(x)));
px[i] = color[i];
}
else {
px[i] = color_white[i];
}
}
}
}
}
int main(int argc, char *argv[]) {
if(argc != 3) abort();
read_png_file(argv[1]);
process_png_file();
write_png_file(argv[2]);
return 0;
}
在函数处理中,这可能是问题开始的地方:
for(int x = 0; x < width; x++) {
png_bytep px = &(row[x * 4]);
for(int i = 0; i < 3; ++i){
if (y == ceil((midY-sin(x*300)))){ //this part
//printf("y: %d ceil: %d\n",y, ceil(sin(x)));
px[i] = color[i];
}
else {
px[i] = color_white[i];
}
}
}
我希望它的振幅更大。
虽然我希望代码更短,但它似乎需要像 https://github.com/mikolalysenko/lena/blob/master/lena.png 这样的虚拟 png,这就是 png 的大小看起来相同的原因。你可以删除 read_png_file() 因为我们只是在处理写作内容(我不知道该怎么做,所以它是复制意大利面)。
sin
函数接受一个以弧度为单位的参数。一个完整的波只有 6.28 弧度(pi 乘以 2)。由于 x
是从左边开始的像素数,每个像素跳过 300 弧度,这意味着每个像素实际上跳过 47.75 个完整的波,这看起来与每个像素向后 0.25 个波相同。因此图像中的波浪只有 4 像素宽(每个波浪)。
我建议尝试每像素 0.1 弧度左右。这将使波浪宽度约为 62.8 像素,因此它们实际上足够大,可以看到。将 sin(x*300)
更改为 sin(x*0.1)
。
正弦波中的 Y 值仅介于 -1 和 1 之间。由于您使用 Y 值确定要绘制的像素,因此波浪只有 2 个像素高。我建议您将其乘以 50 左右,使您的波浪高 100 像素,因此它们实际上足够大可以看到。将 sin(whatever)
更改为 sin(whatever)*50
.