merge with Dev
This commit is contained in:
commit
ae7d7a911b
3223
rtengine/cJSON.c
3223
rtengine/cJSON.c
File diff suppressed because it is too large
Load Diff
268
rtengine/cJSON.h
268
rtengine/cJSON.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -28,113 +28,247 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 5
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_False 0
|
||||
#define cJSON_True 1
|
||||
#define cJSON_NULL 2
|
||||
#define cJSON_Number 3
|
||||
#define cJSON_String 4
|
||||
#define cJSON_Array 5
|
||||
#define cJSON_Object 6
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next, *prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
int type; /* The type of the item, as above. */
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
char *valuestring; /* The item's string, if type==cJSON_String */
|
||||
int valueint; /* The item's number, if type==cJSON_Number */
|
||||
double valuedouble; /* The item's number, if type==cJSON_Number */
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks {
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type __stdcall
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall
|
||||
#endif
|
||||
#else /* !WIN32 */
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
|
||||
extern char *cJSON_PrintUnformatted(cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array, int item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object, const char *string);
|
||||
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
extern const char *cJSON_GetErrorPtr(void);
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check if the item is a string and return its valuestring */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
extern cJSON *cJSON_CreateBool(int b);
|
||||
extern cJSON *cJSON_CreateNumber(double num);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray(void);
|
||||
extern cJSON *cJSON_CreateObject(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/arrray that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
extern cJSON *cJSON_CreateIntArray(const int *numbers, int count);
|
||||
extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
extern cJSON *cJSON_CreateStringArray(const char **strings, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
extern void cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
extern void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
extern cJSON *cJSON_Duplicate(cJSON *item, int recurse);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated);
|
||||
|
||||
extern void cJSON_Minify(char *json);
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Macros for creating things quickly. */
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
|
||||
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
|
||||
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -736,7 +736,7 @@ void Color::rgb2hsv(float r, float g, float b, float &h, float &s, float &v)
|
||||
if (del_Max < 0.00001 && del_Max > -0.00001) { // no fabs, slow!
|
||||
s = 0.f;
|
||||
} else {
|
||||
s = del_Max / var_Max;
|
||||
s = del_Max / (var_Max == 0.0 ? 1.0 : var_Max);
|
||||
|
||||
if (var_R == var_Max) {
|
||||
h = (var_G - var_B) / del_Max;
|
||||
@ -1766,15 +1766,41 @@ void Color::Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat &
|
||||
}
|
||||
#endif // __SSE2__
|
||||
|
||||
inline float Color::computeXYZ2Lab(float f)
|
||||
{
|
||||
if (f < 0.f) {
|
||||
return 327.68 * ((kappa * f / MAXVALF + 16.0) / 116.0);
|
||||
} else if (f > 65535.f) {
|
||||
return (327.68f * xcbrtf(f / MAXVALF));
|
||||
} else {
|
||||
return cachef[f];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline float Color::computeXYZ2LabY(float f)
|
||||
{
|
||||
if (f < 0.f) {
|
||||
return 327.68 * (kappa * f / MAXVALF);
|
||||
} else if (f > 65535.f) {
|
||||
return 327.68f * (116.f * xcbrtf(f / MAXVALF) - 16.f);
|
||||
} else {
|
||||
return cachefy[f];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b, const float wp[3][3], int width)
|
||||
{
|
||||
|
||||
#ifdef __SSE2__
|
||||
vfloat minvalfv = F2V(0.f);
|
||||
vfloat maxvalfv = F2V(MAXVALF);
|
||||
vfloat c500v = F2V(500.f);
|
||||
vfloat c200v = F2V(200.f);
|
||||
#endif
|
||||
int i = 0;
|
||||
|
||||
#ifdef __SSE2__
|
||||
|
||||
for (; i < width - 3; i += 4) {
|
||||
@ -1786,18 +1812,18 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b,
|
||||
const vfloat zv = F2V(wp[2][0]) * rv + F2V(wp[2][1]) * gv + F2V(wp[2][2]) * bv;
|
||||
|
||||
vmask maxMask = vmaskf_gt(vmaxf(xv, vmaxf(yv, zv)), maxvalfv);
|
||||
|
||||
if (_mm_movemask_ps((vfloat)maxMask)) {
|
||||
vmask minMask = vmaskf_lt(vminf(xv, vminf(yv, zv)), minvalfv);
|
||||
if (_mm_movemask_ps((vfloat)maxMask) || _mm_movemask_ps((vfloat)minMask)) {
|
||||
// take slower code path for all 4 pixels if one of the values is > MAXVALF. Still faster than non SSE2 version
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
float x = xv[k];
|
||||
float y = yv[k];
|
||||
float z = zv[k];
|
||||
float fx = (x <= 65535.f ? cachef[x] : (327.68f * xcbrtf(x / MAXVALF)));
|
||||
float fy = (y <= 65535.f ? cachef[y] : (327.68f * xcbrtf(y / MAXVALF)));
|
||||
float fz = (z <= 65535.f ? cachef[z] : (327.68f * xcbrtf(z / MAXVALF)));
|
||||
float fx = computeXYZ2Lab(x);
|
||||
float fy = computeXYZ2Lab(y);
|
||||
float fz = computeXYZ2Lab(z);
|
||||
|
||||
L[i + k] = (y <= 65535.0f ? cachefy[y] : 327.68f * (116.f * xcbrtf(y / MAXVALF) - 16.f));
|
||||
L[i + k] = computeXYZ2LabY(y);
|
||||
a[i + k] = (500.f * (fx - fy));
|
||||
b[i + k] = (200.f * (fy - fz));
|
||||
}
|
||||
@ -1823,11 +1849,11 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b,
|
||||
float z = wp[2][0] * rv + wp[2][1] * gv + wp[2][2] * bv;
|
||||
float fx, fy, fz;
|
||||
|
||||
fx = (x <= 65535.0f ? cachef[x] : (327.68f * xcbrtf(x / MAXVALF)));
|
||||
fy = (y <= 65535.0f ? cachef[y] : (327.68f * xcbrtf(y / MAXVALF)));
|
||||
fz = (z <= 65535.0f ? cachef[z] : (327.68f * xcbrtf(z / MAXVALF)));
|
||||
fx = computeXYZ2Lab(x);
|
||||
fy = computeXYZ2Lab(y);
|
||||
fz = computeXYZ2Lab(z);
|
||||
|
||||
L[i] = (y <= 65535.0f ? cachefy[y] : 327.68f * (116.f * xcbrtf(y / MAXVALF) - 16.f));
|
||||
L[i] = computeXYZ2LabY(y);
|
||||
a[i] = 500.0f * (fx - fy);
|
||||
b[i] = 200.0f * (fy - fz);
|
||||
}
|
||||
@ -1841,11 +1867,11 @@ void Color::XYZ2Lab(float X, float Y, float Z, float &L, float &a, float &b)
|
||||
float y = Y;
|
||||
float fx, fy, fz;
|
||||
|
||||
fx = (x <= 65535.0f ? cachef[x] : (327.68f * xcbrtf(x / MAXVALF)));
|
||||
fy = (y <= 65535.0f ? cachef[y] : (327.68f * xcbrtf(y / MAXVALF)));
|
||||
fz = (z <= 65535.0f ? cachef[z] : (327.68f * xcbrtf(z / MAXVALF)));
|
||||
fx = computeXYZ2Lab(x);
|
||||
fy = computeXYZ2Lab(y);
|
||||
fz = computeXYZ2Lab(z);
|
||||
|
||||
L = (y <= 65535.0f ? cachefy[y] : 327.68f * (116.f * xcbrtf(y / MAXVALF) - 16.f));
|
||||
L = computeXYZ2LabY(y);
|
||||
a = (500.0f * (fx - fy));
|
||||
b = (200.0f * (fy - fz));
|
||||
}
|
||||
@ -1877,11 +1903,11 @@ void Color::Yuv2Lab(float Yin, float u, float v, float &L, float &a, float &b, c
|
||||
|
||||
gamutmap(X, Y, Z, wp);
|
||||
|
||||
float fx = (X <= 65535.0 ? cachef[X] : (327.68 * std::cbrt(X / MAXVALF)));
|
||||
float fy = (Y <= 65535.0 ? cachef[Y] : (327.68 * std::cbrt(Y / MAXVALF)));
|
||||
float fz = (Z <= 65535.0 ? cachef[Z] : (327.68 * std::cbrt(Z / MAXVALF)));
|
||||
float fx = computeXYZ2Lab(X);
|
||||
float fy = computeXYZ2Lab(Y);
|
||||
float fz = computeXYZ2Lab(Z);
|
||||
|
||||
L = (Y <= 65535.0f ? cachefy[Y] : 327.68f * (116.f * xcbrtf(Y / MAXVALF) - 16.f));
|
||||
L = computeXYZ2LabY(Y);
|
||||
a = (500.0 * (fx - fy));
|
||||
b = (200.0 * (fy - fz));
|
||||
}
|
||||
|
@ -97,6 +97,10 @@ private:
|
||||
#ifdef __SSE2__
|
||||
static vfloat hue2rgb(vfloat p, vfloat q, vfloat t);
|
||||
#endif
|
||||
|
||||
static float computeXYZ2Lab(float f);
|
||||
static float computeXYZ2LabY(float f);
|
||||
|
||||
public:
|
||||
|
||||
typedef enum Channel {
|
||||
|
@ -2471,6 +2471,14 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float
|
||||
const AdobeToneCurve& adobeTC = static_cast<const AdobeToneCurve&>((const ToneCurve&) * this);
|
||||
|
||||
for (size_t i = start; i < end; ++i) {
|
||||
const bool oog_r = OOG(rc[i]);
|
||||
const bool oog_g = OOG(gc[i]);
|
||||
const bool oog_b = OOG(bc[i]);
|
||||
|
||||
if (oog_r && oog_g && oog_b) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float r = CLIP(rc[i]);
|
||||
float g = CLIP(gc[i]);
|
||||
float b = CLIP(bc[i]);
|
||||
@ -2492,12 +2500,18 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float
|
||||
|
||||
if (ar >= 65535.f && ag >= 65535.f && ab >= 65535.f) {
|
||||
// clip fast path, will also avoid strange colours of clipped highlights
|
||||
rc[i] = gc[i] = bc[i] = 65535.f;
|
||||
//rc[i] = gc[i] = bc[i] = 65535.f;
|
||||
if (!oog_r) rc[i] = 65535.f;
|
||||
if (!oog_g) gc[i] = 65535.f;
|
||||
if (!oog_b) bc[i] = 65535.f;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ar <= 0.f && ag <= 0.f && ab <= 0.f) {
|
||||
rc[i] = gc[i] = bc[i] = 0;
|
||||
//rc[i] = gc[i] = bc[i] = 0;
|
||||
if (!oog_r) rc[i] = 0.f;
|
||||
if (!oog_g) gc[i] = 0.f;
|
||||
if (!oog_b) bc[i] = 0.f;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2537,10 +2551,9 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float
|
||||
g = newg;
|
||||
b = newb;
|
||||
}
|
||||
|
||||
rc[i] = r;
|
||||
gc[i] = g;
|
||||
bc[i] = b;
|
||||
if (!oog_r) rc[i] = r;
|
||||
if (!oog_g) gc[i] = g;
|
||||
if (!oog_b) bc[i] = b;
|
||||
|
||||
continue;
|
||||
}
|
||||
@ -2648,9 +2661,9 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float
|
||||
b = newb;
|
||||
}
|
||||
|
||||
rc[i] = r;
|
||||
gc[i] = g;
|
||||
bc[i] = b;
|
||||
if (!oog_r) rc[i] = r;
|
||||
if (!oog_g) gc[i] = g;
|
||||
if (!oog_b) bc[i] = b;
|
||||
|
||||
continue;
|
||||
}
|
||||
@ -2711,10 +2724,9 @@ void PerceptualToneCurve::BatchApply(const size_t start, const size_t end, float
|
||||
g = newg;
|
||||
b = newb;
|
||||
}
|
||||
|
||||
rc[i] = r;
|
||||
gc[i] = g;
|
||||
bc[i] = b;
|
||||
if (!oog_r) rc[i] = r;
|
||||
if (!oog_g) gc[i] = g;
|
||||
if (!oog_b) bc[i] = b;
|
||||
}
|
||||
}
|
||||
float PerceptualToneCurve::cf_range[2];
|
||||
|
@ -45,6 +45,32 @@ namespace rtengine
|
||||
class ToneCurve;
|
||||
class ColorAppearance;
|
||||
|
||||
namespace curves {
|
||||
|
||||
inline void setLutVal(const LUTf &lut, float &val)
|
||||
{
|
||||
if (!OOG(val)) {
|
||||
val = lut[std::max(val, 0.f)];
|
||||
} else if (val < 0.f) {
|
||||
float m = lut[0.f];
|
||||
val += m;
|
||||
} else {
|
||||
float m = lut[MAXVALF];
|
||||
val += (m - MAXVALF);
|
||||
}
|
||||
}
|
||||
|
||||
inline void setLutVal(float &val, float lutval, float maxval)
|
||||
{
|
||||
if (!OOG(val)) {
|
||||
val = lutval;
|
||||
} else if (val > 0.f) {
|
||||
val += maxval - MAXVALF;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace curves
|
||||
|
||||
class CurveFactory
|
||||
{
|
||||
|
||||
@ -864,7 +890,7 @@ inline void Lightcurve::Apply(float& Li) const
|
||||
|
||||
assert(lutColCurve);
|
||||
|
||||
Li = lutColCurve[Li];
|
||||
curves::setLutVal(lutColCurve, Li);
|
||||
}
|
||||
|
||||
class Brightcurve : public ColorAppearance
|
||||
@ -879,7 +905,7 @@ inline void Brightcurve::Apply(float& Br) const
|
||||
|
||||
assert(lutColCurve);
|
||||
|
||||
Br = lutColCurve[Br];
|
||||
curves::setLutVal(lutColCurve, Br);
|
||||
}
|
||||
|
||||
class Chromacurve : public ColorAppearance
|
||||
@ -894,7 +920,7 @@ inline void Chromacurve::Apply(float& Cr) const
|
||||
|
||||
assert(lutColCurve);
|
||||
|
||||
Cr = lutColCurve[Cr];
|
||||
curves::setLutVal(lutColCurve, Cr);
|
||||
}
|
||||
class Saturcurve : public ColorAppearance
|
||||
{
|
||||
@ -908,7 +934,7 @@ inline void Saturcurve::Apply(float& Sa) const
|
||||
|
||||
assert(lutColCurve);
|
||||
|
||||
Sa = lutColCurve[Sa];
|
||||
curves::setLutVal(lutColCurve, Sa);
|
||||
}
|
||||
|
||||
class Colorfcurve : public ColorAppearance
|
||||
@ -923,7 +949,7 @@ inline void Colorfcurve::Apply(float& Cf) const
|
||||
|
||||
assert(lutColCurve);
|
||||
|
||||
Cf = lutColCurve[Cf];
|
||||
curves::setLutVal(lutColCurve, Cf);
|
||||
}
|
||||
|
||||
|
||||
@ -1012,9 +1038,9 @@ inline void StandardToneCurve::Apply(float& r, float& g, float& b) const
|
||||
|
||||
assert(lutToneCurve);
|
||||
|
||||
r = lutToneCurve[r];
|
||||
g = lutToneCurve[g];
|
||||
b = lutToneCurve[b];
|
||||
curves::setLutVal(lutToneCurve, r);
|
||||
curves::setLutVal(lutToneCurve, g);
|
||||
curves::setLutVal(lutToneCurve, b);
|
||||
}
|
||||
|
||||
inline void StandardToneCurve::BatchApply(
|
||||
@ -1043,29 +1069,36 @@ inline void StandardToneCurve::BatchApply(
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
r[i] = lutToneCurve[r[i]];
|
||||
g[i] = lutToneCurve[g[i]];
|
||||
b[i] = lutToneCurve[b[i]];
|
||||
curves::setLutVal(lutToneCurve, r[i]);
|
||||
curves::setLutVal(lutToneCurve, g[i]);
|
||||
curves::setLutVal(lutToneCurve, b[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
#ifdef __SSE2__
|
||||
|
||||
vfloat tmpr;
|
||||
vfloat tmpg;
|
||||
vfloat tmpb;
|
||||
float mv = lutToneCurve[MAXVALF];
|
||||
for (; i + 3 < end; i += 4) {
|
||||
__m128 r_val = LVF(r[i]);
|
||||
__m128 g_val = LVF(g[i]);
|
||||
__m128 b_val = LVF(b[i]);
|
||||
STVF(r[i], lutToneCurve[r_val]);
|
||||
STVF(g[i], lutToneCurve[g_val]);
|
||||
STVF(b[i], lutToneCurve[b_val]);
|
||||
STVF(tmpr[0], lutToneCurve[r_val]);
|
||||
STVF(tmpg[0], lutToneCurve[g_val]);
|
||||
STVF(tmpb[0], lutToneCurve[b_val]);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
curves::setLutVal(r[i+j], tmpr[j], mv);
|
||||
curves::setLutVal(g[i+j], tmpg[j], mv);
|
||||
curves::setLutVal(b[i+j], tmpb[j], mv);
|
||||
}
|
||||
}
|
||||
|
||||
// Remainder in non-SSE.
|
||||
for (; i < end; ++i) {
|
||||
r[i] = lutToneCurve[r[i]];
|
||||
g[i] = lutToneCurve[g[i]];
|
||||
b[i] = lutToneCurve[b[i]];
|
||||
curves::setLutVal(lutToneCurve, r[i]);
|
||||
curves::setLutVal(lutToneCurve, g[i]);
|
||||
curves::setLutVal(lutToneCurve, b[i]);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1074,10 +1107,13 @@ inline void StandardToneCurve::BatchApply(
|
||||
// Tone curve according to Adobe's reference implementation
|
||||
// values in 0xffff space
|
||||
// inlined to make sure there will be no cache flush when used
|
||||
inline void AdobeToneCurve::Apply(float& r, float& g, float& b) const
|
||||
inline void AdobeToneCurve::Apply (float& ir, float& ig, float& ib) const
|
||||
{
|
||||
|
||||
assert(lutToneCurve);
|
||||
float r = CLIP(ir);
|
||||
float g = CLIP(ig);
|
||||
float b = CLIP(ib);
|
||||
|
||||
if (r >= g) {
|
||||
if (g > b) {
|
||||
@ -1100,6 +1136,10 @@ inline void AdobeToneCurve::Apply(float& r, float& g, float& b) const
|
||||
RGBTone(g, b, r); // Case 7: g >= b > r
|
||||
}
|
||||
}
|
||||
|
||||
setUnlessOOG(ir, r);
|
||||
setUnlessOOG(ig, g);
|
||||
setUnlessOOG(ib, b);
|
||||
}
|
||||
|
||||
inline void AdobeToneCurve::RGBTone(float& r, float& g, float& b) const
|
||||
@ -1112,10 +1152,14 @@ inline void AdobeToneCurve::RGBTone(float& r, float& g, float& b) const
|
||||
}
|
||||
|
||||
// Modifying the Luminance channel only
|
||||
inline void LuminanceToneCurve::Apply(float &r, float &g, float &b) const
|
||||
inline void LuminanceToneCurve::Apply(float &ir, float &ig, float &ib) const
|
||||
{
|
||||
assert(lutToneCurve);
|
||||
|
||||
float r = CLIP(ir);
|
||||
float g = CLIP(ig);
|
||||
float b = CLIP(ib);
|
||||
|
||||
float currLuminance = r * 0.2126729f + g * 0.7151521f + b * 0.0721750f;
|
||||
|
||||
const float newLuminance = lutToneCurve[currLuminance];
|
||||
@ -1124,6 +1168,10 @@ inline void LuminanceToneCurve::Apply(float &r, float &g, float &b) const
|
||||
r = LIM<float> (r * coef, 0.f, 65535.f);
|
||||
g = LIM<float> (g * coef, 0.f, 65535.f);
|
||||
b = LIM<float> (b * coef, 0.f, 65535.f);
|
||||
|
||||
setUnlessOOG(ir, r);
|
||||
setUnlessOOG(ig, g);
|
||||
setUnlessOOG(ib, b);
|
||||
}
|
||||
|
||||
inline float WeightedStdToneCurve::Triangle(float a, float a1, float b) const
|
||||
@ -1157,14 +1205,14 @@ inline vfloat WeightedStdToneCurve::Triangle(vfloat a, vfloat a1, vfloat b) cons
|
||||
|
||||
// Tone curve modifying the value channel only, preserving hue and saturation
|
||||
// values in 0xffff space
|
||||
inline void WeightedStdToneCurve::Apply(float& r, float& g, float& b) const
|
||||
inline void WeightedStdToneCurve::Apply (float& ir, float& ig, float& ib) const
|
||||
{
|
||||
|
||||
assert(lutToneCurve);
|
||||
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
float r = CLIP(ir);
|
||||
float g = CLIP(ig);
|
||||
float b = CLIP(ib);
|
||||
float r1 = lutToneCurve[r];
|
||||
float g1 = Triangle(r, r1, g);
|
||||
float b1 = Triangle(r, r1, b);
|
||||
@ -1180,6 +1228,10 @@ inline void WeightedStdToneCurve::Apply(float& r, float& g, float& b) const
|
||||
r = CLIP<float>(r1 * 0.50f + r2 * 0.25f + r3 * 0.25f);
|
||||
g = CLIP<float> (g1 * 0.25f + g2 * 0.50f + g3 * 0.25f);
|
||||
b = CLIP<float> (b1 * 0.25f + b2 * 0.25f + b3 * 0.50f);
|
||||
|
||||
setUnlessOOG(ir, r);
|
||||
setUnlessOOG(ig, g);
|
||||
setUnlessOOG(ib, b);
|
||||
}
|
||||
|
||||
inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t end, float *r, float *g, float *b) const
|
||||
@ -1216,6 +1268,10 @@ inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t en
|
||||
const vfloat zd5v = F2V(0.5f);
|
||||
const vfloat zd25v = F2V(0.25f);
|
||||
|
||||
vfloat tmpr;
|
||||
vfloat tmpg;
|
||||
vfloat tmpb;
|
||||
|
||||
for (; i + 3 < end; i += 4) {
|
||||
vfloat r_val = LIMV(LVF(r[i]), ZEROV, c65535v);
|
||||
vfloat g_val = LIMV(LVF(g[i]), ZEROV, c65535v);
|
||||
@ -1232,9 +1288,14 @@ inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t en
|
||||
vfloat r3 = Triangle(b_val, b3, r_val);
|
||||
vfloat g3 = Triangle(b_val, b3, g_val);
|
||||
|
||||
STVF(r[i], LIMV(r1 * zd5v + r2 * zd25v + r3 * zd25v, ZEROV, c65535v));
|
||||
STVF(g[i], LIMV(g1 * zd25v + g2 * zd5v + g3 * zd25v, ZEROV, c65535v));
|
||||
STVF(b[i], LIMV(b1 * zd25v + b2 * zd25v + b3 * zd5v, ZEROV, c65535v));
|
||||
STVF(tmpr[0], LIMV(r1 * zd5v + r2 * zd25v + r3 * zd25v, ZEROV, c65535v));
|
||||
STVF(tmpg[0], LIMV(g1 * zd25v + g2 * zd5v + g3 * zd25v, ZEROV, c65535v));
|
||||
STVF(tmpb[0], LIMV(b1 * zd25v + b2 * zd25v + b3 * zd5v, ZEROV, c65535v));
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
setUnlessOOG(r[i+j], tmpr[j]);
|
||||
setUnlessOOG(g[i+j], tmpg[j]);
|
||||
setUnlessOOG(b[i+j], tmpb[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Remainder in non-SSE.
|
||||
@ -1247,14 +1308,14 @@ inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t en
|
||||
|
||||
// Tone curve modifying the value channel only, preserving hue and saturation
|
||||
// values in 0xffff space
|
||||
inline void SatAndValueBlendingToneCurve::Apply(float& r, float& g, float& b) const
|
||||
inline void SatAndValueBlendingToneCurve::Apply (float& ir, float& ig, float& ib) const
|
||||
{
|
||||
|
||||
assert(lutToneCurve);
|
||||
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
float r = CLIP(ir);
|
||||
float g = CLIP(ig);
|
||||
float b = CLIP(ib);
|
||||
|
||||
const float lum = (r + g + b) / 3.f;
|
||||
const float newLum = lutToneCurve[lum];
|
||||
@ -1280,6 +1341,10 @@ inline void SatAndValueBlendingToneCurve::Apply(float& r, float& g, float& b) co
|
||||
}
|
||||
|
||||
Color::hsv2rgbdcp(h, s, v + dV, r, g, b);
|
||||
|
||||
setUnlessOOG(ir, r);
|
||||
setUnlessOOG(ig, g);
|
||||
setUnlessOOG(ib, b);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1190,13 +1190,17 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int
|
||||
}
|
||||
|
||||
// with looktable and tonecurve we need to clip
|
||||
newr = FCLIP(newr);
|
||||
newg = FCLIP(newg);
|
||||
newb = FCLIP(newb);
|
||||
// newr = FCLIP(newr);
|
||||
// newg = FCLIP(newg);
|
||||
// newb = FCLIP(newb);
|
||||
|
||||
if (as_in.data->apply_look_table) {
|
||||
float cnewr = FCLIP(newr);
|
||||
float cnewg = FCLIP(newg);
|
||||
float cnewb = FCLIP(newb);
|
||||
|
||||
float h, s, v;
|
||||
Color::rgb2hsvdcp(newr, newg, newb, h, s, v);
|
||||
Color::rgb2hsvdcp(cnewr, cnewg, cnewb, h, s, v);
|
||||
|
||||
hsdApply(look_info, look_table, h, s, v);
|
||||
s = CLIP01(s);
|
||||
@ -1209,7 +1213,11 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int
|
||||
h -= 6.0f;
|
||||
}
|
||||
|
||||
Color::hsv2rgbdcp( h, s, v, newr, newg, newb);
|
||||
Color::hsv2rgbdcp( h, s, v, cnewr, cnewg, cnewb);
|
||||
|
||||
setUnlessOOG(newr, cnewr);
|
||||
setUnlessOOG(newg, cnewg);
|
||||
setUnlessOOG(newb, cnewb);
|
||||
}
|
||||
|
||||
if (as_in.data->use_tone_curve) {
|
||||
|
@ -242,7 +242,7 @@ void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, int srcwidt
|
||||
|
||||
for (int i = 0; i < srcheight; i++)
|
||||
for (int j = 0; j < srcwidth; j++) {
|
||||
dst[i][j] = CLIP(buffer[i][j]); // TODO: Really a clip necessary?
|
||||
dst[i][j] = /*CLIP*/(buffer[i][j]); // TODO: Really a clip necessary?
|
||||
}
|
||||
|
||||
}
|
||||
@ -493,7 +493,7 @@ void ImProcFunctions :: dirpyr_equalizercam(CieImage *ncie, float ** src, float
|
||||
for (int i = 0; i < srcheight; i++)
|
||||
for (int j = 0; j < srcwidth; j++) {
|
||||
if (ncie->J_p[i][j] > 8.f && ncie->J_p[i][j] < 92.f) {
|
||||
dst[i][j] = CLIP(buffer[i][j]); // TODO: Really a clip necessary?
|
||||
dst[i][j] = /*CLIP*/( buffer[i][j] ); // TODO: Really a clip necessary?
|
||||
} else {
|
||||
dst[i][j] = src[i][j];
|
||||
}
|
||||
@ -501,7 +501,7 @@ void ImProcFunctions :: dirpyr_equalizercam(CieImage *ncie, float ** src, float
|
||||
} else {
|
||||
for (int i = 0; i < srcheight; i++)
|
||||
for (int j = 0; j < srcwidth; j++) {
|
||||
dst[i][j] = CLIP(buffer[i][j]); // TODO: Really a clip necessary?
|
||||
dst[i][j] = /*CLIP*/( buffer[i][j] ); // TODO: Really a clip necessary?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ inline void ImageDatas::convertTo(unsigned char src, unsigned short& dst) const
|
||||
template<>
|
||||
inline void ImageDatas::convertTo(float src, unsigned char& dst) const
|
||||
{
|
||||
dst = uint16ToUint8Rounded(src);
|
||||
dst = uint16ToUint8Rounded(CLIP(src));
|
||||
}
|
||||
template<>
|
||||
inline void ImageDatas::convertTo(unsigned char src, float& dst) const
|
||||
|
@ -146,6 +146,9 @@ void Imagefloat::setScanline (int row, unsigned char* buffer, int bps, unsigned
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace rtengine { extern void filmlike_clip(float *r, float *g, float *b); }
|
||||
|
||||
void Imagefloat::getScanline (int row, unsigned char* buffer, int bps)
|
||||
{
|
||||
|
||||
@ -163,18 +166,24 @@ void Imagefloat::getScanline (int row, unsigned char* buffer, int bps)
|
||||
sbuffer[ix++] = g(row, i) / 65535.f;
|
||||
sbuffer[ix++] = b(row, i) / 65535.f;
|
||||
}
|
||||
} else if (bps == 16) {
|
||||
} else {
|
||||
unsigned short *sbuffer = (unsigned short *)buffer;
|
||||
for (int i = 0, ix = 0; i < width; i++) {
|
||||
sbuffer[ix++] = CLIP(r(row, i));
|
||||
sbuffer[ix++] = CLIP(g(row, i));
|
||||
sbuffer[ix++] = CLIP(b(row, i));
|
||||
}
|
||||
} else if (bps == 8) {
|
||||
for (int i = 0, ix = 0; i < width; i++) {
|
||||
buffer[ix++] = rtengine::uint16ToUint8Rounded(CLIP(r(row, i)));
|
||||
buffer[ix++] = rtengine::uint16ToUint8Rounded(CLIP(g(row, i)));
|
||||
buffer[ix++] = rtengine::uint16ToUint8Rounded(CLIP(b(row, i)));
|
||||
float ri = r(row, i);
|
||||
float gi = g(row, i);
|
||||
float bi = b(row, i);
|
||||
if (ri > 65535.f || gi > 65535.f || bi > 65535.f) {
|
||||
filmlike_clip(&ri, &gi, &bi);
|
||||
}
|
||||
if (bps == 16) {
|
||||
sbuffer[ix++] = CLIP(ri);
|
||||
sbuffer[ix++] = CLIP(gi);
|
||||
sbuffer[ix++] = CLIP(bi);
|
||||
} else if (bps == 8) {
|
||||
buffer[ix++] = rtengine::uint16ToUint8Rounded(CLIP(ri));
|
||||
buffer[ix++] = rtengine::uint16ToUint8Rounded(CLIP(gi));
|
||||
buffer[ix++] = rtengine::uint16ToUint8Rounded(CLIP(bi));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -238,6 +247,8 @@ void Imagefloat::getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, Prev
|
||||
gm /= area;
|
||||
bm /= area;
|
||||
|
||||
const auto CLIP0 = [](float v) -> float { return std::max(v, 0.f); };
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel
|
||||
{
|
||||
@ -270,9 +281,9 @@ void Imagefloat::getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, Prev
|
||||
continue;
|
||||
}
|
||||
|
||||
lineR[dst_x] = CLIP(rm2 * r(src_y, src_x));
|
||||
lineG[dst_x] = CLIP(gm2 * g(src_y, src_x));
|
||||
lineB[dst_x] = CLIP(bm2 * b(src_y, src_x));
|
||||
lineR[dst_x] = CLIP0(rm2 * r(src_y, src_x));
|
||||
lineG[dst_x] = CLIP0(gm2 * g(src_y, src_x));
|
||||
lineB[dst_x] = CLIP0(bm2 * b(src_y, src_x));
|
||||
}
|
||||
} else {
|
||||
// source image, first line of the current destination row
|
||||
@ -303,15 +314,15 @@ void Imagefloat::getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, Prev
|
||||
// convert back to gamma and clip
|
||||
if (src_sub_width == skip && src_sub_height == skip) {
|
||||
// Common case where the sub-region is complete
|
||||
lineR[dst_x] = CLIP(rm * rtot);
|
||||
lineG[dst_x] = CLIP(gm * gtot);
|
||||
lineB[dst_x] = CLIP(bm * btot);
|
||||
lineR[dst_x] = CLIP0(rm * rtot);
|
||||
lineG[dst_x] = CLIP0(gm * gtot);
|
||||
lineB[dst_x] = CLIP0(bm * btot);
|
||||
} else {
|
||||
// computing a special factor for this incomplete sub-region
|
||||
float area = src_sub_width * src_sub_height;
|
||||
lineR[dst_x] = CLIP(rm2 * rtot / area);
|
||||
lineG[dst_x] = CLIP(gm2 * gtot / area);
|
||||
lineB[dst_x] = CLIP(bm2 * btot / area);
|
||||
lineR[dst_x] = CLIP0(rm2 * rtot / area);
|
||||
lineG[dst_x] = CLIP0(gm2 * gtot / area);
|
||||
lineB[dst_x] = CLIP0(bm2 * btot / area);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -357,9 +368,9 @@ Imagefloat::to8()
|
||||
|
||||
for (int h = 0; h < height; ++h) {
|
||||
for (int w = 0; w < width; ++w) {
|
||||
img8->r(h, w) = uint16ToUint8Rounded(r(h, w));
|
||||
img8->g(h, w) = uint16ToUint8Rounded(g(h, w));
|
||||
img8->b(h, w) = uint16ToUint8Rounded(b(h, w));
|
||||
img8->r(h, w) = uint16ToUint8Rounded(CLIP(r(h, w)));
|
||||
img8->g(h, w) = uint16ToUint8Rounded(CLIP(g(h, w)));
|
||||
img8->b(h, w) = uint16ToUint8Rounded(CLIP(b(h, w)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,9 +387,9 @@ Imagefloat::to16()
|
||||
|
||||
for (int h = 0; h < height; ++h) {
|
||||
for (int w = 0; w < width; ++w) {
|
||||
img16->r(h, w) = r(h, w);
|
||||
img16->g(h, w) = g(h, w);
|
||||
img16->b(h, w) = b(h, w);
|
||||
img16->r(h, w) = CLIP(r(h, w));
|
||||
img16->g(h, w) = CLIP(g(h, w));
|
||||
img16->b(h, w) = CLIP(b(h, w));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,11 +50,13 @@
|
||||
namespace {
|
||||
|
||||
using namespace rtengine;
|
||||
|
||||
|
||||
// begin of helper function for rgbProc()
|
||||
void shadowToneCurve(const LUTf &shtonecurve, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize)
|
||||
{
|
||||
|
||||
#ifdef __SSE2__
|
||||
#if defined( __SSE2__ ) && defined( __x86_64__ )
|
||||
vfloat cr = F2V(0.299f);
|
||||
vfloat cg = F2V(0.587f);
|
||||
vfloat cb = F2V(0.114f);
|
||||
@ -62,7 +64,7 @@ void shadowToneCurve(const LUTf &shtonecurve, float *rtemp, float *gtemp, float
|
||||
|
||||
for (int i = istart, ti = 0; i < tH; i++, ti++) {
|
||||
int j = jstart, tj = 0;
|
||||
#ifdef __SSE2__
|
||||
#if defined( __SSE2__ ) && defined( __x86_64__ )
|
||||
|
||||
for (; j < tW - 3; j += 4, tj += 4) {
|
||||
|
||||
@ -99,14 +101,14 @@ void shadowToneCurve(const LUTf &shtonecurve, float *rtemp, float *gtemp, float
|
||||
void highlightToneCurve(const LUTf &hltonecurve, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize, float exp_scale, float comp, float hlrange)
|
||||
{
|
||||
|
||||
#ifdef __SSE2__
|
||||
#if defined( __SSE2__ ) && defined( __x86_64__ )
|
||||
vfloat threev = F2V(3.f);
|
||||
vfloat maxvalfv = F2V(MAXVALF);
|
||||
#endif
|
||||
|
||||
for (int i = istart, ti = 0; i < tH; i++, ti++) {
|
||||
int j = jstart, tj = 0;
|
||||
#ifdef __SSE2__
|
||||
#if defined( __SSE2__ ) && defined( __x86_64__ )
|
||||
|
||||
for (; j < tW - 3; j += 4, tj += 4) {
|
||||
|
||||
@ -180,8 +182,9 @@ void proPhotoBlue(float *rtemp, float *gtemp, float *btemp, int istart, int tH,
|
||||
float r = rtemp[ti * tileSize + tj + k];
|
||||
float g = gtemp[ti * tileSize + tj + k];
|
||||
|
||||
if (r == 0.0f || g == 0.0f) {
|
||||
float b = btemp[ti * tileSize + tj + k];
|
||||
float b = btemp[ti * tileSize + tj + k];
|
||||
|
||||
if ((r == 0.0f || g == 0.0f) && rtengine::min(r, g, b) >= 0.f) {
|
||||
float h, s, v;
|
||||
Color::rgb2hsv(r, g, b, h, s, v);
|
||||
s *= 0.99f;
|
||||
@ -196,9 +199,9 @@ void proPhotoBlue(float *rtemp, float *gtemp, float *btemp, int istart, int tH,
|
||||
for (; j < tW; j++, tj++) {
|
||||
float r = rtemp[ti * tileSize + tj];
|
||||
float g = gtemp[ti * tileSize + tj];
|
||||
float b = btemp[ti * tileSize + tj];
|
||||
|
||||
if (r == 0.0f || g == 0.0f) {
|
||||
float b = btemp[ti * tileSize + tj];
|
||||
if ((r == 0.0f || g == 0.0f) && rtengine::min(r, g, b) >= 0.f) {
|
||||
float h, s, v;
|
||||
Color::rgb2hsv(r, g, b, h, s, v);
|
||||
s *= 0.99f;
|
||||
@ -240,9 +243,6 @@ void customToneCurve(const ToneCurve &customToneCurve, ToneCurveParams::TcMode c
|
||||
|
||||
for (int i = istart, ti = 0; i < tH; i++, ti++) {
|
||||
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
|
||||
rtemp[ti * tileSize + tj] = CLIP<float> (rtemp[ti * tileSize + tj]);
|
||||
gtemp[ti * tileSize + tj] = CLIP<float> (gtemp[ti * tileSize + tj]);
|
||||
btemp[ti * tileSize + tj] = CLIP<float> (btemp[ti * tileSize + tj]);
|
||||
userToneCurve.Apply(rtemp[ti * tileSize + tj], gtemp[ti * tileSize + tj], btemp[ti * tileSize + tj]);
|
||||
}
|
||||
}
|
||||
@ -3276,7 +3276,7 @@ filmlike_clip_rgb_tone(float *r, float *g, float *b, const float L)
|
||||
*b = b_;
|
||||
}
|
||||
|
||||
static void
|
||||
/*static*/ void
|
||||
filmlike_clip(float *r, float *g, float *b)
|
||||
{
|
||||
// This is Adobe's hue-stable film-like curve with a diagonal, ie only used for clipping. Can probably be further optimized.
|
||||
@ -3693,6 +3693,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
}
|
||||
|
||||
float out_rgbx[4 * TS] ALIGNED16; // Line buffer for CLUT
|
||||
float clutr[TS] ALIGNED16;
|
||||
float clutg[TS] ALIGNED16;
|
||||
float clutb[TS] ALIGNED16;
|
||||
|
||||
LUTu histToneCurveThr;
|
||||
|
||||
@ -3783,9 +3786,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
filmlike_clip(&r, &g, &b);
|
||||
}
|
||||
|
||||
rtemp[ti * TS + tj] = r;
|
||||
gtemp[ti * TS + tj] = g;
|
||||
btemp[ti * TS + tj] = b;
|
||||
setUnlessOOG(rtemp[ti * TS + tj], r);
|
||||
setUnlessOOG(gtemp[ti * TS + tj], g);
|
||||
setUnlessOOG(btemp[ti * TS + tj], b);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3794,33 +3797,46 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
|
||||
|
||||
//brightness/contrast
|
||||
rtemp[ti * TS + tj] = tonecurve[ rtemp[ti * TS + tj] ];
|
||||
gtemp[ti * TS + tj] = tonecurve[ gtemp[ti * TS + tj] ];
|
||||
btemp[ti * TS + tj] = tonecurve[ btemp[ti * TS + tj] ];
|
||||
float r = tonecurve[ CLIP(rtemp[ti * TS + tj]) ];
|
||||
float g = tonecurve[ CLIP(gtemp[ti * TS + tj]) ];
|
||||
float b = tonecurve[ CLIP(btemp[ti * TS + tj]) ];
|
||||
|
||||
int y = CLIP<int> (lumimulf[0] * Color::gamma2curve[rtemp[ti * TS + tj]] + lumimulf[1] * Color::gamma2curve[gtemp[ti * TS + tj]] + lumimulf[2] * Color::gamma2curve[btemp[ti * TS + tj]]);
|
||||
histToneCurveThr[y >> histToneCurveCompression]++;
|
||||
|
||||
setUnlessOOG(rtemp[ti * TS + tj], r);
|
||||
setUnlessOOG(gtemp[ti * TS + tj], g);
|
||||
setUnlessOOG(btemp[ti * TS + tj], b);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vfloat tmpr;
|
||||
vfloat tmpg;
|
||||
vfloat tmpb;
|
||||
|
||||
for (int i = istart, ti = 0; i < tH; i++, ti++) {
|
||||
int j = jstart, tj = 0;
|
||||
#ifdef __SSE2__
|
||||
|
||||
for (; j < tW - 3; j += 4, tj += 4) {
|
||||
//brightness/contrast
|
||||
STVF(rtemp[ti * TS + tj], tonecurve(LVF(rtemp[ti * TS + tj])));
|
||||
STVF(gtemp[ti * TS + tj], tonecurve(LVF(gtemp[ti * TS + tj])));
|
||||
STVF(btemp[ti * TS + tj], tonecurve(LVF(btemp[ti * TS + tj])));
|
||||
STVF(tmpr[0], tonecurve(LVF(rtemp[ti * TS + tj])));
|
||||
STVF(tmpg[0], tonecurve(LVF(gtemp[ti * TS + tj])));
|
||||
STVF(tmpb[0], tonecurve(LVF(btemp[ti * TS + tj])));
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
setUnlessOOG(rtemp[ti * TS + tj + k], tmpr[k]);
|
||||
setUnlessOOG(gtemp[ti * TS + tj + k], tmpg[k]);
|
||||
setUnlessOOG(btemp[ti * TS + tj + k], tmpb[k]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
for (; j < tW; j++, tj++) {
|
||||
//brightness/contrast
|
||||
rtemp[ti * TS + tj] = tonecurve[rtemp[ti * TS + tj]];
|
||||
gtemp[ti * TS + tj] = tonecurve[gtemp[ti * TS + tj]];
|
||||
btemp[ti * TS + tj] = tonecurve[btemp[ti * TS + tj]];
|
||||
setUnlessOOG(rtemp[ti * TS + tj], tonecurve[rtemp[ti * TS + tj]]);
|
||||
setUnlessOOG(gtemp[ti * TS + tj], tonecurve[gtemp[ti * TS + tj]]);
|
||||
setUnlessOOG(btemp[ti * TS + tj], tonecurve[btemp[ti * TS + tj]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3868,17 +3884,17 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
|
||||
// individual R tone curve
|
||||
if (rCurve) {
|
||||
rtemp[ti * TS + tj] = rCurve[ rtemp[ti * TS + tj] ];
|
||||
setUnlessOOG(rtemp[ti * TS + tj], rCurve[ rtemp[ti * TS + tj] ]);
|
||||
}
|
||||
|
||||
// individual G tone curve
|
||||
if (gCurve) {
|
||||
gtemp[ti * TS + tj] = gCurve[ gtemp[ti * TS + tj] ];
|
||||
setUnlessOOG(gtemp[ti * TS + tj], gCurve[ gtemp[ti * TS + tj] ]);
|
||||
}
|
||||
|
||||
// individual B tone curve
|
||||
if (bCurve) {
|
||||
btemp[ti * TS + tj] = bCurve[ btemp[ti * TS + tj] ];
|
||||
setUnlessOOG(btemp[ti * TS + tj], bCurve[ btemp[ti * TS + tj] ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3945,18 +3961,22 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
bool neg = false;
|
||||
bool more_rgb = false;
|
||||
//gamut control : Lab values are in gamut
|
||||
Color::gamutLchonly(HH, sincosval, Lpro, Chpro, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], wip, highlight, 0.15f, 0.96f, neg, more_rgb);
|
||||
Color::gamutLchonly (HH, sincosval, Lpro, Chpro, r, g, b, wip, highlight, 0.15f, 0.96f, neg, more_rgb);
|
||||
#else
|
||||
//gamut control : Lab values are in gamut
|
||||
Color::gamutLchonly(HH, sincosval, Lpro, Chpro, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], wip, highlight, 0.15f, 0.96f);
|
||||
Color::gamutLchonly (HH, sincosval, Lpro, Chpro, r, g, b, wip, highlight, 0.15f, 0.96f);
|
||||
#endif
|
||||
//end of gamut control
|
||||
} else {
|
||||
float x_, y_, z_;
|
||||
//calculate RGB with L_2 and old value of a and b
|
||||
Color::Lab2XYZ(L_2, a_1, b_1, x_, y_, z_) ;
|
||||
Color::xyz2rgb(x_, y_, z_, rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], wip);
|
||||
Color::xyz2rgb (x_, y_, z_, r, g, b, wip);
|
||||
}
|
||||
|
||||
setUnlessOOG(rtemp[ti * TS + tj], r);
|
||||
setUnlessOOG(gtemp[ti * TS + tj], g);
|
||||
setUnlessOOG(btemp[ti * TS + tj], b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4107,9 +4127,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
bo *= preserv;
|
||||
}
|
||||
|
||||
rtemp[ti * TS + tj] = CLIP(ro);
|
||||
gtemp[ti * TS + tj] = CLIP(go);
|
||||
btemp[ti * TS + tj] = CLIP(bo);
|
||||
setUnlessOOG(rtemp[ti * TS + tj], CLIP(ro));
|
||||
setUnlessOOG(gtemp[ti * TS + tj], CLIP(go));
|
||||
setUnlessOOG(btemp[ti * TS + tj], CLIP(bo));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4163,9 +4183,11 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
float b = btemp[ti * TS + tj];
|
||||
float ro, go, bo;
|
||||
labtoning(r, g, b, ro, go, bo, algm, metchrom, twoc, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, clToningcurve, cl2Toningcurve, iplow, iphigh, wp, wip);
|
||||
rtemp[ti * TS + tj] = CLIP (ro); //I used CLIP because there is a little bug in gamutLchonly that return 65536.ii instead of 65535 ==> crash
|
||||
gtemp[ti * TS + tj] = CLIP(go);
|
||||
btemp[ti * TS + tj] = CLIP(bo);
|
||||
if (!OOG(rtemp[ti * TS + tj]) || !OOG(gtemp[ti * TS + tj]) || !OOG(btemp[ti * TS + tj])) {
|
||||
rtemp[ti * TS + tj] = ro;
|
||||
gtemp[ti * TS + tj] = go;
|
||||
btemp[ti * TS + tj] = bo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4247,9 +4269,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
for (int i = istart, ti = 0; i < tH; i++, ti++) {
|
||||
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
|
||||
const SatAndValueBlendingToneCurve& userToneCurvebw = static_cast<const SatAndValueBlendingToneCurve&>(customToneCurvebw1);
|
||||
rtemp[ti * TS + tj] = CLIP<float> (rtemp[ti * TS + tj]);
|
||||
gtemp[ti * TS + tj] = CLIP<float> (gtemp[ti * TS + tj]);
|
||||
btemp[ti * TS + tj] = CLIP<float> (btemp[ti * TS + tj]);
|
||||
// rtemp[ti * TS + tj] = CLIP<float> (rtemp[ti * TS + tj]);
|
||||
// gtemp[ti * TS + tj] = CLIP<float> (gtemp[ti * TS + tj]);
|
||||
// btemp[ti * TS + tj] = CLIP<float> (btemp[ti * TS + tj]);
|
||||
userToneCurvebw.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]);
|
||||
}
|
||||
}
|
||||
@ -4257,9 +4279,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
for (int i = istart, ti = 0; i < tH; i++, ti++) {
|
||||
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
|
||||
const WeightedStdToneCurve& userToneCurvebw = static_cast<const WeightedStdToneCurve&>(customToneCurvebw1);
|
||||
rtemp[ti * TS + tj] = CLIP<float> (rtemp[ti * TS + tj]);
|
||||
gtemp[ti * TS + tj] = CLIP<float> (gtemp[ti * TS + tj]);
|
||||
btemp[ti * TS + tj] = CLIP<float> (btemp[ti * TS + tj]);
|
||||
// rtemp[ti * TS + tj] = CLIP<float> (rtemp[ti * TS + tj]);
|
||||
// gtemp[ti * TS + tj] = CLIP<float> (gtemp[ti * TS + tj]);
|
||||
// btemp[ti * TS + tj] = CLIP<float> (btemp[ti * TS + tj]);
|
||||
|
||||
userToneCurvebw.Apply(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj]);
|
||||
}
|
||||
@ -4412,28 +4434,32 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, v_work2xyz);
|
||||
Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, v_xyz2clut);
|
||||
|
||||
STVF(rtemp[ti * TS + tj], sourceR);
|
||||
STVF(gtemp[ti * TS + tj], sourceG);
|
||||
STVF(btemp[ti * TS + tj], sourceB);
|
||||
STVF (clutr[tj], sourceR);
|
||||
STVF (clutg[tj], sourceG);
|
||||
STVF (clutb[tj], sourceB);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
for (; j < tW; j++, tj++) {
|
||||
float &sourceR = rtemp[ti * TS + tj];
|
||||
float &sourceG = gtemp[ti * TS + tj];
|
||||
float &sourceB = btemp[ti * TS + tj];
|
||||
float sourceR = rtemp[ti * TS + tj];
|
||||
float sourceG = gtemp[ti * TS + tj];
|
||||
float sourceB = btemp[ti * TS + tj];
|
||||
|
||||
float x, y, z;
|
||||
Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, wprof);
|
||||
Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, xyz2clut);
|
||||
Color::xyz2rgb (x, y, z, clutr[tj], clutg[tj], clutb[tj], xyz2clut);
|
||||
}
|
||||
} else {
|
||||
memcpy(clutr, &rtemp[ti * TS], sizeof(float) * TS);
|
||||
memcpy(clutg, >emp[ti * TS], sizeof(float) * TS);
|
||||
memcpy(clutb, &btemp[ti * TS], sizeof(float) * TS);
|
||||
}
|
||||
|
||||
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
|
||||
float &sourceR = rtemp[ti * TS + tj];
|
||||
float &sourceG = gtemp[ti * TS + tj];
|
||||
float &sourceB = btemp[ti * TS + tj];
|
||||
float &sourceR = clutr[tj];
|
||||
float &sourceG = clutg[tj];
|
||||
float &sourceB = clutb[tj];
|
||||
|
||||
// Apply gamma sRGB (default RT)
|
||||
sourceR = Color::gamma_srgbclipped(sourceR);
|
||||
@ -4441,20 +4467,19 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
sourceB = Color::gamma_srgbclipped(sourceB);
|
||||
}
|
||||
|
||||
const std::size_t line_offset = ti * TS;
|
||||
hald_clut->getRGB(
|
||||
film_simulation_strength,
|
||||
std::min(TS, tW - jstart),
|
||||
rtemp + line_offset,
|
||||
gtemp + line_offset,
|
||||
btemp + line_offset,
|
||||
clutr,
|
||||
clutg,
|
||||
clutb,
|
||||
out_rgbx
|
||||
);
|
||||
|
||||
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
|
||||
float &sourceR = rtemp[ti * TS + tj];
|
||||
float &sourceG = gtemp[ti * TS + tj];
|
||||
float &sourceB = btemp[ti * TS + tj];
|
||||
float &sourceR = clutr[tj];
|
||||
float &sourceG = clutg[tj];
|
||||
float &sourceB = clutb[tj];
|
||||
|
||||
// Apply inverse gamma sRGB
|
||||
sourceR = Color::igamma_srgb(out_rgbx[tj * 4 + 0]);
|
||||
@ -4470,9 +4495,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
#ifdef __SSE2__
|
||||
|
||||
for (; j < tW - 3; j += 4, tj += 4) {
|
||||
vfloat sourceR = LVF(rtemp[ti * TS + tj]);
|
||||
vfloat sourceG = LVF(gtemp[ti * TS + tj]);
|
||||
vfloat sourceB = LVF(btemp[ti * TS + tj]);
|
||||
vfloat sourceR = LVF (clutr[tj]);
|
||||
vfloat sourceG = LVF (clutg[tj]);
|
||||
vfloat sourceB = LVF (clutb[tj]);
|
||||
|
||||
vfloat x;
|
||||
vfloat y;
|
||||
@ -4480,23 +4505,31 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, v_clut2xyz);
|
||||
Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, v_xyz2work);
|
||||
|
||||
STVF(rtemp[ti * TS + tj], sourceR);
|
||||
STVF(gtemp[ti * TS + tj], sourceG);
|
||||
STVF(btemp[ti * TS + tj], sourceB);
|
||||
STVF (clutr[tj], sourceR);
|
||||
STVF (clutg[tj], sourceG);
|
||||
STVF (clutb[tj], sourceB);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
for (; j < tW; j++, tj++) {
|
||||
float &sourceR = rtemp[ti * TS + tj];
|
||||
float &sourceG = gtemp[ti * TS + tj];
|
||||
float &sourceB = btemp[ti * TS + tj];
|
||||
float &sourceR = clutr[tj];
|
||||
float &sourceG = clutg[tj];
|
||||
float &sourceB = clutb[tj];
|
||||
|
||||
float x, y, z;
|
||||
Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, clut2xyz);
|
||||
Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, wiprof);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
|
||||
if (!OOG(rtemp[ti * TS + tj]) || !OOG(gtemp[ti * TS + tj]) || !OOG(btemp[ti * TS + tj])) {
|
||||
rtemp[ti * TS + tj] = clutr[tj];
|
||||
gtemp[ti * TS + tj] = clutg[tj];
|
||||
btemp[ti * TS + tj] = clutb[tj];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4625,7 +4658,7 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
for (int j = 0; j < tW; j++) {
|
||||
|
||||
//mix channel
|
||||
tmpImage->r(i, j) = tmpImage->g(i, j) = tmpImage->b(i, j) = CLIP((bwr * tmpImage->r(i, j) + bwg * tmpImage->g(i, j) + bwb * tmpImage->b(i, j)) * kcorec);
|
||||
tmpImage->r (i, j) = tmpImage->g (i, j) = tmpImage->b (i, j) = /*CLIP*/ ((bwr * tmpImage->r (i, j) + bwg * tmpImage->g (i, j) + bwb * tmpImage->b (i, j)) * kcorec);
|
||||
|
||||
#ifndef __SSE2__
|
||||
|
||||
@ -4682,9 +4715,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
for (int j = 0; j < tW; j++) {
|
||||
const WeightedStdToneCurve& userToneCurve = static_cast<const WeightedStdToneCurve&>(customToneCurvebw2);
|
||||
|
||||
tmpImage->r(i, j) = CLIP<float> (tmpImage->r(i, j));
|
||||
tmpImage->g(i, j) = CLIP<float> (tmpImage->g(i, j));
|
||||
tmpImage->b(i, j) = CLIP<float> (tmpImage->b(i, j));
|
||||
// tmpImage->r (i, j) = CLIP<float> (tmpImage->r (i, j));
|
||||
// tmpImage->g (i, j) = CLIP<float> (tmpImage->g (i, j));
|
||||
// tmpImage->b (i, j) = CLIP<float> (tmpImage->b (i, j));
|
||||
|
||||
userToneCurve.Apply(tmpImage->r(i, j), tmpImage->g(i, j), tmpImage->b(i, j));
|
||||
}
|
||||
@ -4721,9 +4754,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
bo *= preserv;
|
||||
}
|
||||
|
||||
tmpImage->r(i, j) = CLIP(ro);
|
||||
tmpImage->g(i, j) = CLIP(go);
|
||||
tmpImage->b(i, j) = CLIP(bo);
|
||||
tmpImage->r(i, j) = /*CLIP*/(ro);
|
||||
tmpImage->g(i, j) = /*CLIP*/(go);
|
||||
tmpImage->b(i, j) = /*CLIP*/(bo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4830,9 +4863,11 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
|
||||
float b = tmpImage->b(i, j);
|
||||
float ro, bo, go;
|
||||
labtoning(r, g, b, ro, go, bo, algm, metchrom, twoc, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, clToningcurve, cl2Toningcurve, iplow, iphigh, wp, wip);
|
||||
tmpImage->r(i, j) = CLIP(ro);
|
||||
tmpImage->g(i, j) = CLIP(go);
|
||||
tmpImage->b(i, j) = CLIP(bo);
|
||||
if (!OOG(tmpImage->r(i, j)) || !OOG(tmpImage->g(i, j)) || !OOG(tmpImage->b(i, j))) {
|
||||
tmpImage->r (i, j) = ro;
|
||||
tmpImage->g (i, j) = go;
|
||||
tmpImage->b (i, j) = bo;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -5076,9 +5111,9 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go,
|
||||
r += corr;
|
||||
}
|
||||
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
// r = CLIP(r);
|
||||
// g = CLIP(g);
|
||||
// b = CLIP(b);
|
||||
}
|
||||
|
||||
{
|
||||
@ -5090,9 +5125,9 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go,
|
||||
g += corr;
|
||||
}
|
||||
|
||||
r = CLIP(r);
|
||||
b = CLIP(b);
|
||||
g = CLIP(g);
|
||||
// r = CLIP(r);
|
||||
// b = CLIP(b);
|
||||
// g = CLIP(g);
|
||||
}
|
||||
|
||||
|
||||
@ -5106,9 +5141,9 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go,
|
||||
b += corr;
|
||||
}
|
||||
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
// r = CLIP(r);
|
||||
// g = CLIP(g);
|
||||
// b = CLIP(b);
|
||||
}
|
||||
|
||||
// mid tones
|
||||
@ -5139,9 +5174,9 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go,
|
||||
g -= 20000.f * RedM;
|
||||
b -= 20000.f * RedM;
|
||||
}
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
// r = CLIP(r);
|
||||
// g = CLIP(g);
|
||||
// b = CLIP(b);
|
||||
}
|
||||
|
||||
{
|
||||
@ -5156,9 +5191,9 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go,
|
||||
g += 10000.f * GreenM;
|
||||
b -= 20000.f * GreenM;
|
||||
}
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
// r = CLIP(r);
|
||||
// g = CLIP(g);
|
||||
// b = CLIP(b);
|
||||
}
|
||||
|
||||
{
|
||||
@ -5173,9 +5208,9 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go,
|
||||
g -= 20000.f * BlueM;
|
||||
b += 10000.f * BlueM;
|
||||
}
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
// r = CLIP(r);
|
||||
// g = CLIP(g);
|
||||
// b = CLIP(b);
|
||||
}
|
||||
|
||||
//high tones
|
||||
@ -5200,9 +5235,9 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go,
|
||||
b -= corr;
|
||||
}
|
||||
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
// r = CLIP(r);
|
||||
// g = CLIP(g);
|
||||
// b = CLIP(b);
|
||||
}
|
||||
|
||||
{
|
||||
@ -5215,9 +5250,9 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go,
|
||||
b -= corr;
|
||||
}
|
||||
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
// r = CLIP(r);
|
||||
// g = CLIP(g);
|
||||
// b = CLIP(b);
|
||||
}
|
||||
|
||||
{
|
||||
@ -5230,9 +5265,9 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go,
|
||||
g -= corr;
|
||||
}
|
||||
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
// r = CLIP(r);
|
||||
// g = CLIP(g);
|
||||
// b = CLIP(b);
|
||||
}
|
||||
|
||||
ro = r;
|
||||
@ -5289,24 +5324,24 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g
|
||||
b -= factor * krl;
|
||||
}
|
||||
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
// g = CLIP(g);
|
||||
// b = CLIP(b);
|
||||
|
||||
if (kgl > 0.f) {
|
||||
r -= factor * kgl;
|
||||
b -= factor * kgl;
|
||||
}
|
||||
|
||||
r = CLIP(r);
|
||||
b = CLIP(b);
|
||||
// r = CLIP(r);
|
||||
// b = CLIP(b);
|
||||
|
||||
if (kbl > 0.f) {
|
||||
r -= factor * kbl;
|
||||
g -= factor * kbl;
|
||||
}
|
||||
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
// r = CLIP(r);
|
||||
// g = CLIP(g);
|
||||
}
|
||||
|
||||
//high tones
|
||||
@ -5333,9 +5368,9 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g
|
||||
g += factor * (kgh > 0.f ? kgh : 0.f);
|
||||
b += factor * (kbh > 0.f ? kbh : 0.f);
|
||||
|
||||
r = CLIP(r);
|
||||
g = CLIP(g);
|
||||
b = CLIP(b);
|
||||
// r = CLIP(r);
|
||||
// g = CLIP(g);
|
||||
// b = CLIP(b);
|
||||
}
|
||||
|
||||
float preserv = 1.f;
|
||||
@ -5344,9 +5379,9 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g
|
||||
preserv = lumbefore / lumafter;
|
||||
}
|
||||
|
||||
ro = CLIP(r * preserv);
|
||||
go = CLIP(g * preserv);
|
||||
bo = CLIP(b * preserv);
|
||||
setUnlessOOG(ro, CLIP(r * preserv));
|
||||
setUnlessOOG(go, CLIP(g * preserv));
|
||||
setUnlessOOG(bo, CLIP(b * preserv));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5363,9 +5398,13 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g
|
||||
**/
|
||||
void ImProcFunctions::labtoning(float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, LUTf & clToningcurve, LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3])
|
||||
{
|
||||
ro = CLIP(r);
|
||||
go = CLIP(g);
|
||||
bo = CLIP(b);
|
||||
|
||||
float realL;
|
||||
float h, s, l;
|
||||
Color::rgb2hsl(r, g, b, h, s, l);
|
||||
Color::rgb2hsl (ro, go, bo, h, s, l);
|
||||
float x2, y2, z2;
|
||||
float xl, yl, zl;
|
||||
|
||||
|
@ -30,8 +30,66 @@
|
||||
namespace rtengine
|
||||
{
|
||||
|
||||
extern void filmlike_clip(float *r, float *g, float *b);
|
||||
|
||||
namespace {
|
||||
|
||||
inline void clipLAB(float iL, float ia, float ib, float &oL, float &oa, float &ob, const float scale, const float wp[3][3], const float wip[3][3])
|
||||
{
|
||||
if (iL < 0.f) {
|
||||
oL = oa = ob = 0.f;
|
||||
} else if (iL > 32768.f) {
|
||||
|
||||
float X, Y, Z;
|
||||
float r, g, b;
|
||||
Color::Lab2XYZ(iL, ia, ib, X, Y, Z);
|
||||
Color::xyz2rgb(X, Y, Z, r, g, b, wip);
|
||||
filmlike_clip(&r, &g, &b);
|
||||
Color::rgbxyz(r, g, b, X, Y, Z, wp);
|
||||
Color::XYZ2Lab(X, Y, Z, oL, oa, ob);
|
||||
oL /= scale;
|
||||
oa /= scale;
|
||||
ob /= scale;
|
||||
|
||||
// oL = 32768.f / scale;
|
||||
// oa = ob = 0.f;
|
||||
} else {
|
||||
oL = iL / scale;
|
||||
oa = ia / scale;
|
||||
ob = ib / scale;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void clipLAB(float iL, float ia, float ib, double &oL, double &oa, double &ob, const float scale, const float wp[3][3], const float wip[3][3])
|
||||
{
|
||||
float tL, ta, tb;
|
||||
clipLAB(iL, ia, ib, tL, ta, tb, scale, wp, wip);
|
||||
oL = tL;
|
||||
oa = ta;
|
||||
ob = tb;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern const Settings* settings;
|
||||
|
||||
#define DECLARE_WORKING_MATRICES_(space) \
|
||||
TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix ( space ); \
|
||||
const float wp[3][3] = { \
|
||||
{static_cast<float> (wprof[0][0]), static_cast<float> (wprof[0][1]), static_cast<float> (wprof[0][2])}, \
|
||||
{static_cast<float> (wprof[1][0]), static_cast<float> (wprof[1][1]), static_cast<float> (wprof[1][2])}, \
|
||||
{static_cast<float> (wprof[2][0]), static_cast<float> (wprof[2][1]), static_cast<float> (wprof[2][2])} \
|
||||
}; \
|
||||
\
|
||||
TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix ( space ); \
|
||||
const float wip[3][3] = { \
|
||||
{static_cast<float> (wiprof[0][0]), static_cast<float> (wiprof[0][1]), static_cast<float> (wiprof[0][2])}, \
|
||||
{static_cast<float> (wiprof[1][0]), static_cast<float> (wiprof[1][1]), static_cast<float> (wiprof[1][2])}, \
|
||||
{static_cast<float> (wiprof[2][0]), static_cast<float> (wiprof[2][1]), static_cast<float> (wiprof[2][2])} \
|
||||
}
|
||||
|
||||
|
||||
// Used in ImProcCoordinator::updatePreviewImage (rtengine/improccoordinator.cc)
|
||||
// Crop::update (rtengine/dcrop.cc)
|
||||
// Thumbnail::processImage (rtengine/rtthumbnail.cc)
|
||||
@ -40,6 +98,8 @@ extern const Settings* settings;
|
||||
// otherwise divide by 327.68, convert to xyz and apply the sRGB transform, before converting with gamma2curve
|
||||
void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image)
|
||||
{
|
||||
DECLARE_WORKING_MATRICES_(params->icm.working);
|
||||
|
||||
if (monitorTransform) {
|
||||
|
||||
int W = lab->W;
|
||||
@ -76,9 +136,8 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image)
|
||||
float* rb = lab->b[i];
|
||||
|
||||
for (int j = 0; j < W; j++) {
|
||||
buffer[iy++] = rL[j] / 327.68f;
|
||||
buffer[iy++] = ra[j] / 327.68f;
|
||||
buffer[iy++] = rb[j] / 327.68f;
|
||||
clipLAB(rL[j], ra[j], rb[j], buffer[iy], buffer[iy+1], buffer[iy+2], 327.68f, wp, wip);
|
||||
iy += 3;
|
||||
}
|
||||
|
||||
cmsDoTransform (monitorTransform, buffer, data + ix, W);
|
||||
@ -106,12 +165,14 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image)
|
||||
|
||||
float R, G, B;
|
||||
float x_, y_, z_;
|
||||
float L, a, b;
|
||||
|
||||
for (int j = 0; j < W; ++j) {
|
||||
|
||||
//float L1=rL[j],a1=ra[j],b1=rb[j];//for testing
|
||||
clipLAB(rL[j], ra[j], rb[j], L, a, b, 1.f, wp, wip);
|
||||
|
||||
Color::Lab2XYZ(rL[j], ra[j], rb[j], x_, y_, z_ );
|
||||
Color::Lab2XYZ(L, a, b, x_, y_, z_ );
|
||||
|
||||
Color::xyz2srgb(x_, y_, z_, R, G, B);
|
||||
|
||||
@ -136,6 +197,8 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image)
|
||||
// otherwise divide by 327.68, convert to xyz and apply the RGB transform, before converting with gamma2curve
|
||||
Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings)
|
||||
{
|
||||
DECLARE_WORKING_MATRICES_(icm.working);
|
||||
|
||||
//gamutmap(lab);
|
||||
|
||||
if (cx < 0) {
|
||||
@ -212,9 +275,8 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
|
||||
float* rb = lab->b[i];
|
||||
|
||||
for (int j = cx; j < cx + cw; j++) {
|
||||
buffer[iy++] = rL[j] / 327.68f;
|
||||
buffer[iy++] = ra[j] / 327.68f;
|
||||
buffer[iy++] = rb[j] / 327.68f;
|
||||
clipLAB(rL[j], ra[j], rb[j], buffer[iy], buffer[iy+1], buffer[iy+2], 327.68f, wp, wip);
|
||||
iy += 3;
|
||||
}
|
||||
|
||||
cmsDoTransform (hTransform, buffer, data + ix, cw);
|
||||
@ -242,8 +304,10 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
|
||||
|
||||
float R, G, B;
|
||||
float x_, y_, z_;
|
||||
float L, a, b;
|
||||
|
||||
for (int j = cx; j < cx + cw; ++j) {
|
||||
clipLAB(rL[j], ra[j], rb[j], L, a, b, 1.f, wp, wip);
|
||||
Color::Lab2XYZ(rL[j], ra[j], rb[j], x_, y_, z_);
|
||||
|
||||
Color::xyz2rgb(x_, y_, z_, R, G, B, xyz_rgb);
|
||||
|
@ -162,9 +162,9 @@ void ImProcFunctions::Lanczos (const Imagefloat* src, Imagefloat* dst, float sca
|
||||
b += wh[k] * lb[jj];
|
||||
}
|
||||
|
||||
dst->r (i, j) = CLIP (r);//static_cast<int> (r));
|
||||
dst->g (i, j) = CLIP (g);//static_cast<int> (g));
|
||||
dst->b (i, j) = CLIP (b);//static_cast<int> (b));
|
||||
dst->r (i, j) = /*CLIP*/ (r);//static_cast<int> (r));
|
||||
dst->g (i, j) = /*CLIP*/ (g);//static_cast<int> (g));
|
||||
dst->b (i, j) = /*CLIP*/ (b);//static_cast<int> (b));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ void transLineFuji(const float* const red, const float* const green, const float
|
||||
}
|
||||
}
|
||||
|
||||
void transLineD1x(const float* const red, const float* const green, const float* const blue, const int i, rtengine::Imagefloat* const image, const int tran, const int imwidth, const int imheight, const bool oddHeight, const bool clip)
|
||||
void transLineD1x (const float* const red, const float* const green, const float* const blue, const int i, rtengine::Imagefloat* const image, const int tran, const int imwidth, const int imheight, const bool oddHeight)
|
||||
{
|
||||
// Nikon D1X has an uncommon sensor with 4028 x 1324 sensels.
|
||||
// Vertical sensel size is 2x horizontal sensel size
|
||||
@ -223,12 +223,6 @@ void transLineD1x(const float* const red, const float* const green, const float*
|
||||
image->r(row, col) = MAX(0.f, -0.0625f * (red[j] + image->r(row + 3, col)) + 0.5625f * (image->r(row - 1, col) + image->r(row + 1, col)));
|
||||
image->g(row, col) = MAX(0.f, -0.0625f * (green[j] + image->g(row + 3, col)) + 0.5625f * (image->g(row - 1, col) + image->g(row + 1, col)));
|
||||
image->b(row, col) = MAX(0.f, -0.0625f * (blue[j] + image->b(row + 3, col)) + 0.5625f * (image->b(row - 1, col) + image->b(row + 1, col)));
|
||||
|
||||
if (clip) {
|
||||
image->r(row, col) = MIN(image->r(row, col), rtengine::MAXVALF);
|
||||
image->g(row, col) = MIN(image->g(row, col), rtengine::MAXVALF);
|
||||
image->b(row, col) = MIN(image->b(row, col), rtengine::MAXVALF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,12 +280,6 @@ void transLineD1x(const float* const red, const float* const green, const float*
|
||||
image->r(j, col) = MAX(0.f, -0.0625f * (red[j] + image->r(j, col + 3)) + 0.5625f * (image->r(j, col - 1) + image->r(j, col + 1)));
|
||||
image->g(j, col) = MAX(0.f, -0.0625f * (green[j] + image->g(j, col + 3)) + 0.5625f * (image->g(j, col - 1) + image->g(j, col + 1)));
|
||||
image->b(j, col) = MAX(0.f, -0.0625f * (blue[j] + image->b(j, col + 3)) + 0.5625f * (image->b(j, col - 1) + image->b(j, col + 1)));
|
||||
|
||||
if (clip) {
|
||||
image->r(j, col) = MIN(image->r(j, col), rtengine::MAXVALF);
|
||||
image->g(j, col) = MIN(image->g(j, col), rtengine::MAXVALF);
|
||||
image->b(j, col) = MIN(image->b(j, col), rtengine::MAXVALF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,12 +307,6 @@ void transLineD1x(const float* const red, const float* const green, const float*
|
||||
image->g(row, 2 * i - 3) = MAX(0.f, -0.0625f * (green[j] + image->g(row, 2 * i - 6)) + 0.5625f * (image->g(row, 2 * i - 2) + image->g(row, 2 * i - 4)));
|
||||
image->b(row, 2 * i - 3) = MAX(0.f, -0.0625f * (blue[j] + image->b(row, 2 * i - 6)) + 0.5625f * (image->b(row, 2 * i - 2) + image->b(row, 2 * i - 4)));
|
||||
|
||||
if (clip) {
|
||||
image->r(row, 2 * i - 3) = MIN(image->r(row, 2 * i - 3), rtengine::MAXVALF);
|
||||
image->g(row, 2 * i - 3) = MIN(image->g(row, 2 * i - 3), rtengine::MAXVALF);
|
||||
image->b(row, 2 * i - 3) = MIN(image->b(row, 2 * i - 3), rtengine::MAXVALF);
|
||||
}
|
||||
|
||||
image->r(row, 2 * i) = red[j];
|
||||
image->g(row, 2 * i) = green[j];
|
||||
image->b(row, 2 * i) = blue[j];
|
||||
@ -337,12 +319,6 @@ void transLineD1x(const float* const red, const float* const green, const float*
|
||||
image->g(row, 2 * i - 1) = MAX(0.f, -0.0625f * (green[j] + image->g(row, 2 * i - 4)) + 0.5625f * (image->g(row, 2 * i) + image->g(row, 2 * i - 2)));
|
||||
image->b(row, 2 * i - 1) = MAX(0.f, -0.0625f * (blue[j] + image->b(row, 2 * i - 4)) + 0.5625f * (image->b(row, 2 * i) + image->b(row, 2 * i - 2)));
|
||||
|
||||
if (clip) {
|
||||
image->r(j, 2 * i - 1) = MIN(image->r(j, 2 * i - 1), rtengine::MAXVALF);
|
||||
image->g(j, 2 * i - 1) = MIN(image->g(j, 2 * i - 1), rtengine::MAXVALF);
|
||||
image->b(j, 2 * i - 1) = MIN(image->b(j, 2 * i - 1), rtengine::MAXVALF);
|
||||
}
|
||||
|
||||
image->r(row, 2 * i + 1) = (red[j] + image->r(row, 2 * i - 1)) / 2;
|
||||
image->g(row, 2 * i + 1) = (green[j] + image->g(row, 2 * i - 1)) / 2;
|
||||
image->b(row, 2 * i + 1) = (blue[j] + image->b(row, 2 * i - 1)) / 2;
|
||||
@ -374,12 +350,6 @@ void transLineD1x(const float* const red, const float* const green, const float*
|
||||
image->r(2 * i - 3, j) = MAX(0.f, -0.0625f * (red[j] + image->r(2 * i - 6, j)) + 0.5625f * (image->r(2 * i - 2, j) + image->r(2 * i - 4, j)));
|
||||
image->g(2 * i - 3, j) = MAX(0.f, -0.0625f * (green[j] + image->g(2 * i - 6, j)) + 0.5625f * (image->g(2 * i - 2, j) + image->g(2 * i - 4, j)));
|
||||
image->b(2 * i - 3, j) = MAX(0.f, -0.0625f * (blue[j] + image->b(2 * i - 6, j)) + 0.5625f * (image->b(2 * i - 2, j) + image->b(2 * i - 4, j)));
|
||||
|
||||
if (clip) {
|
||||
image->r(2 * i - 3, j) = MIN(image->r(2 * i - 3, j), rtengine::MAXVALF);
|
||||
image->g(2 * i - 3, j) = MIN(image->g(2 * i - 3, j), rtengine::MAXVALF);
|
||||
image->b(2 * i - 3, j) = MIN(image->b(2 * i - 3, j), rtengine::MAXVALF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,12 +359,6 @@ void transLineD1x(const float* const red, const float* const green, const float*
|
||||
image->g(2 * i - 1, j) = MAX(0.f, -0.0625f * (green[j] + image->g(2 * i - 4, j)) + 0.5625f * (image->g(2 * i, j) + image->g(2 * i - 2, j)));
|
||||
image->b(2 * i - 1, j) = MAX(0.f, -0.0625f * (blue[j] + image->b(2 * i - 4, j)) + 0.5625f * (image->b(2 * i, j) + image->b(2 * i - 2, j)));
|
||||
|
||||
if (clip) {
|
||||
image->r(2 * i - 1, j) = MIN(image->r(2 * i - 1, j), rtengine::MAXVALF);
|
||||
image->g(2 * i - 1, j) = MIN(image->g(2 * i - 1, j), rtengine::MAXVALF);
|
||||
image->b(2 * i - 1, j) = MIN(image->b(2 * i - 1, j), rtengine::MAXVALF);
|
||||
}
|
||||
|
||||
image->r(2 * i + 1, j) = (red[j] + image->r(2 * i - 1, j)) / 2;
|
||||
image->g(2 * i + 1, j) = (green[j] + image->g(2 * i - 1, j)) / 2;
|
||||
image->b(2 * i + 1, j) = (blue[j] + image->b(2 * i - 1, j)) / 2;
|
||||
@ -725,8 +689,6 @@ void RawImageSource::getImage(const ColorTemp &ctemp, int tran, Imagefloat* imag
|
||||
hlmax[1] = clmax[1] * gm;
|
||||
hlmax[2] = clmax[2] * bm;
|
||||
|
||||
const bool doClip = (chmax[0] >= clmax[0] || chmax[1] >= clmax[1] || chmax[2] >= clmax[2]) && !hrp.hrenabled;
|
||||
|
||||
float area = skip * skip;
|
||||
rm /= area;
|
||||
gm /= area;
|
||||
@ -769,17 +731,6 @@ void RawImageSource::getImage(const ColorTemp &ctemp, int tran, Imagefloat* imag
|
||||
gtot *= gm;
|
||||
btot *= bm;
|
||||
|
||||
if (doClip) {
|
||||
// note: as hlmax[] can be larger than CLIP and we can later apply negative
|
||||
// exposure this means that we can clip away local highlights which actually
|
||||
// are not clipped. We have to do that though as we only check pixel by pixel
|
||||
// and don't know if this will transition into a clipped area, if so we need
|
||||
// to clip also surrounding to make a good colour transition
|
||||
rtot = CLIP(rtot);
|
||||
gtot = CLIP(gtot);
|
||||
btot = CLIP(btot);
|
||||
}
|
||||
|
||||
line_red[j] = rtot;
|
||||
line_grn[j] = gtot;
|
||||
line_blue[j] = btot;
|
||||
@ -804,12 +755,6 @@ void RawImageSource::getImage(const ColorTemp &ctemp, int tran, Imagefloat* imag
|
||||
gtot *= gm;
|
||||
btot *= bm;
|
||||
|
||||
if (doClip) {
|
||||
rtot = CLIP(rtot);
|
||||
gtot = CLIP(gtot);
|
||||
btot = CLIP(btot);
|
||||
}
|
||||
|
||||
line_red[j] = rtot;
|
||||
line_grn[j] = gtot;
|
||||
line_blue[j] = btot;
|
||||
@ -823,7 +768,7 @@ void RawImageSource::getImage(const ColorTemp &ctemp, int tran, Imagefloat* imag
|
||||
}
|
||||
|
||||
if (d1x) {
|
||||
transLineD1x(line_red, line_grn, line_blue, ix, image, tran, imwidth, imheight, d1xHeightOdd, doClip);
|
||||
transLineD1x (line_red, line_grn, line_blue, ix, image, tran, imwidth, imheight, d1xHeightOdd);
|
||||
} else if (fuji) {
|
||||
transLineFuji(line_red, line_grn, line_blue, ix, image, tran, imheight, fw);
|
||||
} else {
|
||||
@ -3942,9 +3887,9 @@ lab2ProphotoRgbD50(float L, float A, float B, float& r, float& g, float& b)
|
||||
r = prophoto_xyz[0][0] * X + prophoto_xyz[0][1] * Y + prophoto_xyz[0][2] * Z;
|
||||
g = prophoto_xyz[1][0] * X + prophoto_xyz[1][1] * Y + prophoto_xyz[1][2] * Z;
|
||||
b = prophoto_xyz[2][0] * X + prophoto_xyz[2][1] * Y + prophoto_xyz[2][2] * Z;
|
||||
r = CLIP01(r);
|
||||
g = CLIP01(g);
|
||||
b = CLIP01(b);
|
||||
// r = CLIP01(r);
|
||||
// g = CLIP01(g);
|
||||
// b = CLIP01(b);
|
||||
}
|
||||
|
||||
// Converts raw image including ICC input profile to working space - floating point version
|
||||
|
@ -138,6 +138,20 @@ constexpr std::uint8_t uint16ToUint8Rounded(std::uint16_t i)
|
||||
return ((i + 128) - ((i + 128) >> 8)) >> 8;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr bool OOG(const T &val, const T &high=T(MAXVAL))
|
||||
{
|
||||
return (val < T(0)) || (val > high);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setUnlessOOG(T &out, const T &val)
|
||||
{
|
||||
if (!OOG(out)) {
|
||||
out = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
bool invertMatrix(const std::array<std::array<T, 3>, 3> &in, std::array<std::array<T, 3>, 3> &out)
|
||||
@ -165,6 +179,7 @@ bool invertMatrix(const std::array<std::array<T, 3>, 3> &in, std::array<std::arr
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::array<std::array<T, 3>, 3> dotProduct(const std::array<std::array<T, 3>, 3> &a, const std::array<std::array<T, 3>, 3> &b)
|
||||
{
|
||||
@ -199,6 +214,5 @@ std::array<T, 3> dotProduct(const std::array<std::array<T, 3>, 3> &a, const std:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -1131,11 +1131,11 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT
|
||||
|
||||
for (int j = 0; j < rwidth; j++) {
|
||||
float red = baseImg->r (i, j) * rmi;
|
||||
baseImg->r (i, j) = CLIP (red);
|
||||
baseImg->r (i, j) = /*CLIP*/ (red);
|
||||
float green = baseImg->g (i, j) * gmi;
|
||||
baseImg->g (i, j) = CLIP (green);
|
||||
baseImg->g (i, j) = /*CLIP*/ (green);
|
||||
float blue = baseImg->b (i, j) * bmi;
|
||||
baseImg->b (i, j) = CLIP (blue);
|
||||
baseImg->b (i, j) = /*CLIP*/ (blue);
|
||||
|
||||
}
|
||||
}
|
||||
@ -1327,6 +1327,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// luminance processing
|
||||
// ipf.EPDToneMap(labView,0,6);
|
||||
|
||||
@ -1397,7 +1398,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT
|
||||
ipf.ciecam_02float (cieView, adap, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, sk, execsharp, d, dj, yb, rtt);
|
||||
delete cieView;
|
||||
}
|
||||
|
||||
|
||||
// color processing
|
||||
//ipf.colorCurve (labView, labView);
|
||||
|
||||
|
@ -1104,7 +1104,7 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb)
|
||||
}
|
||||
|
||||
float oldMedian;
|
||||
const float percentile = float(LIM(1, params->fattal.anchor, 100)) / 100.f;
|
||||
const float percentile = float(LIM(params->fattal.anchor, 1, 100)) / 100.f;
|
||||
findMinMaxPercentile (Yr.data(), Yr.getRows() * Yr.getCols(), percentile, oldMedian, percentile, oldMedian, multiThread);
|
||||
// median filter on the deep shadows, to avoid boosting noise
|
||||
// because w2 >= w and h2 >= h, we can use the L buffer as temporary buffer for Median_Denoise()
|
||||
@ -1159,15 +1159,15 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb)
|
||||
for (int x = 0; x < w; x++) {
|
||||
int xx = x * wr + 1;
|
||||
|
||||
float Y = std::max(Yr (x, y), epsilon);
|
||||
float l = std::max (L (xx, yy), epsilon) * (scale / Y);
|
||||
rgb->r (y, x) = std::max (rgb->r (y, x), 0.f) * l;
|
||||
rgb->g (y, x) = std::max (rgb->g (y, x), 0.f) * l;
|
||||
rgb->b (y, x) = std::max (rgb->b (y, x), 0.f) * l;
|
||||
float Y = std::max(Yr(x, y), epsilon);
|
||||
float l = std::max(L(xx, yy), epsilon) * (scale / Y);
|
||||
rgb->r(y, x) *= l;
|
||||
rgb->g(y, x) *= l;
|
||||
rgb->b(y, x) *= l;
|
||||
|
||||
assert (std::isfinite (rgb->r (y, x)));
|
||||
assert (std::isfinite (rgb->g (y, x)));
|
||||
assert (std::isfinite (rgb->b (y, x)));
|
||||
assert(std::isfinite(rgb->r(y, x)));
|
||||
assert(std::isfinite(rgb->g(y, x)));
|
||||
assert(std::isfinite(rgb->b(y, x)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1978,6 +1978,7 @@ bool EditorPanel::saveImmediately (const Glib::ustring &filename, const SaveForm
|
||||
{
|
||||
rtengine::procparams::ProcParams pparams;
|
||||
ipc->getParams (&pparams);
|
||||
|
||||
rtengine::ProcessingJob *job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
||||
|
||||
// save immediately
|
||||
@ -1985,7 +1986,9 @@ bool EditorPanel::saveImmediately (const Glib::ustring &filename, const SaveForm
|
||||
|
||||
int err = 0;
|
||||
|
||||
if (sf.format == "tif") {
|
||||
if (gimpPlugin) {
|
||||
err = img->saveAsTIFF (filename, 32, true);
|
||||
} else if (sf.format == "tif") {
|
||||
err = img->saveAsTIFF (filename, sf.tiffBits, sf.tiffUncompressed);
|
||||
} else if (sf.format == "png") {
|
||||
err = img->saveAsPNG (filename, sf.pngBits);
|
||||
|
@ -297,6 +297,10 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch
|
||||
ipDialog->add_filter (filter_icc);
|
||||
ipDialog->add_filter (filter_iccdng);
|
||||
ipDialog->add_filter (filter_any);
|
||||
#ifdef WIN32
|
||||
ipDialog->set_show_hidden(true); // ProgramData is hidden on Windows
|
||||
#endif
|
||||
|
||||
|
||||
oldip = "";
|
||||
|
||||
|
@ -663,15 +663,8 @@ int main (int argc, char **argv)
|
||||
m.run (*rtWindow);
|
||||
gdk_threads_leave();
|
||||
|
||||
if (gimpPlugin &&
|
||||
rtWindow->epanel && rtWindow->epanel->isRealized()) {
|
||||
SaveFormat sf;
|
||||
sf.format = "tif";
|
||||
sf.tiffBits = 16;
|
||||
sf.tiffUncompressed = true;
|
||||
sf.saveParams = true;
|
||||
|
||||
if (!rtWindow->epanel->saveImmediately (argv2, sf)) {
|
||||
if (gimpPlugin && rtWindow->epanel && rtWindow->epanel->isRealized()) {
|
||||
if (!rtWindow->epanel->saveImmediately(argv2, SaveFormat())) {
|
||||
ret = -2;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user