mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
204 lines
No EOL
5.6 KiB
C++
204 lines
No EOL
5.6 KiB
C++
#include "image.h"
|
|
#include <cstring>
|
|
#include "logger.h"
|
|
#include "libs/openjp2/openjpeg.h"
|
|
#include <filesystem>
|
|
|
|
#define INVERT_ENDIAN_16(x) ((x >> 8) | (x << 8))
|
|
|
|
namespace image
|
|
{
|
|
template <typename T>
|
|
void Image<T>::save_j2k(std::string file)
|
|
{
|
|
if (data_size == 0 || d_height == 0) // Make sure we aren't just gonna crash
|
|
{
|
|
logger->trace("Tried to save empty J2K!");
|
|
return;
|
|
}
|
|
|
|
opj_cparameters_t parameters;
|
|
opj_image_t *image;
|
|
OPJ_CODEC_FORMAT codec_format = OPJ_CODEC_J2K;
|
|
|
|
opj_set_default_encoder_parameters(¶meters);
|
|
parameters.numresolution = 5;
|
|
|
|
{
|
|
opj_image_cmptparm_t comp_params[4];
|
|
memset(comp_params, 0, 4 * sizeof(opj_image_cmptparm_t));
|
|
|
|
for (int i = 0; i < d_channels; i++)
|
|
{
|
|
comp_params[i].prec = d_depth;
|
|
// comp_params[i].bpp = 8;
|
|
comp_params[i].sgnd = 0;
|
|
comp_params[i].dx = parameters.subsampling_dx;
|
|
comp_params[i].dy = parameters.subsampling_dy;
|
|
comp_params[i].w = d_width;
|
|
comp_params[i].h = d_height;
|
|
}
|
|
|
|
image = opj_image_create(d_channels, comp_params, d_channels == 1 ? OPJ_CLRSPC_GRAY : OPJ_CLRSPC_SRGB);
|
|
|
|
if (image == NULL)
|
|
{
|
|
logger->error("JP2 image is null? C");
|
|
}
|
|
else
|
|
{
|
|
image->x0 = 0;
|
|
image->y0 = 0;
|
|
image->x1 = (d_width - 1) * parameters.subsampling_dx + 1;
|
|
image->y1 = (d_height - 1) * parameters.subsampling_dy + 1;
|
|
|
|
// Put into image
|
|
for (int c = 0; c < d_channels; c++)
|
|
for (size_t i = 0; i < d_width * d_height; i++)
|
|
image->comps[c].data[i] = channel(c)[i];
|
|
}
|
|
}
|
|
|
|
if (image == NULL)
|
|
{
|
|
logger->error("JP2 image is null? F");
|
|
return;
|
|
}
|
|
|
|
opj_stream_t *stream;
|
|
opj_codec_t *codec;
|
|
|
|
stream = NULL;
|
|
parameters.tcp_mct = image->numcomps == 1 ? 0 : 1;
|
|
|
|
codec = opj_create_compress(codec_format);
|
|
|
|
if (codec == NULL)
|
|
goto abort;
|
|
|
|
opj_setup_encoder(codec, ¶meters, image);
|
|
|
|
stream = opj_stream_create_default_file_stream(file.c_str(), false);
|
|
|
|
if (stream == NULL)
|
|
{
|
|
logger->error("NULL STREAM");
|
|
goto abort;
|
|
}
|
|
|
|
if (!opj_start_compress(codec, image, stream))
|
|
{
|
|
logger->error("START COMPRESS ERROR");
|
|
goto abort;
|
|
}
|
|
|
|
if (!opj_encode(codec, stream))
|
|
{
|
|
logger->error("ENCODE ERROR");
|
|
goto abort;
|
|
}
|
|
|
|
opj_end_compress(codec, stream);
|
|
|
|
abort:
|
|
|
|
if (stream)
|
|
opj_stream_destroy(stream);
|
|
|
|
if (codec)
|
|
opj_destroy_codec(codec);
|
|
|
|
opj_image_destroy(image);
|
|
|
|
if (parameters.cp_comment)
|
|
free(parameters.cp_comment);
|
|
|
|
return;
|
|
}
|
|
|
|
template <typename T>
|
|
void Image<T>::load_j2k(std::string file)
|
|
{
|
|
if (!std::filesystem::exists(file))
|
|
return;
|
|
|
|
// Init decoder parameters
|
|
opj_dparameters_t core;
|
|
memset(&core, 0, sizeof(opj_dparameters_t));
|
|
opj_set_default_decoder_parameters(&core);
|
|
|
|
// Setup image, stream and codec
|
|
opj_image_t *image = NULL;
|
|
opj_stream_t *l_stream = opj_stream_create_file_stream(file.c_str(), OPJ_J2K_STREAM_CHUNK_SIZE, true);
|
|
opj_codec_t *l_codec = opj_create_decompress(OPJ_CODEC_J2K);
|
|
|
|
// Check we could open the stream
|
|
if (!l_stream)
|
|
{
|
|
opj_destroy_codec(l_codec);
|
|
return;
|
|
}
|
|
|
|
// Setup decoder
|
|
if (!opj_setup_decoder(l_codec, &core))
|
|
{
|
|
opj_stream_destroy(l_stream);
|
|
opj_destroy_codec(l_codec);
|
|
return;
|
|
}
|
|
|
|
// Read header
|
|
if (!opj_read_header(l_stream, l_codec, &image))
|
|
{
|
|
opj_stream_destroy(l_stream);
|
|
opj_destroy_codec(l_codec);
|
|
opj_image_destroy(image);
|
|
return;
|
|
}
|
|
|
|
// Decode image
|
|
if (!(opj_decode(l_codec, l_stream, image) &&
|
|
opj_end_decompress(l_codec, l_stream)))
|
|
{
|
|
opj_destroy_codec(l_codec);
|
|
opj_stream_destroy(l_stream);
|
|
opj_image_destroy(image);
|
|
return;
|
|
}
|
|
|
|
// Parse into image
|
|
int depth = image->comps[0].prec;
|
|
init(image->x1, image->y1, image->numcomps);
|
|
|
|
if (d_depth == 16)
|
|
{
|
|
for (int c = 0; c < d_channels; c++)
|
|
for (int i = 0; i < int(image->x1 * image->y1); i++)
|
|
channel(c)[i] = image->comps[c].data[i] << (16 - depth);
|
|
}
|
|
else if (d_depth == 8)
|
|
{
|
|
if (depth >= 8)
|
|
{
|
|
for (int c = 0; c < d_channels; c++)
|
|
for (int i = 0; i < int(image->x1 * image->y1); i++)
|
|
channel(c)[i] = image->comps[c].data[i] >> (depth - 8);
|
|
}
|
|
else
|
|
{
|
|
for (int c = 0; c < d_channels; c++)
|
|
for (int i = 0; i < int(image->x1 * image->y1); i++)
|
|
channel(c)[i] = image->comps[c].data[i] << (8 - depth);
|
|
}
|
|
}
|
|
|
|
// Free everything up
|
|
opj_destroy_codec(l_codec);
|
|
opj_stream_destroy(l_stream);
|
|
opj_image_destroy(image);
|
|
}
|
|
|
|
// Generate Images for uint16_t and uint8_t
|
|
template class Image<uint8_t>;
|
|
template class Image<uint16_t>;
|
|
} |