
We always store CMYK data as YCCK, for two reasons: 1. If we ever want to do subsampling, then doing 2111 or 2112 makes sense with YCCK, while it doesn't make sense if we store CMYK directly. 2. It forces us to write a color transform header. With a color transform header, everyone agrees that the CMYK channels should be stored inverted, while without it behavior between decoders is inconsistent. (We could write an explicit color transform header for CMYK too though, but with YCCK it's harder to forget since the output will look wrong everywhere without it.) initialize_mcu() grows a full CMYKBitmap override. Some of the macroblock traversal could probably shared with some kind of for_all_macroblocks() type function in the future, but the color conversion math is different enough that this should be a separate function. Other than that, we pass around a mode parameter and make a few fuctions write 4 instead of 3 channels, and that's it. We use the luminance quantization and huffman tables for the K channel.
30 lines
566 B
C++
30 lines
566 B
C++
/*
|
|
* Copyright (c) 2023, Lucas Chollet <lucas.chollet@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Error.h>
|
|
#include <LibGfx/Forward.h>
|
|
|
|
namespace Gfx {
|
|
|
|
struct JPEGEncoderOptions {
|
|
Optional<ReadonlyBytes> icc_data;
|
|
u8 quality { 75 };
|
|
};
|
|
|
|
class JPEGWriter {
|
|
public:
|
|
using Options = JPEGEncoderOptions;
|
|
|
|
static ErrorOr<void> encode(Stream&, Bitmap const&, Options const& = {});
|
|
static ErrorOr<void> encode(Stream&, CMYKBitmap const&, Options const& = {});
|
|
|
|
private:
|
|
JPEGWriter() = delete;
|
|
};
|
|
|
|
}
|