libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

destination_manager.cc (5412B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #include <string.h>
      7 
      8 #include "lib/jpegli/encode.h"
      9 #include "lib/jpegli/error.h"
     10 #include "lib/jpegli/memory_manager.h"
     11 
     12 namespace jpegli {
     13 
     14 constexpr size_t kDestBufferSize = 64 << 10;
     15 
     16 struct StdioDestinationManager {
     17   jpeg_destination_mgr pub;
     18   FILE* f;
     19   uint8_t* buffer;
     20 
     21   static void init_destination(j_compress_ptr cinfo) {
     22     auto* dest = reinterpret_cast<StdioDestinationManager*>(cinfo->dest);
     23     dest->pub.next_output_byte = dest->buffer;
     24     dest->pub.free_in_buffer = kDestBufferSize;
     25   }
     26 
     27   static boolean empty_output_buffer(j_compress_ptr cinfo) {
     28     auto* dest = reinterpret_cast<StdioDestinationManager*>(cinfo->dest);
     29     if (fwrite(dest->buffer, 1, kDestBufferSize, dest->f) != kDestBufferSize) {
     30       JPEGLI_ERROR("Failed to write to output stream.");
     31     }
     32     dest->pub.next_output_byte = dest->buffer;
     33     dest->pub.free_in_buffer = kDestBufferSize;
     34     return TRUE;
     35   }
     36 
     37   static void term_destination(j_compress_ptr cinfo) {
     38     auto* dest = reinterpret_cast<StdioDestinationManager*>(cinfo->dest);
     39     size_t bytes_left = kDestBufferSize - dest->pub.free_in_buffer;
     40     if (bytes_left &&
     41         fwrite(dest->buffer, 1, bytes_left, dest->f) != bytes_left) {
     42       JPEGLI_ERROR("Failed to write to output stream.");
     43     }
     44     fflush(dest->f);
     45     if (ferror(dest->f)) {
     46       JPEGLI_ERROR("Failed to write to output stream.");
     47     }
     48   }
     49 };
     50 
     51 struct MemoryDestinationManager {
     52   jpeg_destination_mgr pub;
     53   // Output buffer supplied by the application
     54   uint8_t** output;
     55   unsigned long* output_size;
     56   // Output buffer allocated by us.
     57   uint8_t* temp_buffer;
     58   // Current output buffer (either application supplied or allocated by us).
     59   uint8_t* current_buffer;
     60   size_t buffer_size;
     61 
     62   static void init_destination(j_compress_ptr cinfo) {}
     63 
     64   static boolean empty_output_buffer(j_compress_ptr cinfo) {
     65     auto* dest = reinterpret_cast<MemoryDestinationManager*>(cinfo->dest);
     66     uint8_t* next_buffer =
     67         reinterpret_cast<uint8_t*>(malloc(dest->buffer_size * 2));
     68     memcpy(next_buffer, dest->current_buffer, dest->buffer_size);
     69     if (dest->temp_buffer != nullptr) {
     70       free(dest->temp_buffer);
     71     }
     72     dest->temp_buffer = next_buffer;
     73     dest->current_buffer = next_buffer;
     74     *dest->output = next_buffer;
     75     *dest->output_size = dest->buffer_size;
     76     dest->pub.next_output_byte = next_buffer + dest->buffer_size;
     77     dest->pub.free_in_buffer = dest->buffer_size;
     78     dest->buffer_size *= 2;
     79     return TRUE;
     80   }
     81 
     82   static void term_destination(j_compress_ptr cinfo) {
     83     auto* dest = reinterpret_cast<MemoryDestinationManager*>(cinfo->dest);
     84     *dest->output_size = dest->buffer_size - dest->pub.free_in_buffer;
     85   }
     86 };
     87 
     88 }  // namespace jpegli
     89 
     90 void jpegli_stdio_dest(j_compress_ptr cinfo, FILE* outfile) {
     91   if (outfile == nullptr) {
     92     JPEGLI_ERROR("jpegli_stdio_dest: Invalid destination.");
     93   }
     94   if (cinfo->dest && cinfo->dest->init_destination !=
     95                          jpegli::StdioDestinationManager::init_destination) {
     96     JPEGLI_ERROR("jpegli_stdio_dest: a different dest manager was already set");
     97   }
     98   if (!cinfo->dest) {
     99     cinfo->dest = reinterpret_cast<jpeg_destination_mgr*>(
    100         jpegli::Allocate<jpegli::StdioDestinationManager>(cinfo, 1));
    101   }
    102   auto* dest = reinterpret_cast<jpegli::StdioDestinationManager*>(cinfo->dest);
    103   dest->f = outfile;
    104   dest->buffer = jpegli::Allocate<uint8_t>(cinfo, jpegli::kDestBufferSize);
    105   dest->pub.next_output_byte = dest->buffer;
    106   dest->pub.free_in_buffer = jpegli::kDestBufferSize;
    107   dest->pub.init_destination =
    108       jpegli::StdioDestinationManager::init_destination;
    109   dest->pub.empty_output_buffer =
    110       jpegli::StdioDestinationManager::empty_output_buffer;
    111   dest->pub.term_destination =
    112       jpegli::StdioDestinationManager::term_destination;
    113 }
    114 
    115 void jpegli_mem_dest(j_compress_ptr cinfo, unsigned char** outbuffer,
    116                      unsigned long* outsize) {
    117   if (outbuffer == nullptr || outsize == nullptr) {
    118     JPEGLI_ERROR("jpegli_mem_dest: Invalid destination.");
    119   }
    120   if (cinfo->dest && cinfo->dest->init_destination !=
    121                          jpegli::MemoryDestinationManager::init_destination) {
    122     JPEGLI_ERROR("jpegli_mem_dest: a different dest manager was already set");
    123   }
    124   if (!cinfo->dest) {
    125     auto* dest = jpegli::Allocate<jpegli::MemoryDestinationManager>(cinfo, 1);
    126     dest->temp_buffer = nullptr;
    127     cinfo->dest = reinterpret_cast<jpeg_destination_mgr*>(dest);
    128   }
    129   auto* dest = reinterpret_cast<jpegli::MemoryDestinationManager*>(cinfo->dest);
    130   dest->pub.init_destination =
    131       jpegli::MemoryDestinationManager::init_destination;
    132   dest->pub.empty_output_buffer =
    133       jpegli::MemoryDestinationManager::empty_output_buffer;
    134   dest->pub.term_destination =
    135       jpegli::MemoryDestinationManager::term_destination;
    136   dest->output = outbuffer;
    137   dest->output_size = outsize;
    138   if (*outbuffer == nullptr || *outsize == 0) {
    139     dest->temp_buffer =
    140         reinterpret_cast<uint8_t*>(malloc(jpegli::kDestBufferSize));
    141     *outbuffer = dest->temp_buffer;
    142     *outsize = jpegli::kDestBufferSize;
    143   }
    144   dest->current_buffer = *outbuffer;
    145   dest->buffer_size = *outsize;
    146   dest->pub.next_output_byte = dest->current_buffer;
    147   dest->pub.free_in_buffer = dest->buffer_size;
    148 }