使用libtiff在C语言中读写TIFF文件时输出黑图问题求助
问题分析与修复方案
你的代码输出全黑图像,核心是几个关键逻辑错误导致的,以下是问题点和修复后的完整代码:
关键错误点
- 错误复用
STRIPOFFSETS和STRIPBYTECOUNTS:这两个标签是输入文件内部的字节偏移与条带大小记录,输出文件有独立的文件结构,直接复制会导致输出文件的偏移指向无效位置,无法正确解析图像数据。 - 强制设置
COLORMAP:如果输入文件不是调色板类型TIFF(比如灰度、RGB图),强行设置调色板会破坏图像的颜色解释逻辑,引发显示异常。 - 缺失关键标签
PHOTOMETRIC:这个标签定义了图像的光度解释类型(灰度、RGB、调色板等),未设置会导致阅读器无法正确识别图像色彩模式。 - 未检查关键操作返回值:输出文件打开、内存分配、条带读取/写入的操作未做错误校验,一旦失败会引发后续逻辑崩溃。
- 输出文件打开模式错误:使用
w+不符合libtiff推荐写法,应使用w创建新文件。
修复后的代码
// Include necessary header files #include <stdio.h> #include <stdlib.h> #include <tiffio.h> // Main function int main() { // Open the input TIFF file TIFF* tif_in = TIFFOpen("image.tiff", "rb"); if (!tif_in) { printf("Failed to open input TIFF file.\n"); return 1; } // Open the output TIFF file TIFF* tif_out = TIFFOpen("output.tiff", "w"); if (!tif_out) { printf("Failed to open output TIFF file.\n"); TIFFClose(tif_in); return 1; } // Variables to store image properties uint32 width, height; uint16 bits_per_sample, samples_per_pixel, photometric, planar_config; uint32 strip_size; uint8* strip_data; uint32 number_of_strips; uint16 compression_method; // Retrieve core image properties from input TIFFGetField(tif_in, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(tif_in, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(tif_in, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); TIFFGetField(tif_in, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); TIFFGetField(tif_in, TIFFTAG_COMPRESSION, &compression_method); TIFFGetField(tif_in, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(tif_in, TIFFTAG_PLANARCONFIG, &planar_config); // Set core properties for output file TIFFSetField(tif_out, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(tif_out, TIFFTAG_IMAGELENGTH, height); TIFFSetField(tif_out, TIFFTAG_BITSPERSAMPLE, bits_per_sample); TIFFSetField(tif_out, TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel); TIFFSetField(tif_out, TIFFTAG_COMPRESSION, compression_method); TIFFSetField(tif_out, TIFFTAG_PHOTOMETRIC, photometric); TIFFSetField(tif_out, TIFFTAG_PLANARCONFIG, planar_config); // Only copy color map if input is palette-type image if (photometric == PHOTOMETRIC_PALETTE) { uint16 cmap_depth; uint16 *cmap_red, *cmap_green, *cmap_blue; TIFFGetField(tif_in, TIFFTAG_COLORMAP, &cmap_red, &cmap_green, &cmap_blue); TIFFGetField(tif_in, TIFFTAG_COLORMAPDEPTH, &cmap_depth); TIFFSetField(tif_out, TIFFTAG_COLORMAP, cmap_red, cmap_green, cmap_blue); TIFFSetField(tif_out, TIFFTAG_COLORMAPDEPTH, cmap_depth); } // Allocate memory for strip data strip_size = TIFFStripSize(tif_in); strip_data = (uint8*)malloc(strip_size); if (!strip_data) { printf("Failed to allocate memory for strip data.\n"); TIFFClose(tif_in); TIFFClose(tif_out); return 1; } // Get total number of strips number_of_strips = TIFFNumberOfStrips(tif_in); // Print image properties for debugging printf("Strip size is %u\n", strip_size); printf("Number of strips are %u\n", number_of_strips); printf("Compression method is %u\n", compression_method); printf("Width: %u, Height: %u\n", width, height); printf("Photometric interpretation: %u\n", photometric); // Read and write each strip for (uint32 strip = 0; strip < number_of_strips; strip++) { tsize_t bytes_read = TIFFReadEncodedStrip(tif_in, strip, strip_data, strip_size); if (bytes_read < 0) { printf("Failed to read strip %u\n", strip); free(strip_data); TIFFClose(tif_in); TIFFClose(tif_out); return 1; } if (TIFFWriteEncodedStrip(tif_out, strip, strip_data, bytes_read) < 0) { printf("Failed to write strip %u\n", strip); free(strip_data); TIFFClose(tif_in); TIFFClose(tif_out); return 1; } } // Cleanup resources TIFFClose(tif_in); TIFFClose(tif_out); free(strip_data); return 0; }
额外说明
- 代码会根据输入文件的
PHOTOMETRIC标签自动判断是否复制调色板,避免强制设置引发的兼容性问题。 - 所有关键操作都添加了错误校验,能及时定位并报告问题。
- 不再手动处理条带偏移和字节计数,由libtiff自动管理输出文件的结构标签。
- 使用读取操作的实际字节数作为写入长度,确保数据完全一致。
内容的提问来源于stack exchange,提问作者hacker4life
相关产品推荐
相关产品推荐

