Files
Jungfraujoch/preview/JFJochJPEG.cpp
T
leonarski_f 84228bf8be
Build Packages / Create release (push) Successful in 24s
Build Packages / build:viewer:macos-arm64:nocuda (push) Successful in 3m29s
Build Packages / build:rugnux:macos-arm64:nocuda (push) Successful in 2m43s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 8m27s
Build Packages / build:rugnux:linux-x86_64:cuda (push) Successful in 9m53s
Build Packages / build:viewer:linux-x86_64:nocuda (push) Successful in 9m58s
Build Packages / build:viewer:linux-x86_64:cuda (push) Successful in 11m22s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 13m39s
Build Packages / build:viewer:windows-x86_64:nocuda (push) Successful in 18m37s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 16m32s
Build Packages / build:viewer:windows-x86_64:cuda (push) Successful in 24m11s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 25m30s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 19m3s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 20m23s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 19m41s
Build Packages / Generate python client (push) Successful in 50s
Build Packages / Build documentation (push) Successful in 1m16s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 21m0s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 18m38s
Build Packages / build:rugnux:windows-x86_64:cuda (push) Successful in 14m33s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 17m55s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 20m50s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 18m38s
Build Packages / Unit tests (push) Successful in 1h46m14s
v1.0.0-rc.173 (#83)
* jfjoch_broker: Optional per-dataset authentication - statistics, images and plots can require a bearer token, which jfjoch_viewer supports.
* jfjoch_viewer: Dark mode and a theme-matched colour scheme, a magnifier panel, and simpler contrast and background controls.
* Rugnux: Multiple performance improvements on GPU and CPU (CPU-only processing up to 40% faster, faster image decoding on ARM), with unchanged results.
* Rugnux: `--model` rigid-body refinement runs on the GPU, and the model-validation check is faster and more reliable.
* Rugnux: Improved scaling and merging - error model, outlier rejection, absorption correction and French-Wilson amplitudes now agree more closely with XDS and ctruncate.
* Rugnux: Improved integration - radial background on powder and ice rings, crowded rotation data keep their reflections, and CPU-only builds integrate large unit cells as GPU builds do.
* Rugnux: More robust detector geometry - measured beam centre, X-ray bandwidth and goniometer rate, and geometry refinement accepted only on significant evidence.
* Rugnux: Merged files are written in the standard setting, or in the setting of a reference MTZ, structure-factor mmCIF or model, with its free-R flags.
* Rugnux: Richer report - ice and powder rings, further lattices, superstructure candidates and mosaicity, with warnings worded as prompts to check.
* Rugnux: Clear error messages when a data set needs more GPU or host memory than is available.

Reviewed-on: #83
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
2026-09-29 15:57:32 +02:00

89 lines
2.8 KiB
C++

// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include <vector>
#include <csetjmp>
#include <cstdio>
#include <cstdint>
#include <cmath>
#include <new>
#include <jpeglib.h>
#include <jerror.h>
#include "../common/JFJochException.h"
#include "../common/CompressedImage.h"
#include "JFJochJPEG.h"
namespace {
// libjpeg's own error handler prints its message and calls exit(), from whichever thread was
// encoding - out of memory included. This one jumps back to WriteJPEGToMem, which throws instead.
struct JPEGErrorManager {
jpeg_error_mgr mgr;
std::jmp_buf jump;
};
void JPEGErrorExit(j_common_ptr cinfo) {
std::longjmp(reinterpret_cast<JPEGErrorManager *>(cinfo->err)->jump, 1);
}
}
std::string WriteJPEGToMem(const CompressedImage& image, int quality) {
unsigned char *buf = nullptr;
unsigned long buf_size = 0;
if (image.GetMode() != CompressedImageMode::RGB)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Only RGB images allowed for JPEG saving");
std::vector<uint8_t> buffer;
image.GetUncompressed(buffer);
struct jpeg_compress_struct cinfo;
JPEGErrorManager jerr;
cinfo.err = jpeg_std_error(&jerr.mgr);
jerr.mgr.error_exit = JPEGErrorExit;
if (setjmp(jerr.jump)) {
const bool out_of_memory = (jerr.mgr.msg_code == JERR_OUT_OF_MEMORY);
char message[JMSG_LENGTH_MAX];
jerr.mgr.format_message(reinterpret_cast<j_common_ptr>(&cinfo), message);
jpeg_destroy_compress(&cinfo);
free(buf);
if (out_of_memory)
throw std::bad_alloc();
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
std::string("JPEG encoding failed: ") + message);
}
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, &buf, &buf_size);
cinfo.image_width = image.GetWidth();
cinfo.image_height = image.GetHeight();
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
/*set the quality [0..100] */
jpeg_set_quality (&cinfo, quality, true);
jpeg_simple_progression(&cinfo);
jpeg_start_compress(&cinfo, true);
JSAMPROW row_pointer; /* pointer to a single row */
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer = (JSAMPROW) (buffer.data() + cinfo.next_scanline*(sizeof(char)*3)*image.GetWidth());
jpeg_write_scanlines(&cinfo, &row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
std::string ret;
if (buf_size > 0)
ret = std::string((char *)buf, buf_size);
free(buf);
return ret;
}