merge with dev
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
This file is part of RawTherapee.
|
||||
|
||||
Copyright (c) 2016-2018 TooWaBoo
|
||||
Version 2.85
|
||||
Version 2.86
|
||||
|
||||
RawTherapee is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -113,6 +113,10 @@ window > box {
|
||||
dialog {
|
||||
background-color: @bg-grey;
|
||||
border-radius: 0;
|
||||
-GtkDialog-button-spacing: 0;
|
||||
-GtkDialog-content-area-spacing: 0;
|
||||
-GtkDialog-content-area-border: 0;
|
||||
-GtkDialog-action-area-border: 0;
|
||||
}
|
||||
dialog > box {
|
||||
padding: 0.666666666666666666em;
|
||||
@@ -336,9 +340,13 @@ fontchooser scrolledwindow,
|
||||
/*** end ***************************************************************************************/
|
||||
|
||||
/*** Load - Save dialog ************************************************************************/
|
||||
filechooser {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
filechooser box > box box > button {
|
||||
filechooser box > box box > button {
|
||||
margin-top: 0.5em;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
filechooser image {
|
||||
@@ -465,7 +473,7 @@ separator,
|
||||
background-color: transparent;
|
||||
}
|
||||
grid separator.horizontal, box separator.horizontal {
|
||||
margin: 0.166666666666666666em 0;
|
||||
margin: 0.333333333333333333em 0.166666666666666666em;
|
||||
padding: 0;
|
||||
}
|
||||
grid separator.vertical, box separator.vertical {
|
||||
@@ -537,12 +545,12 @@ menu separator {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.scrollableToolbar separator:not(.dummy) {
|
||||
.scrollableToolbar separator.vertical {
|
||||
background-color: shade(@bg-light-grey,.75);
|
||||
margin: 0.166666666666666666em;
|
||||
}
|
||||
|
||||
#MyExpander separator {
|
||||
#MyExpander separator.horizontal {
|
||||
background-color: @view-grid-border;
|
||||
margin: 0.333333333333333333em 0.166666666666666666em;
|
||||
}
|
||||
@@ -944,7 +952,8 @@ window.csd:not(.fullscreen) #MainNotebook > header.top {
|
||||
#PrefNotebook > header {
|
||||
margin: -0.666666666666666666em -0.666666666666666666em 0.333333333333333333em;
|
||||
}
|
||||
#PrefNotebook > header tab label {
|
||||
#PrefNotebook > header tab label,
|
||||
#AboutNotebook > header tab label {
|
||||
padding-top: 0.25em;
|
||||
padding-bottom: 0.25em;
|
||||
}
|
||||
@@ -1409,8 +1418,12 @@ combobox entry + button:not(.dummy) {
|
||||
border-bottom-left-radius: 0;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
#PlacesPaned button.combo {
|
||||
margin: 0 0 calc(0.416666666666666666em - 8px) 0;
|
||||
margin: 0;
|
||||
}
|
||||
#PlacesPaned combobox {
|
||||
margin-bottom: calc(0.416666666666666666em - 8px);
|
||||
}
|
||||
|
||||
/* Reset button */
|
||||
@@ -1435,14 +1448,15 @@ colorchooser colorswatch#add-color-button:first-child {
|
||||
}
|
||||
|
||||
/* Save, Cancel, OK ... buttons */
|
||||
.dialog-action-area button {
|
||||
dialog .dialog-action-area button {
|
||||
min-height: 2.166666666666666666em;
|
||||
margin-top: 1em;
|
||||
margin: 0.5em 0 0 0.333333333333333333em;
|
||||
padding: 0;
|
||||
}
|
||||
messagedialog .dialog-action-area button {
|
||||
min-height: 1.833333333333333333em;
|
||||
margin: -12px 0.5em 0.5em 0.5em;
|
||||
margin: -12px 0.5em 0.5em;
|
||||
padding: 0;
|
||||
}
|
||||
messagedialog .dialog-action-area button:not(:only-child):nth-child(1) {
|
||||
margin-right: 0.25em;
|
||||
@@ -1789,7 +1803,7 @@ radio:disabled {
|
||||
|
||||
radiobutton label,
|
||||
checkbutton label {
|
||||
margin: 0 0 0 0.416666666666666666em;
|
||||
margin: 0 0.416666666666666666em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ set(RTENGINESOURCEFILES
|
||||
guidedfilter.cc
|
||||
ipdehaze.cc
|
||||
iplabregions.cc
|
||||
lj92.c
|
||||
)
|
||||
|
||||
if(LENSFUN_HAS_LOAD_DIRECTORY)
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
/*RT*/#define LOCALTIME
|
||||
/*RT*/#define DJGPP
|
||||
/*RT*/#include "jpeg.h"
|
||||
/*RT*/#include "lj92.h"
|
||||
/*RT*/#ifdef _OPENMP
|
||||
/*RT*/#include <omp.h>
|
||||
/*RT*/#endif
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -1124,6 +1128,64 @@ void CLASS ljpeg_idct (struct jhead *jh)
|
||||
FORC(64) jh->idct[c] = CLIP(((float *)work[2])[c]+0.5);
|
||||
}
|
||||
|
||||
void CLASS lossless_dnglj92_load_raw()
|
||||
{
|
||||
BENCHFUN
|
||||
|
||||
tiff_bps = 16;
|
||||
|
||||
int save = ifp->pos;
|
||||
uint16_t *lincurve = !strncmp(make,"Blackmagic",10) ? curve : nullptr;
|
||||
tile_width = tile_length < INT_MAX ? tile_width : raw_width;
|
||||
size_t tileCount = raw_width / tile_width;
|
||||
|
||||
size_t dataOffset[tileCount];
|
||||
if(tile_length < INT_MAX) {
|
||||
for (size_t t = 0; t < tileCount; ++t) {
|
||||
dataOffset[t] = get4();
|
||||
}
|
||||
} else {
|
||||
dataOffset[0] = ifp->pos;
|
||||
}
|
||||
uint8_t *data = (uint8_t*)malloc(ifp->size);
|
||||
fseek(ifp, 0, SEEK_SET);
|
||||
// read whole file
|
||||
int data_length = ifp->size;
|
||||
fread(data, 1, data_length, ifp);
|
||||
lj92 lj;
|
||||
int newwidth, newheight, newbps;
|
||||
lj92_open(&lj, &data[dataOffset[0]], data_length, &newwidth, &newheight, &newbps);
|
||||
lj92_close(lj);
|
||||
if (newwidth * newheight * tileCount != raw_width * raw_height) {
|
||||
// not a lj92 file
|
||||
fseek(ifp, save, SEEK_SET);
|
||||
free(data);
|
||||
lossless_dng_load_raw();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel for num_threads(std::min<int>(tileCount, omp_get_max_threads()))
|
||||
#endif
|
||||
for (size_t t = 0; t < tileCount; ++t) {
|
||||
size_t tcol = t * tile_width;
|
||||
lj92 lj;
|
||||
int newwidth, newheight, newbps;
|
||||
lj92_open(&lj, &data[dataOffset[t]], data_length, &newwidth, &newheight, &newbps);
|
||||
|
||||
uint16_t *target = (uint16_t*)malloc(newwidth * newheight * sizeof *target);
|
||||
lj92_decode(lj, target, tile_width, 0, lincurve, 0x1000);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for(int x = 0; x < tile_width; ++x) {
|
||||
RAW(y, x + tcol) = target[y * tile_width + x];
|
||||
}
|
||||
}
|
||||
lj92_close(lj);
|
||||
free(target);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
void CLASS lossless_dng_load_raw()
|
||||
{
|
||||
unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j;
|
||||
@@ -9280,7 +9342,7 @@ void CLASS identify()
|
||||
switch (tiff_compress) {
|
||||
case 0:
|
||||
case 1: load_raw = &CLASS packed_dng_load_raw; break;
|
||||
case 7: load_raw = &CLASS lossless_dng_load_raw; break;
|
||||
case 7: load_raw = (!strncmp(make,"Blackmagic",10) || !strncmp(make,"Canon",5)) ? &CLASS lossless_dnglj92_load_raw : &CLASS lossless_dng_load_raw; break;
|
||||
case 8: load_raw = &CLASS deflate_dng_load_raw; break;
|
||||
case 34892: load_raw = &CLASS lossy_dng_load_raw; break;
|
||||
default: load_raw = 0;
|
||||
|
||||
@@ -290,6 +290,7 @@ void ljpeg_idct (struct jhead *jh);
|
||||
void canon_sraw_load_raw();
|
||||
void adobe_copy_pixel (unsigned row, unsigned col, ushort **rp);
|
||||
void lossless_dng_load_raw();
|
||||
void lossless_dnglj92_load_raw();
|
||||
void packed_dng_load_raw();
|
||||
void deflate_dng_load_raw();
|
||||
void init_fuji_compr(struct fuji_compressed_params* info);
|
||||
|
||||
@@ -161,6 +161,13 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory*
|
||||
model = "Unknown";
|
||||
}
|
||||
|
||||
if (model == "Unknown") {
|
||||
tag = newFrameRootDir->findTag("UniqueCameraModel");
|
||||
if (tag) {
|
||||
model = tag->valueToString();
|
||||
}
|
||||
}
|
||||
|
||||
tag = newFrameRootDir->findTagUpward("Orientation");
|
||||
|
||||
if (tag) {
|
||||
|
||||
@@ -1079,6 +1079,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
|
||||
hListener->histogramChanged(histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve, histCCurve, /*histCLurve, histLLCurve,*/ histLCAM, histCCAM, histRedRaw, histGreenRaw, histBlueRaw, histChroma, histLRETI);
|
||||
}
|
||||
}
|
||||
if (orig_prev != oprevi) {
|
||||
delete oprevi;
|
||||
oprevi = nullptr;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
696
rtengine/lj92.c
Normal file
696
rtengine/lj92.c
Normal file
@@ -0,0 +1,696 @@
|
||||
/*
|
||||
lj92.c
|
||||
(c) Andrew Baldwin 2014
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lj92.h"
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
|
||||
//#define SLOW_HUFF
|
||||
//#define DEBUG
|
||||
|
||||
typedef struct _ljp {
|
||||
u8* data;
|
||||
u8* dataend;
|
||||
int datalen;
|
||||
int scanstart;
|
||||
int ix;
|
||||
int x; // Width
|
||||
int y; // Height
|
||||
int bits; // Bit depth
|
||||
int writelen; // Write rows this long
|
||||
int skiplen; // Skip this many values after each row
|
||||
u16* linearize; // Linearization table
|
||||
int linlen;
|
||||
int sssshist[16];
|
||||
|
||||
// Huffman table - only one supported, and probably needed
|
||||
#ifdef SLOW_HUFF
|
||||
int* maxcode;
|
||||
int* mincode;
|
||||
int* valptr;
|
||||
u8* huffval;
|
||||
int* huffsize;
|
||||
int* huffcode;
|
||||
#else
|
||||
u16* hufflut;
|
||||
int huffbits;
|
||||
#endif
|
||||
// Parse state
|
||||
int cnt;
|
||||
u32 b;
|
||||
u16* image;
|
||||
u16* rowcache;
|
||||
u16* outrow[2];
|
||||
} ljp;
|
||||
|
||||
static int find(ljp* self) {
|
||||
int ix = self->ix;
|
||||
u8* data = self->data;
|
||||
while (data[ix] != 0xFF && ix<(self->datalen-1)) {
|
||||
ix += 1;
|
||||
}
|
||||
ix += 2;
|
||||
if (ix>=self->datalen) return -1;
|
||||
self->ix = ix;
|
||||
return data[ix-1];
|
||||
}
|
||||
|
||||
#define BEH(ptr) ((((int)(*&ptr))<<8)|(*(&ptr+1)))
|
||||
|
||||
static int parseHuff(ljp* self) {
|
||||
int ret = LJ92_ERROR_CORRUPT;
|
||||
u8* huffhead = &self->data[self->ix]; // xstruct.unpack('>HB16B',self.data[self.ix:self.ix+19])
|
||||
u8* bits = &huffhead[2];
|
||||
bits[0] = 0; // Because table starts from 1
|
||||
int hufflen = BEH(huffhead[0]);
|
||||
if ((self->ix + hufflen) >= self->datalen) return ret;
|
||||
#ifdef SLOW_HUFF
|
||||
u8* huffval = calloc(hufflen - 19,sizeof(u8));
|
||||
if (huffval == NULL) return LJ92_ERROR_NO_MEMORY;
|
||||
self->huffval = huffval;
|
||||
for (int hix=0;hix<(hufflen-19);hix++) {
|
||||
huffval[hix] = self->data[self->ix+19+hix];
|
||||
#ifdef DEBUG
|
||||
printf("huffval[%d]=%d\n",hix,huffval[hix]);
|
||||
#endif
|
||||
}
|
||||
self->ix += hufflen;
|
||||
// Generate huffman table
|
||||
int k = 0;
|
||||
int i = 1;
|
||||
int j = 1;
|
||||
int huffsize_needed = 1;
|
||||
// First calculate how long huffsize needs to be
|
||||
while (i<=16) {
|
||||
while (j<=bits[i]) {
|
||||
huffsize_needed++;
|
||||
k = k+1;
|
||||
j = j+1;
|
||||
}
|
||||
i = i+1;
|
||||
j = 1;
|
||||
}
|
||||
// Now allocate and do it
|
||||
int* huffsize = calloc(huffsize_needed,sizeof(int));
|
||||
if (huffsize == NULL) return LJ92_ERROR_NO_MEMORY;
|
||||
self->huffsize = huffsize;
|
||||
k = 0;
|
||||
i = 1;
|
||||
j = 1;
|
||||
// First calculate how long huffsize needs to be
|
||||
int hsix = 0;
|
||||
while (i<=16) {
|
||||
while (j<=bits[i]) {
|
||||
huffsize[hsix++] = i;
|
||||
k = k+1;
|
||||
j = j+1;
|
||||
}
|
||||
i = i+1;
|
||||
j = 1;
|
||||
}
|
||||
huffsize[hsix++] = 0;
|
||||
|
||||
// Calculate the size of huffcode array
|
||||
int huffcode_needed = 0;
|
||||
k = 0;
|
||||
int code = 0;
|
||||
int si = huffsize[0];
|
||||
while (1) {
|
||||
while (huffsize[k] == si) {
|
||||
huffcode_needed++;
|
||||
code = code+1;
|
||||
k = k+1;
|
||||
}
|
||||
if (huffsize[k] == 0)
|
||||
break;
|
||||
while (huffsize[k] != si) {
|
||||
code = code << 1;
|
||||
si = si + 1;
|
||||
}
|
||||
}
|
||||
// Now fill it
|
||||
int* huffcode = calloc(huffcode_needed,sizeof(int));
|
||||
if (huffcode == NULL) return LJ92_ERROR_NO_MEMORY;
|
||||
self->huffcode = huffcode;
|
||||
int hcix = 0;
|
||||
k = 0;
|
||||
code = 0;
|
||||
si = huffsize[0];
|
||||
while (1) {
|
||||
while (huffsize[k] == si) {
|
||||
huffcode[hcix++] = code;
|
||||
code = code+1;
|
||||
k = k+1;
|
||||
}
|
||||
if (huffsize[k] == 0)
|
||||
break;
|
||||
while (huffsize[k] != si) {
|
||||
code = code << 1;
|
||||
si = si + 1;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
|
||||
int* maxcode = calloc(17,sizeof(int));
|
||||
if (maxcode == NULL) return LJ92_ERROR_NO_MEMORY;
|
||||
self->maxcode = maxcode;
|
||||
int* mincode = calloc(17,sizeof(int));
|
||||
if (mincode == NULL) return LJ92_ERROR_NO_MEMORY;
|
||||
self->mincode = mincode;
|
||||
int* valptr = calloc(17,sizeof(int));
|
||||
if (valptr == NULL) return LJ92_ERROR_NO_MEMORY;
|
||||
self->valptr = valptr;
|
||||
|
||||
while (1) {
|
||||
while (1) {
|
||||
i++;
|
||||
if (i>16)
|
||||
break;
|
||||
if (bits[i]!=0)
|
||||
break;
|
||||
maxcode[i] = -1;
|
||||
}
|
||||
if (i>16)
|
||||
break;
|
||||
valptr[i] = j;
|
||||
mincode[i] = huffcode[j];
|
||||
j = j+bits[i]-1;
|
||||
maxcode[i] = huffcode[j];
|
||||
j++;
|
||||
}
|
||||
free(huffsize);
|
||||
self->huffsize = NULL;
|
||||
free(huffcode);
|
||||
self->huffcode = NULL;
|
||||
ret = LJ92_ERROR_NONE;
|
||||
#else
|
||||
/* Calculate huffman direct lut */
|
||||
// How many bits in the table - find highest entry
|
||||
u8* huffvals = &self->data[self->ix+19];
|
||||
int maxbits = 16;
|
||||
while (maxbits>0) {
|
||||
if (bits[maxbits]) break;
|
||||
maxbits--;
|
||||
}
|
||||
self->huffbits = maxbits;
|
||||
/* Now fill the lut */
|
||||
u16* hufflut = (u16*)malloc((1<<maxbits) * sizeof(u16));
|
||||
if (hufflut == NULL) return LJ92_ERROR_NO_MEMORY;
|
||||
self->hufflut = hufflut;
|
||||
int i = 0;
|
||||
int hv = 0;
|
||||
int rv = 0;
|
||||
int vl = 0; // i
|
||||
int hcode;
|
||||
int bitsused = 1;
|
||||
#ifdef DEBUG
|
||||
printf("%04x:%x:%d:%x\n",i,huffvals[hv],bitsused,1<<(maxbits-bitsused));
|
||||
#endif
|
||||
while (i<1<<maxbits) {
|
||||
if (bitsused>maxbits) {
|
||||
break; // Done. Should never get here!
|
||||
}
|
||||
if (vl >= bits[bitsused]) {
|
||||
bitsused++;
|
||||
vl = 0;
|
||||
continue;
|
||||
}
|
||||
if (rv == 1 << (maxbits-bitsused)) {
|
||||
rv = 0;
|
||||
vl++;
|
||||
hv++;
|
||||
#ifdef DEBUG
|
||||
printf("%04x:%x:%d:%x\n",i,huffvals[hv],bitsused,1<<(maxbits-bitsused));
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
hcode = huffvals[hv];
|
||||
hufflut[i] = hcode<<8 | bitsused;
|
||||
//printf("%d %d %d\n",i,bitsused,hcode);
|
||||
i++;
|
||||
rv++;
|
||||
}
|
||||
ret = LJ92_ERROR_NONE;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parseSof3(ljp* self) {
|
||||
if (self->ix+6 >= self->datalen) return LJ92_ERROR_CORRUPT;
|
||||
self->y = BEH(self->data[self->ix+3]);
|
||||
self->x = BEH(self->data[self->ix+5]);
|
||||
self->bits = self->data[self->ix+2];
|
||||
self->ix += BEH(self->data[self->ix]);
|
||||
return LJ92_ERROR_NONE;
|
||||
}
|
||||
|
||||
static int parseBlock(ljp* self,int marker) {
|
||||
self->ix += BEH(self->data[self->ix]);
|
||||
if (self->ix >= self->datalen) return LJ92_ERROR_CORRUPT;
|
||||
return LJ92_ERROR_NONE;
|
||||
}
|
||||
|
||||
#ifdef SLOW_HUFF
|
||||
static int nextbit(ljp* self) {
|
||||
u32 b = self->b;
|
||||
if (self->cnt == 0) {
|
||||
u8* data = &self->data[self->ix];
|
||||
u32 next = *data++;
|
||||
b = next;
|
||||
if (next == 0xff) {
|
||||
data++;
|
||||
self->ix++;
|
||||
}
|
||||
self->ix++;
|
||||
self->cnt = 8;
|
||||
}
|
||||
int bit = b >> 7;
|
||||
self->cnt--;
|
||||
self->b = (b << 1)&0xFF;
|
||||
return bit;
|
||||
}
|
||||
|
||||
static int decode(ljp* self) {
|
||||
int i = 1;
|
||||
int code = nextbit(self);
|
||||
while (code > self->maxcode[i]) {
|
||||
i++;
|
||||
code = (code << 1) + nextbit(self);
|
||||
}
|
||||
int j = self->valptr[i];
|
||||
j = j + code - self->mincode[i];
|
||||
int value = self->huffval[j];
|
||||
return value;
|
||||
}
|
||||
|
||||
static int receive(ljp* self,int ssss) {
|
||||
int i = 0;
|
||||
int v = 0;
|
||||
while (i != ssss) {
|
||||
i++;
|
||||
v = (v<<1) + nextbit(self);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static int extend(ljp* self,int v,int t) {
|
||||
int vt = 1<<(t-1);
|
||||
if (v < vt) {
|
||||
vt = (-1 << t) + 1;
|
||||
v = v + vt;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline static int nextdiff(ljp* self, int Px) {
|
||||
#ifdef SLOW_HUFF
|
||||
int t = decode(self);
|
||||
int diff = receive(self,t);
|
||||
diff = extend(self,diff,t);
|
||||
//printf("%d %d %d %x\n",Px+diff,Px,diff,t);//,index,usedbits);
|
||||
#else
|
||||
u32 b = self->b;
|
||||
int cnt = self->cnt;
|
||||
int huffbits = self->huffbits;
|
||||
int ix = self->ix;
|
||||
int next;
|
||||
while (cnt < huffbits) {
|
||||
next = *(u16*)&self->data[ix];
|
||||
int one = next&0xFF;
|
||||
int two = next>>8;
|
||||
b = (b<<16)|(one<<8)|two;
|
||||
cnt += 16;
|
||||
ix += 2;
|
||||
if (one==0xFF) {
|
||||
//printf("%x %x %x %x %d\n",one,two,b,b>>8,cnt);
|
||||
b >>= 8;
|
||||
cnt -= 8;
|
||||
} else if (two==0xFF) ix++;
|
||||
}
|
||||
int index = b >> (cnt - huffbits);
|
||||
u16 ssssused = self->hufflut[index];
|
||||
int usedbits = ssssused&0xFF;
|
||||
int t = ssssused>>8;
|
||||
self->sssshist[t]++;
|
||||
cnt -= usedbits;
|
||||
int keepbitsmask = (1 << cnt)-1;
|
||||
b &= keepbitsmask;
|
||||
while (cnt < t) {
|
||||
next = *(u16*)&self->data[ix];
|
||||
int one = next&0xFF;
|
||||
int two = next>>8;
|
||||
b = (b<<16)|(one<<8)|two;
|
||||
cnt += 16;
|
||||
ix += 2;
|
||||
if (one==0xFF) {
|
||||
b >>= 8;
|
||||
cnt -= 8;
|
||||
} else if (two==0xFF) ix++;
|
||||
}
|
||||
cnt -= t;
|
||||
int diff = b >> cnt;
|
||||
int vt = 1<<(t-1);
|
||||
if (diff < vt) {
|
||||
vt = (-1 << t) + 1;
|
||||
diff += vt;
|
||||
}
|
||||
keepbitsmask = (1 << cnt)-1;
|
||||
self->b = b & keepbitsmask;
|
||||
self->cnt = cnt;
|
||||
self->ix = ix;
|
||||
//printf("%d %d\n",t,diff);
|
||||
//printf("%d %d %d %x %x %d\n",Px+diff,Px,diff,t,index,usedbits);
|
||||
#ifdef DEBUG
|
||||
#endif
|
||||
#endif
|
||||
return diff;
|
||||
}
|
||||
|
||||
static int parsePred6(ljp* self) {
|
||||
int ret = LJ92_ERROR_CORRUPT;
|
||||
self->ix = self->scanstart;
|
||||
//int compcount = self->data[self->ix+2];
|
||||
self->ix += BEH(self->data[self->ix]);
|
||||
self->cnt = 0;
|
||||
self->b = 0;
|
||||
int write = self->writelen;
|
||||
// Now need to decode huffman coded values
|
||||
int c = 0;
|
||||
int pixels = self->y * self->x;
|
||||
u16* out = self->image;
|
||||
u16* temprow;
|
||||
u16* thisrow = self->outrow[0];
|
||||
u16* lastrow = self->outrow[1];
|
||||
|
||||
// First pixel predicted from base value
|
||||
int diff;
|
||||
int Px;
|
||||
int col = 0;
|
||||
int row = 0;
|
||||
int left = 0;
|
||||
int linear;
|
||||
|
||||
// First pixel
|
||||
diff = nextdiff(self,0);
|
||||
Px = 1 << (self->bits-1);
|
||||
left = Px + diff;
|
||||
if (self->linearize)
|
||||
linear = self->linearize[left];
|
||||
else
|
||||
linear = left;
|
||||
thisrow[col++] = left;
|
||||
out[c++] = linear;
|
||||
if (self->ix >= self->datalen) return ret;
|
||||
--write;
|
||||
int rowcount = self->x-1;
|
||||
while (rowcount--) {
|
||||
diff = nextdiff(self,0);
|
||||
Px = left;
|
||||
left = Px + diff;
|
||||
if (self->linearize)
|
||||
linear = self->linearize[left];
|
||||
else
|
||||
linear = left;
|
||||
thisrow[col++] = left;
|
||||
out[c++] = linear;
|
||||
//printf("%d %d %d %d %x\n",col-1,diff,left,thisrow[col-1],&thisrow[col-1]);
|
||||
if (self->ix >= self->datalen) return ret;
|
||||
if (--write==0) {
|
||||
out += self->skiplen;
|
||||
write = self->writelen;
|
||||
}
|
||||
}
|
||||
temprow = lastrow;
|
||||
lastrow = thisrow;
|
||||
thisrow = temprow;
|
||||
row++;
|
||||
//printf("%x %x\n",thisrow,lastrow);
|
||||
while (c<pixels) {
|
||||
col = 0;
|
||||
diff = nextdiff(self,0);
|
||||
Px = lastrow[col]; // Use value above for first pixel in row
|
||||
left = Px + diff;
|
||||
if (self->linearize) {
|
||||
if (left>self->linlen) return LJ92_ERROR_CORRUPT;
|
||||
linear = self->linearize[left];
|
||||
} else
|
||||
linear = left;
|
||||
thisrow[col++] = left;
|
||||
//printf("%d %d %d %d\n",col,diff,left,lastrow[col]);
|
||||
out[c++] = linear;
|
||||
if (self->ix >= self->datalen) break;
|
||||
rowcount = self->x-1;
|
||||
if (--write==0) {
|
||||
out += self->skiplen;
|
||||
write = self->writelen;
|
||||
}
|
||||
while (rowcount--) {
|
||||
diff = nextdiff(self,0);
|
||||
Px = lastrow[col] + ((left - lastrow[col-1])>>1);
|
||||
left = Px + diff;
|
||||
//printf("%d %d %d %d %d %x\n",col,diff,left,lastrow[col],lastrow[col-1],&lastrow[col]);
|
||||
if (self->linearize) {
|
||||
if (left>self->linlen) return LJ92_ERROR_CORRUPT;
|
||||
linear = self->linearize[left];
|
||||
} else
|
||||
linear = left;
|
||||
thisrow[col++] = left;
|
||||
out[c++] = linear;
|
||||
if (--write==0) {
|
||||
out += self->skiplen;
|
||||
write = self->writelen;
|
||||
}
|
||||
}
|
||||
temprow = lastrow;
|
||||
lastrow = thisrow;
|
||||
thisrow = temprow;
|
||||
if (self->ix >= self->datalen) break;
|
||||
}
|
||||
if (c >= pixels) ret = LJ92_ERROR_NONE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parseScan(ljp* self) {
|
||||
int ret = LJ92_ERROR_CORRUPT;
|
||||
memset(self->sssshist,0,sizeof(self->sssshist));
|
||||
self->ix = self->scanstart;
|
||||
int compcount = self->data[self->ix+2];
|
||||
int pred = self->data[self->ix+3+2*compcount];
|
||||
if (pred<0 || pred>7) return ret;
|
||||
if (pred==6) return parsePred6(self); // Fast path
|
||||
self->ix += BEH(self->data[self->ix]);
|
||||
self->cnt = 0;
|
||||
self->b = 0;
|
||||
int write = self->writelen;
|
||||
// Now need to decode huffman coded values
|
||||
int c = 0;
|
||||
int pixels = self->y * self->x;
|
||||
u16* out = self->image;
|
||||
u16* thisrow = self->outrow[0];
|
||||
u16* lastrow = self->outrow[1];
|
||||
|
||||
// First pixel predicted from base value
|
||||
int diff;
|
||||
int Px;
|
||||
int col = 0;
|
||||
int row = 0;
|
||||
int left = 0;
|
||||
while (c<pixels) {
|
||||
if ((col==0)&&(row==0)) {
|
||||
Px = 1 << (self->bits-1);
|
||||
} else if (row==0) {
|
||||
Px = left;
|
||||
} else if (col==0) {
|
||||
Px = lastrow[col]; // Use value above for first pixel in row
|
||||
} else {
|
||||
switch (pred) {
|
||||
case 0:
|
||||
Px = 0; break; // No prediction... should not be used
|
||||
case 1:
|
||||
Px = left; break;
|
||||
case 2:
|
||||
Px = lastrow[col]; break;
|
||||
case 3:
|
||||
Px = lastrow[col-1];break;
|
||||
case 4:
|
||||
Px = left + lastrow[col] - lastrow[col-1];break;
|
||||
case 5:
|
||||
Px = left + ((lastrow[col] - lastrow[col-1])>>1);break;
|
||||
case 6:
|
||||
Px = lastrow[col] + ((left - lastrow[col-1])>>1);break;
|
||||
case 7:
|
||||
Px = (left + lastrow[col])>>1;break;
|
||||
}
|
||||
}
|
||||
diff = nextdiff(self,Px);
|
||||
left = Px + diff;
|
||||
//printf("%d %d %d\n",c,diff,left);
|
||||
int linear;
|
||||
if (self->linearize) {
|
||||
if (left>self->linlen) return LJ92_ERROR_CORRUPT;
|
||||
linear = self->linearize[left];
|
||||
} else
|
||||
linear = left;
|
||||
thisrow[col] = left;
|
||||
out[c++] = linear;
|
||||
if (++col==self->x) {
|
||||
col = 0;
|
||||
row++;
|
||||
u16* temprow = lastrow;
|
||||
lastrow = thisrow;
|
||||
thisrow = temprow;
|
||||
}
|
||||
if (--write==0) {
|
||||
out += self->skiplen;
|
||||
write = self->writelen;
|
||||
}
|
||||
if (self->ix >= self->datalen+2) break;
|
||||
}
|
||||
if (c >= pixels) ret = LJ92_ERROR_NONE;
|
||||
/*for (int h=0;h<17;h++) {
|
||||
printf("ssss:%d=%d (%f)\n",h,self->sssshist[h],(float)self->sssshist[h]/(float)(pixels));
|
||||
}*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parseImage(ljp* self) {
|
||||
int ret = LJ92_ERROR_NONE;
|
||||
while (1) {
|
||||
int nextMarker = find(self);
|
||||
if (nextMarker == 0xc4)
|
||||
ret = parseHuff(self);
|
||||
else if (nextMarker == 0xc3)
|
||||
ret = parseSof3(self);
|
||||
else if (nextMarker == 0xfe)// Comment
|
||||
ret = parseBlock(self,nextMarker);
|
||||
else if (nextMarker == 0xd9) // End of image
|
||||
break;
|
||||
else if (nextMarker == 0xda) {
|
||||
self->scanstart = self->ix;
|
||||
ret = LJ92_ERROR_NONE;
|
||||
break;
|
||||
} else if (nextMarker == -1) {
|
||||
ret = LJ92_ERROR_CORRUPT;
|
||||
break;
|
||||
} else
|
||||
ret = parseBlock(self,nextMarker);
|
||||
if (ret != LJ92_ERROR_NONE) break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int findSoI(ljp* self) {
|
||||
int ret = LJ92_ERROR_CORRUPT;
|
||||
if (find(self)==0xd8)
|
||||
ret = parseImage(self);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void free_memory(ljp* self) {
|
||||
#ifdef SLOW_HUFF
|
||||
free(self->maxcode);
|
||||
self->maxcode = NULL;
|
||||
free(self->mincode);
|
||||
self->mincode = NULL;
|
||||
free(self->valptr);
|
||||
self->valptr = NULL;
|
||||
free(self->huffval);
|
||||
self->huffval = NULL;
|
||||
free(self->huffsize);
|
||||
self->huffsize = NULL;
|
||||
free(self->huffcode);
|
||||
self->huffcode = NULL;
|
||||
#else
|
||||
free(self->hufflut);
|
||||
self->hufflut = NULL;
|
||||
#endif
|
||||
free(self->rowcache);
|
||||
self->rowcache = NULL;
|
||||
}
|
||||
|
||||
int lj92_open(lj92* lj,
|
||||
uint8_t* data, int datalen,
|
||||
int* width,int* height, int* bitdepth) {
|
||||
ljp* self = (ljp*)calloc(sizeof(ljp),1);
|
||||
if (self==NULL) return LJ92_ERROR_NO_MEMORY;
|
||||
|
||||
self->data = (u8*)data;
|
||||
self->dataend = self->data + datalen;
|
||||
self->datalen = datalen;
|
||||
|
||||
int ret = findSoI(self);
|
||||
|
||||
if (ret == LJ92_ERROR_NONE) {
|
||||
u16* rowcache = (u16*)calloc(self->x * 2,sizeof(u16));
|
||||
if (rowcache == NULL) ret = LJ92_ERROR_NO_MEMORY;
|
||||
else {
|
||||
self->rowcache = rowcache;
|
||||
self->outrow[0] = rowcache;
|
||||
self->outrow[1] = &rowcache[self->x];
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != LJ92_ERROR_NONE) { // Failed, clean up
|
||||
*lj = NULL;
|
||||
free_memory(self);
|
||||
free(self);
|
||||
} else {
|
||||
*width = self->x;
|
||||
*height = self->y;
|
||||
*bitdepth = self->bits;
|
||||
*lj = self;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int lj92_decode(lj92 lj,
|
||||
uint16_t* target,int writeLength, int skipLength,
|
||||
uint16_t* linearize,int linearizeLength) {
|
||||
int ret = LJ92_ERROR_NONE;
|
||||
ljp* self = lj;
|
||||
if (self == NULL) return LJ92_ERROR_BAD_HANDLE;
|
||||
self->image = target;
|
||||
self->writelen = writeLength;
|
||||
self->skiplen = skipLength;
|
||||
self->linearize = linearize;
|
||||
self->linlen = linearizeLength;
|
||||
ret = parseScan(self);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lj92_close(lj92 lj) {
|
||||
ljp* self = lj;
|
||||
if (self != NULL)
|
||||
free_memory(self);
|
||||
free(self);
|
||||
}
|
||||
68
rtengine/lj92.h
Normal file
68
rtengine/lj92.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
lj92.h
|
||||
(c) Andrew Baldwin 2014
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LJ92_H
|
||||
#define LJ92_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
enum LJ92_ERRORS {
|
||||
LJ92_ERROR_NONE = 0,
|
||||
LJ92_ERROR_CORRUPT = -1,
|
||||
LJ92_ERROR_NO_MEMORY = -2,
|
||||
LJ92_ERROR_BAD_HANDLE = -3,
|
||||
LJ92_ERROR_TOO_WIDE = -4,
|
||||
};
|
||||
|
||||
typedef struct _ljp* lj92;
|
||||
|
||||
/* Parse a lossless JPEG (1992) structure returning
|
||||
* - a handle that can be used to decode the data
|
||||
* - width/height/bitdepth of the data
|
||||
* Returns status code.
|
||||
* If status == LJ92_ERROR_NONE, handle must be closed with lj92_close
|
||||
*/
|
||||
int lj92_open(lj92* lj, // Return handle here
|
||||
uint8_t* data,int datalen, // The encoded data
|
||||
int* width,int* height,int* bitdepth); // Width, height and bitdepth
|
||||
|
||||
/* Release a decoder object */
|
||||
void lj92_close(lj92 lj);
|
||||
|
||||
/*
|
||||
* Decode previously opened lossless JPEG (1992) into a 2D tile of memory
|
||||
* Starting at target, write writeLength 16bit values, then skip 16bit skipLength value before writing again
|
||||
* If linearize is not NULL, use table at linearize to convert data values from output value to target value
|
||||
* Data is only correct if LJ92_ERROR_NONE is returned
|
||||
*/
|
||||
int lj92_decode(lj92 lj,
|
||||
uint16_t* target, int writeLength, int skipLength, // The image is written to target as a tile
|
||||
uint16_t* linearize, int linearizeLength); // If not null, linearize the data using this table
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -64,7 +64,7 @@ std::vector<Glib::ustring> listSubDirs (const Glib::RefPtr<Gio::File>& dir, bool
|
||||
} catch (const Glib::Exception& exception) {
|
||||
|
||||
if (options.rtSettings.verbose) {
|
||||
std::cerr << exception.what () << std::endl;
|
||||
std::cerr << exception.what().c_str() << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1208,7 +1208,7 @@ Gtk::Widget* Preferences::getFileBrowserPanel()
|
||||
startupdir = Gtk::manage(new Gtk::Entry());
|
||||
|
||||
Gtk::Button* sdselect = Gtk::manage(new Gtk::Button());
|
||||
sdselect->set_image (*Gtk::manage (new RTImage ("folder-open.png")));
|
||||
sdselect->set_image (*Gtk::manage (new RTImage ("folder-open-small.png")));
|
||||
|
||||
Gtk::RadioButton::Group opts = sdcurrent->get_group();
|
||||
sdlast->set_group(opts);
|
||||
@@ -1277,20 +1277,26 @@ Gtk::Widget* Preferences::getFileBrowserPanel()
|
||||
|
||||
|
||||
Gtk::Frame* frmnu = Gtk::manage(new Gtk::Frame(M("PREFERENCES_MENUOPTIONS")));
|
||||
|
||||
Gtk::Grid* menuGrid = Gtk::manage(new Gtk::Grid());
|
||||
menuGrid->get_style_context()->add_class("grid-spacing");
|
||||
setExpandAlignProperties(menuGrid, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
|
||||
|
||||
ckbmenuGroupRank = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_MENUGROUPRANK")));
|
||||
setExpandAlignProperties(ckbmenuGroupRank, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
|
||||
ckbmenuGroupLabel = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_MENUGROUPLABEL")));
|
||||
ckbmenuGroupFileOperations = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_MENUGROUPFILEOPERATIONS")));
|
||||
setExpandAlignProperties(ckbmenuGroupFileOperations, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
|
||||
ckbmenuGroupProfileOperations = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_MENUGROUPPROFILEOPERATIONS")));
|
||||
ckbmenuGroupExtProg = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_MENUGROUPEXTPROGS")));
|
||||
Gtk::VBox* vbmnu = Gtk::manage(new Gtk::VBox());
|
||||
|
||||
menuGrid->attach (*ckbmenuGroupRank, 0, 0, 1, 1);
|
||||
menuGrid->attach (*ckbmenuGroupLabel, 1, 0, 1, 1);
|
||||
menuGrid->attach (*ckbmenuGroupFileOperations, 0, 1, 1, 1);
|
||||
menuGrid->attach (*ckbmenuGroupProfileOperations, 1, 1, 1, 1);
|
||||
menuGrid->attach (*ckbmenuGroupExtProg, 0, 2, 2, 1);
|
||||
|
||||
vbmnu->pack_start(*ckbmenuGroupRank, Gtk::PACK_SHRINK, 0);
|
||||
vbmnu->pack_start(*ckbmenuGroupLabel, Gtk::PACK_SHRINK, 0);
|
||||
vbmnu->pack_start(*ckbmenuGroupFileOperations, Gtk::PACK_SHRINK, 0);
|
||||
vbmnu->pack_start(*ckbmenuGroupProfileOperations, Gtk::PACK_SHRINK, 0);
|
||||
vbmnu->pack_start(*ckbmenuGroupExtProg, Gtk::PACK_SHRINK, 0);
|
||||
|
||||
frmnu->add(*vbmnu);
|
||||
frmnu->add (*menuGrid);
|
||||
|
||||
|
||||
Gtk::Frame* fre = Gtk::manage(new Gtk::Frame(M("PREFERENCES_PARSEDEXT")));
|
||||
@@ -1362,7 +1368,8 @@ Gtk::Widget* Preferences::getFileBrowserPanel()
|
||||
|
||||
// Separation is needed so that a button is not accidentally clicked when one wanted
|
||||
// to click a spinbox. Ideally, the separation wouldn't require attaching a widget, but how?
|
||||
Gtk::Label *separator = Gtk::manage (new Gtk::Label());
|
||||
Gtk::HSeparator *cacheSeparator = Gtk::manage (new Gtk::HSeparator());
|
||||
cacheSeparator->get_style_context()->add_class("grid-row-separator");
|
||||
|
||||
Gtk::Label* clearThumbsLbl = Gtk::manage (new Gtk::Label(M("PREFERENCES_CACHECLEAR_ALLBUTPROFILES")));
|
||||
setExpandAlignProperties(clearThumbsLbl, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
|
||||
@@ -1380,7 +1387,7 @@ Gtk::Widget* Preferences::getFileBrowserPanel()
|
||||
cacheGrid->attach (*maxThumbHeightSB, 1, 0, 1, 1);
|
||||
cacheGrid->attach (*maxCacheEntriesLbl, 0, 1, 1, 1);
|
||||
cacheGrid->attach (*maxCacheEntriesSB, 1, 1, 1, 1);
|
||||
cacheGrid->attach (*separator, 0, 2, 2, 1);
|
||||
cacheGrid->attach (*cacheSeparator, 0, 2, 2, 1);
|
||||
cacheGrid->attach (*clearThumbsLbl, 0, 3, 1, 1);
|
||||
cacheGrid->attach (*clearThumbsBtn, 1, 3, 1, 1);
|
||||
if (moptions.saveParamsCache) {
|
||||
|
||||
Reference in New Issue
Block a user