Чтение и запись файла png без изменения размера файла в C (libpng)

Я хочу прочитать файл png, просмотреть данные изображения и снова записать без изменения размера файла. Основываясь на документах libpng, png без потерь и использует deflate и lz77 для сжатия. В libpng есть пример проекта, который утверждает, что читает и записывает изображение без потерь, он правильный в значениях пикселей, но изменяет структуру файла (например, количество IDAT, необязательных фрагментов и т. Д.) Размер файла png.

Мой явный вопрос: как извлечь параметры кодирования (такие как параметры deflate или параметры lz77) из сжатого потока (Zstream в libpng) и использовать эти параметры для кодирования необработанного изображения для создания файла изображения, такого же, как входной файл, без каких-либо изменений?

Это мой код. Я пытаюсь сохранить параметры в info_ptr для записи изображения, но не работает. Как это сделать?

int main(int argc, char *argv[])
{
inname = argv[1];
outname = argv[2];

png_structrp read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(read_ptr);



if (!info_ptr)
{
    png_destroy_read_struct(&read_ptr, (png_infopp)NULL, (png_infopp)NULL);
}

png_FILE_p imageFile, imageFile2, imageFileW;
    imageFile=fopen(inname, "rb");  imageFileW = fopen(outname, "wb"); imageFile2 = fopen(inname, "rb");

int fileSize=fsize(imageFile2);
unsigned char* bufImWrite = malloc(sizeof(char)*fileSize);
fread(bufImWrite, 1, fileSize, imageFile2);

png_init_io(read_ptr, imageFile);

png_read_info(read_ptr, info_ptr);


png_uint_32 height;
height = info_ptr->height;


png_bytep * row_pointers;

row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
for (int y = 0; y < height; y++)
    row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(read_ptr, info_ptr));


png_read_image(read_ptr, row_pointers);


png_read_end(read_ptr, info_ptr);


png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);;
png_init_io(png_ptr, imageFileW);
png_write_info(png_ptr, info_ptr);
//png_set_compression_level(png_ptr, 9);
//png_set_compression_window_bits(png_ptr, 15);
//png_set_compression_strategy(png_ptr, 3);
//png_set_compression_mem_level(png_ptr, 8);

png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);


}

person Ali Mahdavi    schedule 29.05.2017    source источник
comment
Это странная просьба. Если вы не хотите, чтобы файл менялся, просто скопируйте его. Если вы хотите изменить содержимое изображения, вполне вероятно, что добиться точно такой же степени сжатия невозможно. Если вы хотите изменить некоторые теги, измените их на месте.   -  person Yves Daoust    schedule 29.05.2017
comment
Этот вопрос правильный @YvesDaoust (проголосовал против?). Ему нужно получить необработанные данные изображения и снова сжать эти данные, чтобы создать тот же файл. Это отличается от копирования (в науке о сжатии). Каково ваше решение этой проблемы?   -  person M SH GOL    schedule 29.05.2017


Ответы (2)


В дополнение к правильному ответу Гленна, даже если вы каким-то образом использовали параметры для сжатия, сжатие могло быть выполнено кодом, который больше не доступен, или кодом, который является проприетарным и недоступным для вас. В любом случае невозможно воспроизвести точные сжатые данные. Просто сохраните исходные сжатые данные, если не собираетесь возиться с изображением.

person Mark Adler    schedule 29.05.2017

Файл PNG не содержит записи точных параметров deflate/zlib, используемых для сжатия, поэтому то, что вы хотите, на самом деле невозможно. Если вам нужно сохранить исходную кодировку, вам следует сохранить копию исходного файла PNG, а не читать его деструктивно.

Если вы хотите изменить вспомогательные фрагменты PNG без изменения данных изображения, используйте какое-либо приложение, например tweakpng, чтобы скопировать фрагменты IHDR, PLTE, IDAT и IEND из исходного файла PNG в новый файл.

Если, как предполагают комментарии, вы хотите добавить водяной знак без изменения сжатого потока данных, это просто невозможно, потому что данные изображения отличаются. Если вам действительно нужен съемный водяной знак, используйте редактируемый формат, например SVG, чтобы водяной знак был отдельным, или такой формат, как APNG, где водяной знак можно хранить в отдельной части. Недостатком этого является то, что любой может удалить водяной знак со своей копии.

person Glenn Randers-Pehrson    schedule 29.05.2017
comment
Спасибо @Glenn Randers-Pehrson, основываясь на вашей заметке, я не могу декодировать и кодировать файл png и создать идентичный файл. Я работаю над водяными знаками на изображениях, и мой метод ограничен размером файла. Другими словами, я хочу внедрить биты водяных знаков в сжатый поток данных png, а также учесть изменения adler и crc после обработки данных. Можете ли вы сказать мне, где лучше всего расположить сжатый поток zlib для манипуляций, сохраняющих структуру данных и качество изображения? - person Ali Mahdavi; 30.05.2017
comment
Если вы добавляете водяной знак, то вы изменяете данные изображения, и совершенно невозможно сохранить тот же сжатый поток данных, потому что сжимается другое изображение. - person Glenn Randers-Pehrson; 30.05.2017
comment
Я полагаю, что можно было бы использовать формат APNG для добавления водяного знака в качестве второго кадра, который будет накладываться на первый, но это, вероятно, выходит за рамки этого вопроса. Я предлагаю вам просто отказаться от этой идеи и жить с повторно сжатыми данными изображения. - person Glenn Randers-Pehrson; 30.05.2017
comment
Еще раз спасибо @Glenn Randers-Pehrson за ваше внимание, я знаю, что изображение с водяным знаком не совпадает с входным изображением, но создание идентичного изображения - это первый шаг. Потому что, если я не могу создать идентичное изображение, я не могу извлечь водяной знак с другой стороны. Итак, моя идея состоит в том, чтобы изменить сжатые данные и создать изображение, почти похожее на ввод. Я делаю это в jpeg, изменяя коэффициент DCT в сжатых данных и ищу способ сделать это в PNG (изменить результат дефляции). В любом случае спасибо вам. - person Ali Mahdavi; 31.05.2017