Comment compresser un tampon avec zlib?
Il y a un exemple d'utilisation sur le site de zlib:http://www.zlib.net/zlib_how.html
cependant dans l'exemple ils compriment un fichier. Je voudrais compresser des données binaires stockées dans une mémoire tampon. Je ne veux pas sauver le comprimé tampon sur le disque.
En Gros voici mon tampon:
fIplImageHeader->imageData = (char*)imageIn->getFrame();
Comment puis-je le compresser avec zlib?
j'apprécierais un peu de code exemple de la façon de le faire.
5 réponses
ceci est un exemple pour empaqueter un tampon avec zlib et enregistrer le contenu comprimé dans un vecteur.
void compress_memory(void *in_data, size_t in_data_size, std::vector<uint8_t> &out_data)
{
std::vector<uint8_t> buffer;
const size_t BUFSIZE = 128 * 1024;
uint8_t temp_buffer[BUFSIZE];
z_stream strm;
strm.zalloc = 0;
strm.zfree = 0;
strm.next_in = reinterpret_cast<uint8_t *>(in_data);
strm.avail_in = in_data_size;
strm.next_out = temp_buffer;
strm.avail_out = BUFSIZE;
deflateInit(&strm, Z_BEST_COMPRESSION);
while (strm.avail_in != 0)
{
int res = deflate(&strm, Z_NO_FLUSH);
assert(res == Z_OK);
if (strm.avail_out == 0)
{
buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE);
strm.next_out = temp_buffer;
strm.avail_out = BUFSIZE;
}
}
int deflate_res = Z_OK;
while (deflate_res == Z_OK)
{
if (strm.avail_out == 0)
{
buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE);
strm.next_out = temp_buffer;
strm.avail_out = BUFSIZE;
}
deflate_res = deflate(&strm, Z_FINISH);
}
assert(deflate_res == Z_STREAM_END);
buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE - strm.avail_out);
deflateEnd(&strm);
out_data.swap(buffer);
}
zlib.h
a toutes les fonctions dont vous avez besoin: compress
(ou compress2
et uncompress
. Voir le code source de zlib pour une réponse.
ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen));
/*
Compresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total size
of the destination buffer, which must be at least the value returned by
compressBound(sourceLen). Upon exit, destLen is the actual size of the
compressed buffer.
compress returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_BUF_ERROR if there was not enough room in the output
buffer.
*/
ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen));
/*
Decompresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total size
of the destination buffer, which must be large enough to hold the entire
uncompressed data. (The size of the uncompressed data must have been saved
previously by the compressor and transmitted to the decompressor by some
mechanism outside the scope of this compression library.) Upon exit, destLen
is the actual size of the uncompressed buffer.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_BUF_ERROR if there was not enough room in the output
buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In
the case where there is not enough room, uncompress() will fill the output
buffer with the uncompressed data up to that point.
*/
Vous pouvez facilement adapter l'exemple en remplaçant fread()
et fwrite()
appels avec des pointeurs directs vers vos données. Pour la compression zlib (appelée deflate comme vous "prendre tout l'air de vos données") vous allouer z_stream
structure, appeler deflateInit()
puis:
- remplir
next_in
avec le prochain bloc de données que vous voulez compresser - set
avail_in
au nombre d'octets disponibles ennext_in
- set
next_out
d'où l' les données compressées devraient être écrites, ce qui devrait normalement être un pointeur à l'intérieur de votre tampon qui avance au fur et à mesure que vous avancez - set
avail_out
au nombre d'octets disponibles ennext_out
- appel
deflate
- répéter les étapes 3 à 5 jusqu'à
avail_out
est non nul (c'est à dire il y a plus de place dans la mémoire tampon de sortie de zlib besoins - pas plus de données à écrire) - répétez les étapes 1 à 6 alors que vous avez données à compresser
eventuellement vous appelez deflateEnd()
et vous avez terminé.
vous lui donnez essentiellement des morceaux d'entrée et de sortie jusqu'à ce que vous n'ayez plus d'entrée et qu'il n'y ait plus de sortie.
ce n'est pas une réponse directe à votre question sur l'API zlib, mais vous pourriez être intéressé par boost::iostreams
bibliothèque jumelé avec zlib
.
cela permet d'utiliser zlib
- des algorithmes d'empaquetage pilotés en utilisant la notation de base des opérations "stream" et ensuite vos données pourraient être facilement compressées en ouvrant un certain flux de mémoire et en faisant le << data
opération.
En cas de boost::iostreams
cela appellerait automatiquement le filtre d'emballage correspondant pour toutes les données qui passent par le flux.
voici un exemple complet qui montre la compression et la décompression en utilisant C++
std::vector
objets:
#include <cstdio>
#include <iosfwd>
#include <iostream>
#include <vector>
#include <zconf.h>
#include <zlib.h>
#include <iomanip>
#include <cassert>
void add_buffer_to_vector(std::vector<char> &vector, const char *buffer, uLongf length) {
for (int character_index = 0; character_index < length; character_index++) {
char current_character = buffer[character_index];
vector.push_back(current_character);
}
}
int compress_vector(std::vector<char> source, std::vector<char> &destination) {
unsigned long source_length = source.size();
uLongf destination_length = compressBound(source_length);
char *destination_data = (char *) malloc(destination_length);
if (destination_data == nullptr) {
return Z_MEM_ERROR;
}
Bytef *source_data = (Bytef *) source.data();
int return_value = compress2((Bytef *) destination_data, &destination_length, source_data, source_length,
Z_BEST_COMPRESSION);
add_buffer_to_vector(destination, destination_data, destination_length);
free(destination_data);
return return_value;
}
int decompress_vector(std::vector<char> source, std::vector<char> &destination) {
unsigned long source_length = source.size();
uLongf destination_length = compressBound(source_length);
char *destination_data = (char *) malloc(destination_length);
if (destination_data == nullptr) {
return Z_MEM_ERROR;
}
Bytef *source_data = (Bytef *) source.data();
int return_value = uncompress((Bytef *) destination_data, &destination_length, source_data, source.size());
add_buffer_to_vector(destination, destination_data, destination_length);
free(destination_data);
return return_value;
}
void add_string_to_vector(std::vector<char> &uncompressed_data,
const char *my_string) {
int character_index = 0;
while (true) {
char current_character = my_string[character_index];
uncompressed_data.push_back(current_character);
if (current_character == '') {
break;
}
character_index++;
}
}
// https://stackoverflow.com/a/27173017/3764804
void print_bytes(std::ostream &stream, const unsigned char *data, size_t data_length, bool format = true) {
stream << std::setfill('0');
for (size_t data_index = 0; data_index < data_length; ++data_index) {
stream << std::hex << std::setw(2) << (int) data[data_index];
if (format) {
stream << (((data_index + 1) % 16 == 0) ? "\n" : " ");
}
}
stream << std::endl;
}
void test_compression() {
std::vector<char> uncompressed(0);
auto *my_string = (char *) "Hello, world!";
add_string_to_vector(uncompressed, my_string);
std::vector<char> compressed(0);
int compression_result = compress_vector(uncompressed, compressed);
assert(compression_result == F_OK);
std::vector<char> decompressed(0);
int decompression_result = decompress_vector(compressed, decompressed);
assert(decompression_result == F_OK);
printf("Uncompressed: %s\n", uncompressed.data());
printf("Compressed: ");
std::ostream &standard_output = std::cout;
print_bytes(standard_output, (const unsigned char *) compressed.data(), compressed.size(), false);
printf("Decompressed: %s\n", decompressed.data());
}
Dans votre main.cpp
appelez simplement:
int main(int argc, char *argv[]) {
test_compression();
return EXIT_SUCCESS;
}
La sortie produit:
Uncompressed: Hello, world!
Compressed: 78daf348cdc9c9d75128cf2fca495164000024e8048a
Decompressed: Hello, world!