You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TGA文件绿色通道修改异常求助(附C++实现代码)

TGA图像绿色通道调整异常问题

我尝试给加载的TGA文件绿色通道添加指定数值,但输出结果不符合预期——哪怕加0都会生成修改后的图像。

当前输出图像:
当前输出图像

预期输出图像:
预期输出图像

怀疑问题出在代码结构或逻辑上,以下是实现的C++代码:

#ifndef PROJECT2_TGA_READER_H
#define PROJECT2_TGA_READER_H

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;
struct TGA_HeaderData{
    char idLength;
    char colorMapType;
    char dataTypeCode;
    short colorMapOrigin;
    short colorMapLength;
    char colorMapDepth;
    short xOrigin;
    short yOrigin;
    short width;
    short height;
    char bitsPerPixel;
    char imageDescriptor;
};
struct Pixel_Data{
    char blue;
    char green;
    char red;
};


class TGA_Reader {
public:
    TGA_Reader(string file_name);

    TGA_HeaderData HeaderData{};

    vector<Pixel_Data> pixels;

    void DeclareFile(string file_name);

    void createFile(const char *name, const TGA_HeaderData &headerData, const vector<Pixel_Data> &pixels);

    TGA_Reader add_green_channel(int value);
};

#include "TGA_Reader.h"

TGA_Reader::TGA_Reader(string file_name) {
    DeclareFile(file_name);
}

void TGA_Reader::DeclareFile(string file_name) {
    ifstream file(file_name, ios::binary);
    if (!file){
        cout<<"not open"<<endl;
        return;
    }
    file.read((char*)&HeaderData.idLength, sizeof(HeaderData.idLength));
    file.read((char*)&HeaderData.colorMapType, sizeof(HeaderData.colorMapType));
    file.read((char*)&HeaderData.dataTypeCode,  sizeof(HeaderData.dataTypeCode));
    file.read((char*)&HeaderData.colorMapOrigin, sizeof(HeaderData.colorMapOrigin));
    file.read((char*)&HeaderData.colorMapLength, sizeof(HeaderData.colorMapLength));
    file.read((char*)&HeaderData.colorMapDepth, sizeof(HeaderData.colorMapDepth));
    file.read((char*)&HeaderData.xOrigin, sizeof(HeaderData.xOrigin));
    file.read((char*)&HeaderData.yOrigin, sizeof(HeaderData.yOrigin));
    file.read((char*)&HeaderData.width, sizeof(HeaderData.width));
    file.read((char*)&HeaderData.height, sizeof(HeaderData.height));
    file.read((char*)&HeaderData.bitsPerPixel, sizeof(HeaderData.bitsPerPixel));
    file.read((char*)&HeaderData.imageDescriptor, sizeof(HeaderData.imageDescriptor));

    pixels.reserve(HeaderData.width*HeaderData.height);

    for (int i = 0; i < HeaderData.width*HeaderData.height; i++) {
        Pixel_Data pixel;
        file.read((char*)&pixel.blue, sizeof(unsigned char));
        file.read((char*)&pixel.green, sizeof(unsigned char));
        file.read((char*)&pixel.red, sizeof(unsigned char));
        pixels.push_back(pixel);
        }

    file.close();
    }


void TGA_Reader::createFile(const char *name,
                            const TGA_HeaderData &headerData,
                            const vector<Pixel_Data> &pixels) {
    ofstream outfile;

    outfile.open("/Users/diegogomez/CLionProjects/Project2/cmake-build-debug/Hello3.tga",ios::binary);

    outfile.write((char*)&headerData.idLength, sizeof(headerData.idLength));
    outfile.write((char*)&headerData.colorMapType, sizeof(headerData.colorMapType));
    outfile.write((char*)&headerData.dataTypeCode,  sizeof(headerData.dataTypeCode));
    outfile.write((char*)&headerData.colorMapOrigin, sizeof(headerData.colorMapOrigin));
    outfile.write((char*)&headerData.colorMapLength, sizeof(headerData.colorMapLength));
    outfile.write((char*)&headerData.colorMapDepth, sizeof(headerData.colorMapDepth));
    outfile.write((char*)&headerData.xOrigin, sizeof(headerData.xOrigin));
    outfile.write((char*)&headerData.yOrigin, sizeof(headerData.yOrigin));
    outfile.write((char*)&headerData.width, sizeof(headerData.width));
    outfile.write((char*)&headerData.height, sizeof(headerData.height));
    outfile.write((char*)&headerData.bitsPerPixel, sizeof(headerData.bitsPerPixel));
    outfile.write((char*)&headerData.imageDescriptor, sizeof(headerData.imageDescriptor));

    cout<<pixels.size()<<endl;

    for (int i = 0; i < pixels.size(); i++) {
        outfile.write((char*)&pixels[i].blue, sizeof(unsigned char));
        outfile.write((char*)&pixels[i].green, sizeof(unsigned char));
        outfile.write((char*)&pixels[i].red, sizeof(unsigned char));
    }
    outfile.close();
}

TGA_Reader TGA_Reader::add_green_channel(int value) {

    TGA_Reader copy(*this); // make a copy of the object
    for (int i = 0; i < copy.pixels.size(); i++) {
        int pixel = (int) (copy.pixels[i].green + value);
        if (pixel < 0) {
            int pixel = 0;
        }
        if (pixel > 255) {
            int pixel = 255;
        }
        (unsigned char)(pixel);
        copy.pixels[i].green = pixel;

    }
    return copy; // return the modified copy
}

问题根源分析

  1. 有符号char的解析错误:Pixel_Data中的green是默认有符号的char类型,TGA图像的颜色值是0-255的无符号数据,读取时128-255会被解析为负数,哪怕加0也会因为类型转换导致数值异常。
  2. 变量作用域错误:add_green_channel函数的if块内重新定义了pixel变量,外层的pixel根本不会被修改,等于白做了范围钳制。
  3. 无效的类型转换:(unsigned char)(pixel);只是做了转换但没有赋值给任何变量,最终还是把未正确处理的int值直接塞给char类型的绿色通道。
  4. 硬编码输出路径:createFile函数写死了输出路径,不仅不灵活,还可能因路径权限或不存在导致输出异常。

修复后的代码

头文件部分

#ifndef PROJECT2_TGA_READER_H
#define PROJECT2_TGA_READER_H

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm> // 用于max/min函数

using namespace std;
struct TGA_HeaderData{
    unsigned char idLength;
    unsigned char colorMapType;
    unsigned char dataTypeCode;
    short colorMapOrigin;
    short colorMapLength;
    unsigned char colorMapDepth;
    short xOrigin;
    short yOrigin;
    short width;
    short height;
    unsigned char bitsPerPixel;
    unsigned char imageDescriptor;
};
struct Pixel_Data{
    unsigned char blue;
    unsigned char green;
    unsigned char red;
};


class TGA_Reader {
public:
    TGA_Reader(string file_name);

    TGA_HeaderData HeaderData{};

    vector<Pixel_Data> pixels;

    void DeclareFile(string file_name);

    void createFile(const char *name, const TGA_HeaderData &headerData, const vector<Pixel_Data> &pixels);

    TGA_Reader add_green_channel(int value);
};
#endif // PROJECT2_TGA_READER_H

实现文件部分

#include "TGA_Reader.h"

TGA_Reader::TGA_Reader(string file_name) {
    DeclareFile(file_name);
}

void TGA_Reader::DeclareFile(string file_name) {
    ifstream file(file_name, ios::binary);
    if (!file){
        cout<<"not open"<<endl;
        return;
    }
    file.read((char*)&HeaderData.idLength, sizeof(HeaderData.idLength));
    file.read((char*)&HeaderData.colorMapType, sizeof(HeaderData.colorMapType));
    file.read((char*)&HeaderData.dataTypeCode,  sizeof(HeaderData.dataTypeCode));
    file.read((char*)&HeaderData.colorMapOrigin, sizeof(HeaderData.colorMapOrigin));
    file.read((char*)&HeaderData.colorMapLength, sizeof(HeaderData.colorMapLength));
    file.read((char*)&HeaderData.colorMapDepth, sizeof(HeaderData.colorMapDepth));
    file.read((char*)&HeaderData.xOrigin, sizeof(HeaderData.xOrigin));
    file.read((char*)&HeaderData.yOrigin, sizeof(HeaderData.yOrigin));
    file.read((char*)&HeaderData.width, sizeof(HeaderData.width));
    file.read((char*)&HeaderData.height, sizeof(HeaderData.height));
    file.read((char*)&HeaderData.bitsPerPixel, sizeof(HeaderData.bitsPerPixel));
    file.read((char*)&HeaderData.imageDescriptor, sizeof(HeaderData.imageDescriptor));

    pixels.reserve(HeaderData.width*HeaderData.height);

    for (int i = 0; i < HeaderData.width*HeaderData.height; i++) {
        Pixel_Data pixel;
        file.read((char*)&pixel.blue, sizeof(pixel.blue));
        file.read((char*)&pixel.green, sizeof(pixel.green));
        file.read((char*)&pixel.red, sizeof(pixel.red));
        pixels.push_back(pixel);
    }

    file.close();
}


void TGA_Reader::createFile(const char *name,
                            const TGA_HeaderData &headerData,
                            const vector<Pixel_Data> &pixels) {
    ofstream outfile(name, ios::binary);
    if (!outfile) {
        cout<<"Failed to create output file"<<endl;
        return;
    }

    outfile.write((char*)&headerData.idLength, sizeof(headerData.idLength));
    outfile.write((char*)&headerData.colorMapType, sizeof(headerData.colorMapType));
    outfile.write((char*)&headerData.dataTypeCode,  sizeof(headerData.dataTypeCode));
    outfile.write((char*)&headerData.colorMapOrigin, sizeof(headerData.colorMapOrigin));
    outfile.write((char*)&headerData.colorMapLength, sizeof(headerData.colorMapLength));
    outfile.write((char*)&headerData.colorMapDepth, sizeof(headerData.colorMapDepth));
    outfile.write((char*)&headerData.xOrigin, sizeof(headerData.xOrigin));
    outfile.write((char*)&headerData.yOrigin, sizeof(headerData.yOrigin));
    outfile.write((char*)&headerData.width, sizeof(headerData.width));
    outfile.write((char*)&headerData.height, sizeof(headerData.height));
    outfile.write((char*)&headerData.bitsPerPixel, sizeof(headerData.bitsPerPixel));
    outfile.write((char*)&headerData.imageDescriptor, sizeof(headerData.imageDescriptor));

    cout<<pixels.size()<<endl;

    for (const auto& pixel : pixels) {
        outfile.write((char*)&pixel.blue, sizeof(pixel.blue));
        outfile.write((char*)&pixel.green, sizeof(pixel.green));
        outfile.write((char*)&pixel.red, sizeof(pixel.red));
    }
    outfile.close();
}

TGA_Reader TGA_Reader::add_green_channel(int value) {
    TGA_Reader copy(*this);
    for (auto& pixel : copy.pixels) {
        int green_val = static_cast<int>(pixel.green) + value;
        // 钳制到0-255的合法范围
        green_val = max(0, min(green_val, 255));
        pixel.green = static_cast<unsigned char>(green_val);
    }
    return copy;
}

修复说明

  1. 改用无符号字符类型:将所有存储图像数据和TGA头的char替换为unsigned char,彻底避免有符号类型的解析和溢出问题。
  2. 修复变量作用域:移除if块内的变量重定义,直接修改外层的颜色值变量,确保范围钳制生效。
  3. 有效类型转换:使用static_cast进行安全的类型转换,并将转换后的值赋值给绿色通道。
  4. 替换硬编码路径:createFile函数使用传入的参数作为输出路径,增强灵活性。
  5. 添加文件检查:创建输出文件时检查是否成功打开,避免后续无意义操作。
  6. 优化循环写法:使用范围for循环遍历像素,代码更简洁且不易出错。

内容的提问来源于stack exchange,提问作者DJA15

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:45:00