首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >24位TARGA的创建与像素处理

24位TARGA的创建与像素处理
EN

Code Review用户
提问于 2022-03-21 18:52:50
回答 2查看 97关注 0票数 5

我编写这段代码是为了熟悉C中的结构,它允许创建和导出24位TGA图像,并更改单个像素的颜色。

我关心的是setPixel函数,以及如何改进它的性能。

首先,从x,y到数组索引的转换,我如何最小化/消除这方面的需要?我想我可以用一个二维数组。

第二,像素的RGB值的设置。如何才能对其进行优化?一次为所有三个人分配一项任务会改善这一状况吗?我该怎么做?

最后,我想知道是否有办法减少makeImagesaveImage的冗长性。我没能找到更好的解决办法。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define HEADER_BYTES 18 // Ammount of bytes header should take up

typedef struct TGAImg_t{
    uint8_t idLength;           // Length of image ID field (0-255)
    uint8_t colorMapType;       // If a color map is present (1) or not (0)
    uint8_t imageType;          // Compression and color types (0-3 and 9-11)
    uint16_t colorMapOrigin;    // Index of first color map entry
    uint16_t colorMapLength;    // Count of color map entries
    uint8_t colorMapEntrySize;  // Number of bits in each color map entry. 16 for Targa 16, 24 for Targa 24...
    uint16_t xOrigin;           // X coord of the lower left corner of the image
    uint16_t yOrigin;           // Y coord of the lower left corner of the image
    uint16_t width;             // Width of the image in pixels
    uint16_t height;            // Height of the image in pixels
    uint8_t imagePixelSize;     // Number of bits in a stored pixel index
    uint8_t imageDescriptorByte;// Document says to just keep this byte as 0
    uint8_t imageDataField[0];  // Array of image pixels.
} TGAImg;

typedef struct RGB_t{
    uint8_t red;
    uint8_t green;
    uint8_t blue;
} RGB;

TGAImg* makeImage(uint8_t idLength, uint8_t colorMapType,
                        uint8_t imageType, uint16_t colorMapOrigin,
                        uint16_t colorMapLength, uint8_t colorMapEntrySize,
                        uint16_t xOrigin, uint16_t yOrigin,
                        uint16_t width, uint16_t height,
                        uint8_t imagePixelSize, uint8_t imageDescriptorByte){
    // Allocate memory for header + image pixels (using info from header params)
    uint32_t dataFieldBytes = width * height * (imagePixelSize / 8);
    TGAImg* img = calloc(HEADER_BYTES + dataFieldBytes, 1 );
    if (!img){
        printf("ERROR: calloc fail for img @ makeImg");
        exit(EXIT_FAILURE);
    }
    // Set header values
    img->idLength = idLength;
    img->colorMapType = colorMapType;
    img->imageType = imageType;
    img->colorMapOrigin = colorMapOrigin;
    img->colorMapLength = colorMapLength;
    img->colorMapEntrySize = colorMapEntrySize;
    img->xOrigin = xOrigin;
    img->yOrigin = yOrigin;
    img->width = width;
    img->height = height;
    img->imagePixelSize = imagePixelSize;
    img->imageDescriptorByte = imageDescriptorByte;
    return img;
}

// Writes contents of a TGAImg struct to a image of name imageName
void saveImage(char imageName[], TGAImg* img){
    FILE* imageFile = fopen(imageName, "wb");

    fwrite(&img->idLength, sizeof(img->idLength), 1, imageFile);
    fwrite(&img->colorMapType, sizeof(img->colorMapType), 1, imageFile);
    fwrite(&img->imageType, sizeof(img->imageType), 1, imageFile);
    fwrite(&img->colorMapOrigin, sizeof(img->colorMapOrigin), 1, imageFile);
    fwrite(&img->colorMapLength, sizeof(img->colorMapLength), 1, imageFile);
    fwrite(&img->colorMapEntrySize, sizeof(img->colorMapEntrySize), 1, imageFile);
    fwrite(&img->xOrigin, sizeof(img->xOrigin), 1, imageFile);
    fwrite(&img->yOrigin, sizeof(img->yOrigin), 1, imageFile);
    fwrite(&img->width, sizeof(img->width), 1, imageFile);
    fwrite(&img->height, sizeof(img->height), 1, imageFile);
    fwrite(&img->imagePixelSize, sizeof(img->imagePixelSize), 1, imageFile);
    fwrite(&img->imageDescriptorByte, sizeof(img->imageDescriptorByte), 1, imageFile);
    fwrite(&img->imageDataField, img->width * img->height * (img->imagePixelSize / 8), 1, imageFile);

    fclose(imageFile);
}

void setPixel(TGAImg* img, RGB color, int x, int y){
    uint32_t index = ((y * img->width) + x) * 3; // Convert x and y to index for array
    // Apply pixel change to all colors
    img->imageDataField[index] = color.blue;
    img->imageDataField[index+1] = color.green;
    img->imageDataField[index+2] = color.red;
}
EN

回答 2

Code Review用户

回答已采纳

发布于 2022-03-22 11:22:51

性能

Row诉Pixel

除了慢setPixel()之外,还提供了一个setLine(),在设置多个相同颜色的像素时提供了减少重复计算的功能。

块与像素

除了慢setPixel()之外,还提供了一个copyBlock(),在设置像素矩形时提供了减少重复计算的功能。在可能的情况下使用memcpy()

便携性

文件与代码结构

TGAImg是包含特定于实现的填充的应用程序,TARGA文件有一个固定的(可能没有填充)定义。

如果允许使用像packed这样的扩展语言限定符,这在C代码中很容易实现。

代码语言:javascript
复制
// typedef struct TGAImg_t{
typedef struct packed TGAImg_t{  // example

如果没有这样的语言扩展,那么编写可移植代码就是一项工作。在大多数情况下,代码需要以字节数组的形式读取文件头,然后一次形成一个TGAImg成员--就像OP编写saveImage()时所做的那样。

Endian

字节顺序可能与代码从文件格式不同。存在着各种endian函数。

代码语言:javascript
复制
// fwrite(&img->colorMapOrigin, sizeof(img->colorMapOrigin), 1, imageFile);
uint16_t u16 = endian_host_to_file16(img->colorMapOrigin);
fwrite(&u16, sizeof u16, 1, imageFile);

迂回症:int可能是16位。

各种代码都需要对此进行解释。

代码语言:javascript
复制
// void setPixel(TGAImg* img, RGB color, int x, int y){
void setPixel(TGAImg* img, RGB color, int_fast32_t, x, int_fast32_t y){

最后,我想知道是否有办法减少makeImage和saveImage的冗长性。我没能找到更好的解决办法。

不清楚为什么代码不简单使用,让调用者填写大多数成员。

代码语言:javascript
复制
TGAImg *makeImage(const TGAImg *init_values)

Bug?

imagePixelSize不是8.像素深度15 允许的的倍数时会有麻烦。

代码语言:javascript
复制
// uint32_t dataFieldBytes = width * height * (imagePixelSize / 8);
// Possible solution - needs review.
uint32_t dataFieldBytes = width * height * ((imagePixelSize + 7) / 8);
票数 3
EN

Code Review用户

发布于 2022-03-21 23:41:43

与其对结构的“头”应该占用的字节数进行硬编码,您只需使用sizeof()来获得它。当应用于结构时,sizeof()将返回其大小,就好像零长度数组不存在一样。

零长度数组是一个过时的GCC扩展。相反,您应该使用灵活的数组成员。您可以通过省略括号之间的零来实现这一点。

由于您typedef您的结构,您不需要给他们的名字。你可以把他们排除在外,像这样:

代码语言:javascript
复制
typedef struct {
    ...
} TGAImg;
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/275149

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档