2 Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
22 #include "dcpomatic_assert.h"
23 #include "exceptions.h"
30 using std::shared_ptr;
33 struct destination_mgr
35 jpeg_destination_mgr pub;
36 std::vector<uint8_t>* data;
41 init_destination (j_compress_ptr)
47 /* Empty the output buffer (i.e. make more space for data); we'll make
48 * the output buffer bigger instead.
51 empty_output_buffer (j_compress_ptr state)
53 auto dest = reinterpret_cast<destination_mgr*> (state->dest);
55 auto const old_size = dest->data->size();
56 dest->data->resize (old_size * 2);
58 dest->pub.next_output_byte = dest->data->data() + old_size;
59 dest->pub.free_in_buffer = old_size;
66 term_destination (j_compress_ptr state)
68 auto dest = reinterpret_cast<destination_mgr*> (state->dest);
70 dest->data->resize (dest->data->size() - dest->pub.free_in_buffer);
75 error_exit (j_common_ptr)
77 throw EncodeError (N_("JPEG encoding error"));
82 image_as_jpeg (shared_ptr<const Image> image, int quality)
84 if (image->pixel_format() != AV_PIX_FMT_RGB24) {
86 Image::ensure_alignment(image, Image::Alignment::PADDED)->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false),
91 struct jpeg_compress_struct compress;
92 struct jpeg_error_mgr error;
94 compress.err = jpeg_std_error (&error);
95 error.error_exit = error_exit;
96 jpeg_create_compress (&compress);
98 auto mgr = new destination_mgr;
99 compress.dest = reinterpret_cast<jpeg_destination_mgr*>(mgr);
101 mgr->pub.init_destination = init_destination;
102 mgr->pub.empty_output_buffer = empty_output_buffer;
103 mgr->pub.term_destination = term_destination;
105 std::vector<uint8_t> data(4096);
107 mgr->pub.next_output_byte = data.data();
108 mgr->pub.free_in_buffer = data.size();
110 compress.image_width = image->size().width;
111 compress.image_height = image->size().height;
112 compress.input_components = 3;
113 compress.in_color_space = JCS_RGB;
115 jpeg_set_defaults (&compress);
116 jpeg_set_quality (&compress, quality, TRUE);
118 jpeg_start_compress (&compress, TRUE);
121 auto const source_data = image->data()[0];
122 auto const source_stride = image->stride()[0];
123 for (auto y = 0U; y < compress.image_height; ++y) {
124 row[0] = source_data + y * source_stride;
125 jpeg_write_scanlines (&compress, row, 1);
128 jpeg_finish_compress (&compress);
130 jpeg_destroy_compress (&compress);
132 return dcp::ArrayData (data.data(), data.size());