blob: da220ba921ce1ed8b5e1dd175ad16e9858d21941 [file]
/* -*- C++ -*-
* Copyright 2019-2025 LibRaw LLC (info@libraw.org)
*
LibRaw is free software; you can redistribute it and/or modify
it under the terms of the one of two licenses as you choose:
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
(See file LICENSE.LGPL provided in LibRaw distribution archive for details).
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
(See file LICENSE.CDDL provided in LibRaw distribution archive for details).
*/
#include "third_party/libraw/internal/libraw_cxx_defs.h"
libraw_processed_image_t *LibRaw::dcraw_make_mem_thumb(int *errcode)
{
if (!T.thumb)
{
if (!ID.toffset && !(imgdata.thumbnail.tlength > 0 &&
load_raw == &LibRaw::broadcom_load_raw) // RPi
)
{
if (errcode)
*errcode = LIBRAW_NO_THUMBNAIL;
}
else
{
if (errcode)
*errcode = LIBRAW_OUT_OF_ORDER_CALL;
}
return NULL;
}
if (T.tlength < 64u)
{
if (errcode)
*errcode = EINVAL;
return NULL;
}
if (INT64(T.tlength) > 1024ULL * 1024ULL * LIBRAW_MAX_THUMBNAIL_MB)
{
if (errcode)
*errcode = LIBRAW_TOO_BIG;
return NULL;
}
if (T.tformat == LIBRAW_THUMBNAIL_BITMAP)
{
libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(
sizeof(libraw_processed_image_t) + T.tlength);
if (!ret)
{
if (errcode)
*errcode = ENOMEM;
return NULL;
}
memset(ret, 0, sizeof(libraw_processed_image_t));
ret->type = LIBRAW_IMAGE_BITMAP;
ret->height = T.theight;
ret->width = T.twidth;
if (T.tcolors > 0 && T.tcolors < 4)
ret->colors = T.tcolors;
else
ret->colors = 3; // defaults
ret->bits = 8;
ret->data_size = T.tlength;
memmove(ret->data, T.thumb, T.tlength);
if (errcode)
*errcode = 0;
return ret;
}
else if (T.tformat == LIBRAW_THUMBNAIL_JPEG)
{
ushort exif[5];
int mk_exif = 0;
if (strcmp(T.thumb + 6, "Exif"))
mk_exif = 1;
int dsize = T.tlength + mk_exif * (sizeof(exif) + sizeof(tiff_hdr));
libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(
sizeof(libraw_processed_image_t) + dsize);
if (!ret)
{
if (errcode)
*errcode = ENOMEM;
return NULL;
}
memset(ret, 0, sizeof(libraw_processed_image_t));
ret->type = LIBRAW_IMAGE_JPEG;
ret->data_size = dsize;
ret->data[0] = 0xff;
ret->data[1] = 0xd8;
if (mk_exif)
{
struct tiff_hdr th;
memcpy(exif, "\xff\xe1 Exif\0\0", 10);
exif[1] = htons(8 + sizeof th);
memmove(ret->data + 2, exif, sizeof(exif));
tiff_head(&th, 0);
memmove(ret->data + (2 + sizeof(exif)), &th, sizeof(th));
memmove(ret->data + (2 + sizeof(exif) + sizeof(th)), T.thumb + 2,
T.tlength - 2);
}
else
{
memmove(ret->data + 2, T.thumb + 2, T.tlength - 2);
}
if (errcode)
*errcode = 0;
return ret;
}
else if (T.tformat == LIBRAW_THUMBNAIL_H265 || T.tformat == LIBRAW_THUMBNAIL_JPEGXL)
{
int dsize = T.tlength;
libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(sizeof(libraw_processed_image_t) + dsize);
if (!ret)
{
if (errcode)
*errcode = ENOMEM;
return NULL;
}
memset(ret, 0, sizeof(libraw_processed_image_t));
ret->type = T.tformat == LIBRAW_THUMBNAIL_H265 ? LIBRAW_IMAGE_H265 : LIBRAW_IMAGE_JPEGXL;
ret->data_size = dsize;
memmove(ret->data, T.thumb, dsize);
if (errcode)
*errcode = 0;
return ret;
}
else
{
if (errcode)
*errcode = LIBRAW_UNSUPPORTED_THUMBNAIL;
return NULL;
}
}
// jlb
// macros for copying pixels to either BGR or RGB formats
#define FORBGR for (c = P1.colors - 1; c >= 0; c--)
#define FORRGB for (c = 0; c < P1.colors; c++)
void LibRaw::get_mem_image_format(int *width, int *height, int *colors,
int *bps) const
{
*width = S.width;
*height = S.height;
if (imgdata.progress_flags < LIBRAW_PROGRESS_FUJI_ROTATE)
{
if (O.use_fuji_rotate)
{
if (IO.fuji_width)
{
int fuji_width = (IO.fuji_width - 1 + IO.shrink) >> IO.shrink;
*width = (ushort)(fuji_width / sqrt(0.5));
*height = (ushort)((*height - fuji_width) / sqrt(0.5));
}
else
{
if (S.pixel_aspect < 0.995)
*height = (ushort)(*height / S.pixel_aspect + 0.5);
if (S.pixel_aspect > 1.005)
*width = (ushort)(*width * S.pixel_aspect + 0.5);
}
}
}
if (S.flip & 4)
{
std::swap(*width, *height);
}
*colors = P1.colors;
*bps = O.output_bps;
}
int LibRaw::copy_mem_image(void *scan0, int stride, int bgr)
{
// the image memory pointed to by scan0 is assumed to be in the format
// returned by get_mem_image_format
if ((imgdata.progress_flags & LIBRAW_PROGRESS_THUMB_MASK) <
LIBRAW_PROGRESS_PRE_INTERPOLATE)
return LIBRAW_OUT_OF_ORDER_CALL;
if (libraw_internal_data.output_data.histogram)
{
int perc, val, total, t_white = 0x2000, c;
perc = int(S.width * S.height * O.auto_bright_thr);
if (IO.fuji_width)
perc /= 2;
if (!((O.highlight & ~2) || O.no_auto_bright))
for (t_white = c = 0; c < P1.colors; c++)
{
for (val = 0x2000, total = 0; --val > 32;)
if ((total += libraw_internal_data.output_data.histogram[c][val]) >
perc)
break;
if (t_white < val)
t_white = val;
}
gamma_curve(O.gamm[0], O.gamm[1], 2, int((t_white << 3) / O.bright));
}
int s_iheight = S.iheight;
int s_iwidth = S.iwidth;
int s_width = S.width;
int s_hwight = S.height;
S.iheight = S.height;
S.iwidth = S.width;
if (S.flip & 4)
SWAP(S.height, S.width);
uchar *ppm;
ushort *ppm2;
int c, row, col, soff, rstep, cstep;
soff = flip_index(0, 0);
cstep = flip_index(0, 1) - soff;
rstep = flip_index(1, 0) - flip_index(0, S.width);
for (row = 0; row < S.height; row++, soff += rstep)
{
uchar *bufp = ((uchar *)scan0) + row * stride;
ppm2 = (ushort *)(ppm = bufp);
// keep trivial decisions in the outer loop for speed
if (bgr)
{
if (O.output_bps == 8)
{
for (col = 0; col < S.width; col++, soff += cstep)
FORBGR *ppm++ = imgdata.color.curve[imgdata.image[soff][c]] >> 8;
}
else
{
for (col = 0; col < S.width; col++, soff += cstep)
FORBGR *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]];
}
}
else
{
if (O.output_bps == 8)
{
for (col = 0; col < S.width; col++, soff += cstep)
FORRGB *ppm++ = imgdata.color.curve[imgdata.image[soff][c]] >> 8;
}
else
{
for (col = 0; col < S.width; col++, soff += cstep)
FORRGB *ppm2++ = imgdata.color.curve[imgdata.image[soff][c]];
}
}
// bufp += stride; // go to the next line
}
S.iheight = s_iheight;
S.iwidth = s_iwidth;
S.width = s_width;
S.height = s_hwight;
return 0;
}
#undef FORBGR
#undef FORRGB
libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *errcode)
{
int width, height, colors, bps;
get_mem_image_format(&width, &height, &colors, &bps);
int stride = width * (bps / 8) * colors;
unsigned ds = height * stride;
libraw_processed_image_t *ret = (libraw_processed_image_t *)::malloc(
sizeof(libraw_processed_image_t) + ds);
if (!ret)
{
if (errcode)
*errcode = ENOMEM;
return NULL;
}
memset(ret, 0, sizeof(libraw_processed_image_t));
// metadata init
ret->type = LIBRAW_IMAGE_BITMAP;
ret->height = height;
ret->width = width;
ret->colors = colors;
ret->bits = bps;
ret->data_size = ds;
copy_mem_image(ret->data, stride, 0);
return ret;
}
void LibRaw::dcraw_clear_mem(libraw_processed_image_t *p)
{
if (p)
::free(p);
}