我有两张像素尺寸相同的图片:org.jpg 和 temple.jpg。我想完成以下任务:
我已经确保 org.jpg 和 temple.jpg 的像素尺寸相同。并尝试编写代码:
#include <iostream>
#include <string>
#include <cstdio>
#include <jpeglib.h>
#include <jerror.h>
#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>
// Manually copy quantization table
void copy_quant_table(JQUANT_TBL* src, JQUANT_TBL* dst) {
for (int i = 0; i < DCTSIZE2; i++) {
dst->quantval[i] = src->quantval[i];
}
}
// Manually copy huffman table
void copy_huff_table(JHUFF_TBL* src, JHUFF_TBL* dst) {
for (int i = 0; i < 256; i++) {
dst->bits[i] = src->bits[i];
dst->huffval[i] = src->huffval[i];
}
}
void custom_copy_critical_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo) {
dstinfo->image_width = srcinfo->image_width;
dstinfo->image_height = srcinfo->image_height;
dstinfo->input_components = srcinfo->num_components;
dstinfo->in_color_space = srcinfo->jpeg_color_space;
jpeg_set_defaults(dstinfo);
jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space);
dstinfo->data_precision = srcinfo->data_precision;
dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;
for (int ci = 0; ci < srcinfo->num_components; ci++) {
jpeg_component_info* compptr = &srcinfo->comp_info[ci];
jpeg_component_info* dstcompptr = &dstinfo->comp_info[ci];
dstcompptr->h_samp_factor = compptr->h_samp_factor;
dstcompptr->v_samp_factor = compptr->v_samp_factor;
}
}
void replace_ffda_hex_code(const std::string& ref_filename, const std::string& output_filename) {
// 打开参考文件和输出文件
std::ifstream ref_file(ref_filename, std::ios::binary);
std::ifstream output_file(output_filename, std::ios::binary);
if (!ref_file || !output_file) {
std::cerr << "Error opening files for hex code replacement." << std::endl;
exit(1);
}
// 寻找FFDA标记
const uint8_t marker_ff = 0xFF;
const uint8_t marker_da = 0xDA;
auto find_ffda_marker = [](std::ifstream& file) -> std::streampos {
uint8_t byte1, byte2;
byte1 = file.get();
byte2 = file.get();
while (!file.eof()) {
if (byte1 == marker_ff && byte2 == marker_da) {
return file.tellg() - std::streamoff(2);
}
byte1 = byte2;
byte2 = file.get();
}
return std::streampos(-1);
};
// 在两个文件中找到FFDA标记的位置
std::streampos ref_ffda_pos = find_ffda_marker(ref_file);
std::streampos output_ffda_pos = find_ffda_marker(output_file);
if (ref_ffda_pos == std::streampos(-1) || output_ffda_pos == std::streampos(-1)) {
std::cerr << "FFDA marker not found in one of the files." << std::endl;
exit(1);
}
// 创建临时文件以保存修改后的输出文件内容
std::ofstream temp_file("temp_output.jpg", std::ios::binary);
if (!temp_file) {
std::cerr << "Error creating temporary file." << std::endl;
exit(1);
}
// 将参考文件的FFDA之前的内容复制到临时文件
ref_file.seekg(0, std::ios::beg);
std::copy_n(std::istreambuf_iterator<char>(ref_file), ref_ffda_pos, std::ostreambuf_iterator<char>(temp_file));
// 将输出文件的FFDA之后的内容复制到临时文件
output_file.seekg(output_ffda_pos, std::ios::beg);
temp_file << output_file.rdbuf();
// 关闭文件
ref_file.close();
output_file.close();
temp_file.close();
// 使用修改后的临时文件覆盖原始输出文件
std::remove(output_filename.c_str());
std::rename("temp_output.jpg", output_filename.c_str());
}
void Debug_output_decompress_Huffman_and_quantization(jpeg_decompress_struct& info, const std::string& name) {
std::cout << name << std::endl << " Quantization tables:" << std::endl;
for (int i = 0; i < NUM_QUANT_TBLS; i++) {
std::cout << "Table " << i << ": ";
if (info.quant_tbl_ptrs[i] != nullptr) {
for (int j = 0; j < DCTSIZE2; j++) {
std::cout << info.quant_tbl_ptrs[i]->quantval[j] << " ";
}
}
std::cout << std::endl;
}
std::cout << name << " Huffman tables:" << std::endl;
for (int i = 0; i < NUM_HUFF_TBLS; i++) {
std::cout << "Table " << i << ": ";
if (info.dc_huff_tbl_ptrs[i] != nullptr) {
std::cout << "DC Table " << i << " bits: ";
for (int j = 0; j < 17; j++) {
std::cout << (int)info.dc_huff_tbl_ptrs[i]->bits[j] << " ";
}
std::cout << " values: ";
for (int j = 0; j < 256; j++) {
std::cout << (int)info.dc_huff_tbl_ptrs[i]->huffval[j] << " ";
}
}
std::cout << std::endl;
if (info.ac_huff_tbl_ptrs[i] != nullptr) {
std::cout << "AC Table " << i << " bits: ";
for (int j = 0; j < 17; j++) {
std::cout << (int)info.ac_huff_tbl_ptrs[i]->bits[j] << " ";
}
std::cout << " values: ";
for (int j = 0; j < 256; j++) {
std::cout << (int)info.ac_huff_tbl_ptrs[i]->huffval[j] << " ";
}
}
std::cout << std::endl;
}
std::cout << "**---------------finish output---------------**" << std::endl;
std::cout << std::endl;
}
void Debug_output_compress_Huffman_and_quantization(jpeg_compress_struct& info, const std::string& name) {
std::cout << name << std::endl << " Quantization tables:" << std::endl;
for (int i = 0; i < NUM_QUANT_TBLS; i++) {
std::cout << "Table " << i << ": ";
if (info.quant_tbl_ptrs[i] != nullptr) {
for (int j = 0; j < DCTSIZE2; j++) {
std::cout << info.quant_tbl_ptrs[i]->quantval[j] << " ";
}
}
std::cout << std::endl;
}
std::cout << name << " Huffman tables:" << std::endl;
for (int i = 0; i < NUM_HUFF_TBLS; i++) {
std::cout << "Table " << i << ": ";
if (info.dc_huff_tbl_ptrs[i] != nullptr) {
std::cout << "DC Table " << i << " bits: ";
for (int j = 0; j < 17; j++) {
std::cout << (int)info.dc_huff_tbl_ptrs[i]->bits[j] << " ";
}
std::cout << " values: ";
for (int j = 0; j < 256; j++) {
std::cout << (int)info.dc_huff_tbl_ptrs[i]->huffval[j] << " ";
}
}
std::cout << std::endl;
if (info.ac_huff_tbl_ptrs[i] != nullptr) {
std::cout << "AC Table " << i << " bits: ";
for (int j = 0; j < 17; j++) {
std::cout << (int)info.ac_huff_tbl_ptrs[i]->bits[j] << " ";
}
std::cout << " values: ";
for (int j = 0; j < 256; j++) {
std::cout << (int)info.ac_huff_tbl_ptrs[i]->huffval[j] << " ";
}
}
std::cout << std::endl;
}
std::cout << "**---------------finish output---------------**" << std::endl;
std::cout << std::endl;
}
void copy_jpeg_file(const std::string& input_filename, const std::string& ref_filename, const std::string& output_filename) {
// Open input and reference files
FILE* input_file;
FILE* ref_file;
errno_t err;
err = fopen_s(&input_file, input_filename.c_str(), "rb");
err = fopen_s(&ref_file, ref_filename.c_str(), "rb");
if (!input_file || !ref_file) {
std::cerr << "Error opening files." << std::endl;
exit(1);
}
// Input image decompression
struct jpeg_decompress_struct srcinfo;
struct jpeg_error_mgr srcerr;
srcinfo.err = jpeg_std_error(&srcerr);
jpeg_create_decompress(&srcinfo);
jpeg_stdio_src(&srcinfo, input_file);
jpeg_read_header(&srcinfo, TRUE);
// Reference image decompression
struct jpeg_decompress_struct refinfo;
struct jpeg_error_mgr referr;
refinfo.err = jpeg_std_error(&referr);
jpeg_create_decompress(&refinfo);
jpeg_stdio_src(&refinfo, ref_file);
jpeg_read_header(&refinfo, TRUE);
// Output image compression
struct jpeg_compress_struct dstinfo;
struct jpeg_error_mgr dsterr;
dstinfo.err = jpeg_std_error(&dsterr);
jpeg_create_compress(&dstinfo);
FILE* output_file;
err = fopen_s(&output_file, output_filename.c_str(), "wb");
if (!output_file) {
std::cerr << "Error opening output file." << std::endl;
exit(1);
}
jpeg_stdio_dest(&dstinfo, output_file);
custom_copy_critical_parameters(&refinfo, &dstinfo);
// Set input color space for output image
dstinfo.in_color_space = srcinfo.out_color_space;
// Disable JFIF header
dstinfo.write_JFIF_header = FALSE;
dstinfo.optimize_coding = FALSE;
dstinfo.smoothing_factor = 0;
dstinfo.dct_method = JDCT_ISLOW;
dstinfo.comp_info[0].h_samp_factor = refinfo.comp_info[0].h_samp_factor;
dstinfo.comp_info[0].v_samp_factor = refinfo.comp_info[0].v_samp_factor;
dstinfo.comp_info[1].h_samp_factor = refinfo.comp_info[1].h_samp_factor;
dstinfo.comp_info[1].v_samp_factor = refinfo.comp_info[1].v_samp_factor;
dstinfo.comp_info[2].h_samp_factor = refinfo.comp_info[2].h_samp_factor;
dstinfo.comp_info[2].v_samp_factor = refinfo.comp_info[2].v_samp_factor;
Debug_output_compress_Huffman_and_quantization(dstinfo, "dstinfo huff_table and quant_table before copied");
// Copy DQT、SOF and DHT
for (int i = 0; i < NUM_QUANT_TBLS; i++) {
if (refinfo.quant_tbl_ptrs[i] != nullptr) {
if (dstinfo.quant_tbl_ptrs[i] == nullptr) {
dstinfo.quant_tbl_ptrs[i] = jpeg_alloc_quant_table((j_common_ptr)&dstinfo);
}
copy_quant_table(refinfo.quant_tbl_ptrs[i], dstinfo.quant_tbl_ptrs[i]);
}
}
for (int i = 0; i < NUM_HUFF_TBLS; i++) {
if (refinfo.dc_huff_tbl_ptrs[i] != nullptr) {
if (dstinfo.dc_huff_tbl_ptrs[i] == nullptr) {
dstinfo.dc_huff_tbl_ptrs[i] = jpeg_alloc_huff_table((j_common_ptr)&dstinfo);
}
copy_huff_table(refinfo.dc_huff_tbl_ptrs[i], dstinfo.dc_huff_tbl_ptrs[i]);
}
if (refinfo.ac_huff_tbl_ptrs[i] != nullptr) {
if (dstinfo.ac_huff_tbl_ptrs[i] == nullptr) {
dstinfo.ac_huff_tbl_ptrs[i] = jpeg_alloc_huff_table((j_common_ptr)&dstinfo);
}
copy_huff_table(refinfo.ac_huff_tbl_ptrs[i], dstinfo.ac_huff_tbl_ptrs[i]);
}
}
Debug_output_decompress_Huffman_and_quantization(srcinfo, "srcinfo huff_table and quant_table after copied");
Debug_output_compress_Huffman_and_quantization(dstinfo, "dstinfo huff_table and quant_table after copied");
Debug_output_decompress_Huffman_and_quantization(refinfo, "refinfo huff_table and quant_table after copied");
// Start decompression of input image and compression of output image
jpeg_start_decompress(&srcinfo);
jpeg_start_compress(&dstinfo, TRUE);
// Allocate memory for scanlines buffer
JSAMPARRAY buffer = (*srcinfo.mem->alloc_sarray)((j_common_ptr)&srcinfo, JPOOL_IMAGE, srcinfo.output_width * srcinfo.output_components, 1);
// Copy scanlines from input image to output image
while (srcinfo.output_scanline < srcinfo.output_height) {
jpeg_read_scanlines(&srcinfo, buffer, 1);
jpeg_write_scanlines(&dstinfo, buffer, 1);
}
// Finish decompression and compression
jpeg_finish_decompress(&srcinfo);
jpeg_finish_compress(&dstinfo);
// Destroy structures and close files
jpeg_destroy_decompress(&srcinfo);
jpeg_destroy_decompress(&refinfo);
jpeg_destroy_compress(&dstinfo);
fclose(input_file);
fclose(ref_file);
fclose(output_file);
}
int main() {
std::string input_filename = "org.JPG";
std::string ref_filename = "temple.jpg";
std::string output_filename = "target.jpg";
// Copy critical parameters from temple.jpg to target.jpg
copy_jpeg_file(input_filename, ref_filename, output_filename);
//replace_ffda_hex_code(ref_filename, output_filename);
return 0;
}
上面的代码已经生成了target.jpg,但其实经过对比,target.jpg和temple.jpg的HEX码还是不一样的。我不确定是什么导致了这种差异。我是不是哪里做错了什么?