/* Display the names and sizes of all chunks in the PNG file. */ void displayChunkNames(const std::vector<unsigned char>& buffer) { // Listing chunks is based on the original file, not the decoded png info. const unsigned char *chunk, *begin, *end, *next; end = &buffer.back() + 1; begin = chunk = &buffer.front() + 8; std::cout << std::endl << "Chunks:" << std::endl; std::cout << " type: length(s)"; std::string last_type; while(chunk + 8 < end && chunk >= begin) { char type[5]; lodepng_chunk_type(type, chunk); if(std::string(type).size() != 4) { std::cout << "this is probably not a PNG" << std::endl; return; } if(last_type != type) { std::cout << std::endl; std::cout << " " << type << ": "; } last_type = type; std::cout << lodepng_chunk_length(chunk) << ", "; next = lodepng_chunk_next_const(chunk); if (next <= chunk) break; // integer overflow chunk = next; } std::cout << std::endl; }
unsigned getChunkInfo(std::vector<std::string>& names, std::vector<size_t>& sizes, const std::vector<unsigned char>& png) { // Listing chunks is based on the original file, not the decoded png info. const unsigned char *chunk, *begin, *end, *next; end = &png.back() + 1; begin = chunk = &png.front() + 8; while(chunk + 8 < end && chunk >= begin) { char type[5]; lodepng_chunk_type(type, chunk); if(std::string(type).size() != 4) return 1; unsigned length = lodepng_chunk_length(chunk); if(chunk + length + 12 > end) return 1; names.push_back(type); sizes.push_back(length); next = lodepng_chunk_next_const(chunk); if (next <= chunk) return 1; // integer overflow chunk = next; } return 0; }
unsigned getChunks(std::vector<std::string> names[3], std::vector<std::vector<unsigned char> > chunks[3], const std::vector<unsigned char>& png) { const unsigned char *chunk, *next, *begin, *end; end = &png.back() + 1; begin = chunk = &png.front() + 8; int location = 0; while (chunk + 8 < end && chunk >= begin) { char type[5]; lodepng_chunk_type(type, chunk); std::string name(type); if (name.size() != 4) return 1; next = lodepng_chunk_next_const(chunk); if (name == "IHDR") { location = 0; } else if (name == "PLTE") { location = 1; } else if (name == "IDAT") { location = 2; } else if (name != "IEND") { names[location].push_back(name); chunks[location].push_back(std::vector<unsigned char>(chunk, next)); } chunk = next; } return 0; }
unsigned insertChunks(std::vector<unsigned char>& png, const std::vector<std::vector<unsigned char> > chunks[3]) { const unsigned char *chunk, *next, *begin, *end; end = &png.back() + 1; begin = chunk = &png.front() + 8; ptrdiff_t l0 = 0; //location 0: IHDR-l0-PLTE (or IHDR-l0-l1-IDAT) ptrdiff_t l1 = 0; //location 1: PLTE-l1-IDAT (or IHDR-l0-l1-IDAT) ptrdiff_t l2 = 0; //location 2: IDAT-l2-IEND while(chunk + 8 < end && chunk >= begin) { char type[5]; lodepng_chunk_type(type, chunk); std::string name(type); if(name.size() != 4) return 1; next = lodepng_chunk_next_const(chunk); if (next <= chunk) return 1; // integer overflow if(name == "PLTE") { if(l0 == 0) l0 = chunk - begin + 8; } else if(name == "IDAT") { if(l0 == 0) l0 = chunk - begin + 8; if(l1 == 0) l1 = chunk - begin + 8; } else if(name == "IEND") { if(l2 == 0) l2 = chunk - begin + 8; } chunk = next; } std::vector<unsigned char> result; result.insert(result.end(), png.begin(), png.begin() + l0); for(size_t i = 0; i < chunks[0].size(); i++) result.insert(result.end(), chunks[0][i].begin(), chunks[0][i].end()); result.insert(result.end(), png.begin() + l0, png.begin() + l1); for(size_t i = 0; i < chunks[1].size(); i++) result.insert(result.end(), chunks[1][i].begin(), chunks[1][i].end()); result.insert(result.end(), png.begin() + l1, png.begin() + l2); for(size_t i = 0; i < chunks[2].size(); i++) result.insert(result.end(), chunks[2][i].begin(), chunks[2][i].end()); result.insert(result.end(), png.begin() + l2, png.end()); png = result; return 0; }
/* Show the filtertypes of each scanline in this PNG image. */ void displayFilterTypes(const std::vector<unsigned char>& buffer, bool ignore_checksums) { //Get color type and interlace type lodepng::State state; if(ignore_checksums) { state.decoder.ignore_crc = 1; state.decoder.zlibsettings.ignore_adler32 = 1; } unsigned w, h; unsigned error; error = lodepng_inspect(&w, &h, &state, &buffer[0], buffer.size()); if(error) { std::cout << "inspect error " << error << ": " << lodepng_error_text(error) << std::endl; return; } if(state.info_png.interlace_method == 1) { std::cout << "showing filtertypes for interlaced PNG not supported by this example" << std::endl; return; } //Read literal data from all IDAT chunks const unsigned char *chunk, *begin, *end, *next; end = &buffer.back() + 1; begin = chunk = &buffer.front() + 8; std::vector<unsigned char> zdata; while(chunk + 8 < end && chunk >= begin) { char type[5]; lodepng_chunk_type(type, chunk); if(std::string(type).size() != 4) { std::cout << "this is probably not a PNG" << std::endl; return; } if(std::string(type) == "IDAT") { const unsigned char* cdata = lodepng_chunk_data_const(chunk); unsigned clength = lodepng_chunk_length(chunk); if(chunk + clength + 12 > end || clength > buffer.size() || chunk + clength + 12 < begin) { std::cout << "invalid chunk length" << std::endl; return; } for(unsigned i = 0; i < clength; i++) { zdata.push_back(cdata[i]); } } next = lodepng_chunk_next_const(chunk); if (next <= chunk) break; // integer overflow chunk = next; } //Decompress all IDAT data std::vector<unsigned char> data; error = lodepng::decompress(data, &zdata[0], zdata.size()); if(error) { std::cout << "decompress error " << error << ": " << lodepng_error_text(error) << std::endl; return; } //A line is 1 filter byte + all pixels size_t linebytes = 1 + lodepng_get_raw_size(w, 1, &state.info_png.color); if(linebytes == 0) { std::cout << "error: linebytes is 0" << std::endl; return; } std::cout << "Filter types: "; for(size_t i = 0; i < data.size(); i += linebytes) { std::cout << (int)(data[i]) << " "; } std::cout << std::endl; }
unsigned getFilterTypesInterlaced(std::vector<std::vector<unsigned char> >& filterTypes, const std::vector<unsigned char>& png) { //Get color type and interlace type lodepng::State state; unsigned w, h; unsigned error; error = lodepng_inspect(&w, &h, &state, &png[0], png.size()); if(error) return 1; //Read literal data from all IDAT chunks const unsigned char *chunk, *begin, *end, *next; end = &png.back() + 1; begin = chunk = &png.front() + 8; std::vector<unsigned char> zdata; while(chunk + 8 < end && chunk >= begin) { char type[5]; lodepng_chunk_type(type, chunk); if(std::string(type).size() != 4) return 1; //Probably not a PNG file if(std::string(type) == "IDAT") { const unsigned char* cdata = lodepng_chunk_data_const(chunk); unsigned clength = lodepng_chunk_length(chunk); if(chunk + clength + 12 > end || clength > png.size() || chunk + clength + 12 < begin) { // corrupt chunk length return 1; } for(unsigned i = 0; i < clength; i++) { zdata.push_back(cdata[i]); } } next = lodepng_chunk_next_const(chunk); if (next <= chunk) return 1; // integer overflow chunk = next; } //Decompress all IDAT data std::vector<unsigned char> data; error = lodepng::decompress(data, &zdata[0], zdata.size()); if(error) return 1; if(state.info_png.interlace_method == 0) { filterTypes.resize(1); //A line is 1 filter byte + all pixels size_t linebytes = 1 + lodepng_get_raw_size(w, 1, &state.info_png.color); for(size_t i = 0; i < data.size(); i += linebytes) { filterTypes[0].push_back(data[i]); } } else { //Interlaced filterTypes.resize(7); static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ size_t pos = 0; for(size_t j = 0; j < 7; j++) { unsigned w2 = (w - ADAM7_IX[j] + ADAM7_DX[j] - 1) / ADAM7_DX[j]; unsigned h2 = (h - ADAM7_IY[j] + ADAM7_DY[j] - 1) / ADAM7_DY[j]; if(ADAM7_IX[j] >= w || ADAM7_IY[j] >= h) w2 = h2 = 0; size_t linebytes = 1 + lodepng_get_raw_size(w2, 1, &state.info_png.color); for(size_t i = 0; i < h2; i++) { filterTypes[j].push_back(data[pos]); pos += linebytes; } } } return 0; /* OK */ }