Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 将tga文件转换为黑白文件时出现问题_C_Image_Converter_Tga - Fatal编程技术网

C 将tga文件转换为黑白文件时出现问题

C 将tga文件转换为黑白文件时出现问题,c,image,converter,tga,C,Image,Converter,Tga,我一直在努力使这个程序转换成黑色和白色的tga图像的颜色。但我不知道该怎么做。我对C非常陌生,还没有掌握ubuntu的语法,甚至还没有掌握ubuntu的正确用法 我想我的问题是tga文件头无法读取。因为我在tga文件上尝试这个程序时得到的结果是一张没有高度的不可修复的图片。“高度=0” 是否有一些好的链接供一个人在C上阅读 #include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include

我一直在努力使这个程序转换成黑色和白色的tga图像的颜色。但我不知道该怎么做。我对C非常陌生,还没有掌握ubuntu的语法,甚至还没有掌握ubuntu的正确用法

我想我的问题是tga文件头无法读取。因为我在tga文件上尝试这个程序时得到的结果是一张没有高度的不可修复的图片。“高度=0”

是否有一些好的链接供一个人在C上阅读

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct pixel {
    uint8_t r, g, b, a;
};

static uint8_t *load_image(char *filename, int *sizex, int *sizey)
{
    uint8_t *image;
    char buf[512];
    char *bufptr;
    int ret;

    FILE *fp = fopen(filename, "r");
    bufptr = fgets(buf, 512, fp);
    ret = fscanf(fp, "%d %d\n", sizex, sizey);
    bufptr = fgets(buf, 512, fp);

    image = malloc(*sizex * *sizey * 4);

    int i;
    uint8_t *ptr = image;
    for (i=0; i<*sizex * *sizey; ++i) {
        ret = fread(ptr, 1, 3, fp);
        ptr += 4;
    }

    fclose(fp);
    return image;
}

static int save_image(const char *filename, uint8_t *image, int sizex, int sizey)
{
    FILE *fp = fopen(filename, "w");
    fprintf(fp, "P6\n%d %d\n255\n", sizex, sizey);

    int i;
    uint8_t *ptr = image;
    for (i=0; i<sizex * sizey; ++i) {
        fwrite(ptr, 1, 3, fp);
        ptr += 4;
    }
    fclose(fp);

    return 1;
}

void convert_grayscale(uint8_t *input, uint8_t *output, int sizex, int sizey)
{
    // Y = 0.299 * R + 0.587 * G + 0.114 * B

    int i;

    for (i = 0; i < sizex * sizey; ++i)
        {
            struct pixel *pin = (struct pixel*) &input[i*4];
            struct pixel *pout = (struct pixel*) &output[i*4];

            float luma = 0.299 * pin->r + 0.587 * pin->g + 0.114 * pin->b;

            if (luma > 255)
                luma = 255;

            uint8_t intluma = (int) luma;

            pout->r = intluma;
            pout->g = intluma;
            pout->b = intluma;
            pout->a = 255;
        }

}

int main()
{
    uint8_t *inputimg, *outputimg;
    int sizex, sizey;

    inputimg = load_image("image.tga", &sizex, &sizey);

    outputimg = malloc(sizex * sizey * 4);

    convert_grayscale(inputimg, outputimg, sizex, sizey);

    save_image("output.tga", outputimg, sizex, sizey);
}
#包括
#包括
#包括
#包括
结构像素{
uint8_t r,g,b,a;
};
静态uint8_t*load_图像(char*filename,int*sizex,int*sizey)
{
uint8_t*图像;
char-buf[512];
char*bufptr;
int ret;
FILE*fp=fopen(文件名,“r”);
bufptr=fgets(buf,512,fp);
ret=fscanf(fp,“%d%d\n”,sizex,sizey);
bufptr=fgets(buf,512,fp);
image=malloc(*sizex**sizey*4);
int i;
uint8_t*ptr=图像;
对于(i=0;ig+0.114*引脚->b;
如果(luma>255)
luma=255;
uint8_t intluma=(int)luma;
pout->r=intluma;
pout->g=intluma;
撅嘴->b=内卢马;
撅嘴->a=255;
}
}
int main()
{
uint8_t*inputimg,*outputimg;
int-sizex,sizey;
inputimg=load_image(“image.tga”、&sizex、&sizey);
outputimg=malloc(sizex*sizey*4);
转换灰度(输入、输出、sizex、sizey);
保存图像(“output.tga”、outputimg、sizex、sizey);
}
(个人提示:阅读后回答较长。对于获得版主权限的所有人来说,这应该是必读的。)

问题在于您的
load_图像
代码似乎设计用于读取PPM(基于ASCII的)图像:

每个PPM图像包括以下内容: 1.用于标识文件类型的“幻数”。ppm图像的幻数是两个字符“P6”。 2.空白(空白、制表符、CRs、LFs)。 3.宽度,格式为十进制ASCII字符。 4.空白。 5.高度,同样以ASCII十进制表示。 6.空白。 7.最大颜色值(Maxval),同样以ASCII十进制表示。必须小于65536且大于零。 8.单个空白字符(通常是换行符)。 9.高度行的光栅[…]

--您的第一个
fgets
读取然后丢弃“幻数”行,然后读取宽度和高度,然后丢弃“maxval”行

它应该适用于PPM图像(您可以将此例程重命名为
load\u PPM\u image
),如果不是因为一个重要问题:在所有ASCII内容之后,您切换到
fread
,因此这里是警告#1

在打开文件之前,请确定是要专门读取ASCII文本,还是可能需要读取二进制数据。

问题是“文本模式”的“w”在读写时将某些字符转换为其他字符。这是所有常见C库中的内置行为;它试图修复上一代程序员留给我们的行尾字符混乱。现在,在文本模式下读取文本文件变得简单了一些,但读取二进制数据是不可能的。您不能确定是否获得了实际上是档案里的东西

让我们继续讨论警告#2:并非所有文件格式都相同。

上面的例行程序(大部分)适用于PPM图像,但它在TGA上会失败,因为它的标题组织方式不同。TGA标题描述得相当好(随机选取谷歌结果)

规范描述字节,因此首先要做的是将
fopen
行更改为

FILE *fp = fopen(filename, "rb");
顺便说一下,一个好的做法是测试它是否成功:

if (fp == NULL)
{
   printf ("Opening the file '%s' failed\n", filename);
   return NULL;
}
然后您可以使用
fgetc
fread
读取一个或多个字节。下面是警告#3:小心使用
fread

fread
按照存储到文件中的顺序读取多个字节,因此您可能认为它可以在一次“读取”操作中读取一个项目,例如
width
height
——每个项目都是一个2字节整数值。但是
fread
不知道系统中字节的顺序(也不知道文件本身中的顺序),所以它可能是读“lo-hi”,正如我所指的规范,而在您的计算机中,整数的字节顺序是“hi-lo”

80 00
然后你用
fread(&width,1,2,fp)
读取并存储这两个字节,这两个字节以相同的顺序存储到计算机内存中字节在末尾。但是如果您的计算机恰好是一个小的Endian顺序系统,您将不会得到值
0x0080=128
,而是
0x8000=32768

避免这种情况的方法是一次读取一个字节:

width = fgetc(fp) + (fgetc(fp)<<8);
..等等。当整个标题都被读取并且您没有遇到意外情况时,您就可以准备好设置来读取实际的图像数据了。不需要进行任何更改,您现有的代码应该可以正常工作


后期编辑:我知道我用了

int colorMapType = fgetc(fp);
其中“颜色映射类型”实际上是一个字节,而不是一个整数。这是为了允许皮带和吊带接近。如果在读取标题时遇到文件结尾,则
fgetc
返回的代码是
EOF
EOF
不能存储到
char
,因为它是一个整数值:
0xFF>FFFFFF
(更准确地说:
(int)-1
)。如果将其存储到
字符中,则无法将其与完全正常的值
0x000000FF
(值255)区分开来

皮带和吊杆方法是检查每个字节:

if (colorMapType == EOF)
{
   printf ("encountered unexpected end of file!\n");
   return NULL;
}
如果您使用的是已知文件,并且您知道该文件是有效的TGA(您可以使用位图编辑器查看和编辑该文件),但如果您计划使用的是不知道其是否有效的文件,则会造成过度杀伤力
if (colorMapType == EOF)
{
   printf ("encountered unexpected end of file!\n");
   return NULL;
}