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.

32
demandé sur Richard Knop 2010-12-27 15:20:13

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);
}
32
répondu Jonas Gulle 2010-12-27 12:55:38

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.
*/
39
répondu Huiwei 2012-04-08 14:26:44

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:

  1. remplir next_in avec le prochain bloc de données que vous voulez compresser
  2. set avail_in au nombre d'octets disponibles en next_in
  3. 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
  4. set avail_out au nombre d'octets disponibles en next_out
  5. appel deflate
  6. 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)
  7. 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.

10
répondu kichik 2010-12-27 12:54:25

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.

3
répondu Yippie-Ki-Yay 2010-12-27 12:30:57

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!
0
répondu BullyWiiPlaza 2018-08-05 17:27:37