Files
libgphoto2/camlibs/mars/mars.c
axxel f41df32817 fix white-space and indentation inconsistencies (second round)
This is basically a continuation of the work from #1002 but her for the
camlibs directory. The purpose was to replace spaces as a means for
indentation with tab characters.

Note: there are some files which are still offending the general
rule but are (mostly) consistent within themselves. I let them be for
the moment. Fixing them would basically replace the whole file.

Also: there are still a ton of whitespace related inconsistencies like
"x=10" vs "x = 10" or "func(10)" vs "func (10)".

This is a whitespace only change (if you include newlines as whitespace).
2024-09-15 10:53:41 +02:00

555 lines
13 KiB
C

/* mars.c
*
* Copyright (C) 2004 Theodore Kilgore <kilgota@auburn.edu>
*
* white_balance() Copyright (C) 2008 Theodore Kilgore and Amauri Magagna.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#define _DEFAULT_SOURCE
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <libgphoto2/gamma.h>
#include <gphoto2/gphoto2.h>
#include <gphoto2/gphoto2-port.h>
#include "libgphoto2/gphoto2-endian.h"
#include "mars.h"
#define GP_MODULE "mars"
#define INIT 0xb5
#define GET_DATA 0x0f
static int
m_read (GPPort *port, char *data, int size)
{
int ret;
ret = gp_port_write(port, "\x21", 1);
if (ret < GP_OK) return ret;
return gp_port_read(port, data, 16);
}
static int
m_command (GPPort *port, char *command, int size, char *response)
{
gp_port_write(port, command, size);
return m_read(port, response, 16);
}
static int mars_routine (Info *info, GPPort *port, char param, int n);
int
mars_init (Camera *camera, GPPort *port, Info *info)
{
char c[16];
unsigned char status = 0;
memset(info,0, sizeof(*info));
memset(c,0,sizeof(c));
GP_DEBUG("Running mars_init\n");
/* Init routine done twice, usually. First time is a dry run. But if
* camera reports 0x02 it is "jammed" and we must clear it.
*/
m_read(port, c, 16);
if (c[0] == 0x02) {
gp_port_write(port, "\x19", 1);
gp_port_read(port, c, 16);
}
else {
status = mars_routine (info, port, INIT, 0);
GP_DEBUG("status = 0x%x\n", status);
}
/* Not a typo. This _will_ download the config data ;) */
mars_read_picture_data (camera, info, port, (char *)info, 0x2000, 0);
/* Removing extraneous line(s) of data. See "protocol.txt" */
if ((info[0] == 0xff)&& (info[1] == 0)&&(info[2]==0xff))
memmove(info, info + 16, 0x1ff0); /* Saving config */
else
memmove(info, info + 144, 0x1f70); /* Saving config */
GP_DEBUG("Leaving mars_init\n");
return GP_OK;
}
int
mars_get_num_pics (Info *info)
{
unsigned int i = 0;
for (i = 0; i < 0x3fe; i++)
if ( !(0xff - info[8*i]) ) {
GP_DEBUG ( "i is %i\n", i);
memcpy(info+0x1ff0, "i", 1);
return i;
}
memcpy(info+0x1ff0, "0", 1);
return 0;
}
int
mars_get_pic_data_size (Info *info, int n)
{
return (info[8*n+6]*0x100 + info[8*n+5])*0x100 + info[8*n+4];
}
static int
set_usb_in_endpoint (Camera *camera, int inep)
{
GPPortSettings settings;
gp_port_get_settings ( camera ->port, &settings);
settings.usb.inep = inep;
GP_DEBUG("inep reset to %02X\n", inep);
return gp_port_set_settings ( camera ->port, settings);
}
static int
mars_read_data (GPPort *port, char *data, int size)
{
int MAX_BULK = 0x2000;
int len = 0;
while(size > 0) {
len = (size>MAX_BULK)?MAX_BULK:size;
gp_port_read (port, data, len);
data += len;
size -= len;
}
return 1;
}
int
mars_read_picture_data (Camera *camera, Info *info, GPPort *port,
char *data, int size, int n)
{
unsigned char c[16];
memset(c,0,sizeof(c));
/*Initialization routine for download. */
mars_routine (info, port, GET_DATA, n);
/*Data transfer begins*/
set_usb_in_endpoint (camera, 0x82);
mars_read_data (port, data, size);
set_usb_in_endpoint (camera, 0x83);
return GP_OK;
}
int
mars_reset (GPPort *port)
{
gp_port_write(port, "\x19\x54", 2);
return GP_OK;
}
static void precalc_table(code_table_t *table)
{
int i;
int is_abs, val, len;
for (i = 0; i < 256; i++) {
is_abs = 0;
val = 0;
len = 0;
if ((i & 0x80) == 0) {
/* code 0 */
val = 0;
len = 1;
}else if ((i & 0xE0) == 0xC0) {
/* code 110 */
val = -3;
len = 3;
}else if ((i & 0xE0) == 0xA0) {
/* code 101 */
val = +3;
len = 3;
}else if ((i & 0xF0) == 0x80) {
/* code 1000 */
val = +8;
len = 4;
}else if ((i & 0xF0) == 0x90) {
/* code 1001 */
val = -8;
len = 4;
}else if ((i & 0xF0) == 0xF0) {
/* code 1111 */
val = -20;
len = 4;
}else if ((i & 0xF8) == 0xE0) {
/* code 11100 */
val = +20;
len = 5;
}else if ((i & 0xF8) == 0xE8) {
/* code 11101xxxxx */
is_abs = 1;
val = 0; /* value is calculated later */
len = 5;
}
table[i].is_abs = is_abs;
table[i].val = val;
table[i].len = len;
}
}
#define CLAMP(x) ((x)<0?0:((x)>255)?255:(x))
#define GET_CODE addr = inp + (bitpos >> 3); \
code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)))
int mars_decompress (unsigned char *inp, unsigned char *outp, int width,
int height)
{
int row, col;
unsigned char code;
int val;
code_table_t table[256];
unsigned char *addr;
int bitpos;
unsigned char lp=0,tp=0,tlp=0,trp=0;
/* First calculate the Huffman table */
precalc_table(table);
bitpos = 0;
/* main decoding loop */
for (row = 0; row < height; row++) {
col = 0;
/* first two pixels in first two rows are stored as raw 8-bit */
if (row < 2) {
GET_CODE;
bitpos += 8;
*outp++ = code;
GET_CODE;
bitpos += 8;
*outp++ = code;
col += 2;
}
while (col < width) {
/* get bitcode */
GET_CODE;
/* update bit position */
bitpos += table[code].len;
/* calculate pixel value */
if (table[code].is_abs) {
/* get 5 more bits and use them as absolute value */
GET_CODE;
val = (code & 0xF8);
bitpos += 5;
} else {
/* value is relative to top or left pixel */
val = table[code].val;
lp = outp[-2];
if (row > 1) {
if (col > 1)
tlp = outp[-2*width-2];
tp = outp[-2*width];
if (col < width-2)
trp = outp[-2*width+2];
}
if (row < 2) {
/* top row: relative to left pixel */
val += lp;
} else if (col < 2) {
/* left column: relative to top pixel */
/* initial estimate */
val += (tp + trp)/2;
} else if (col > width - 3) {
/* left column: relative to top pixel */
val += (tp + lp + tlp +1)/3;
/* main area: average of left and top pixel */
} else {
/* initial estimate for predictor */
tlp>>=1;
trp>>=1;
val += (lp + tp + tlp + trp +1)/3;
}
}
/* store pixel */
*outp++ = CLAMP(val);
col++;
}
}
return GP_OK;
}
static int
mars_routine (Info *info, GPPort *port, char param, int n)
{
char c[16];
char start[2] = {0x19, 0x51};
char do_something[2];
char address1[2];
char address2[2];
char address3[2];
char address4[2];
char address5[2];
char address6[2];
do_something[0]= 0x19;
do_something[1]=param;
/* See protocol.txt for my theories about what these mean. */
address1[0] = 0x19;
address1[1] = info[8*n+1];
address2[0] = 0x19;
address2[1] = info[8*n+2];
address3[0] = 0x19;
address3[1] = info[8*n+3];
address4[0] = 0x19;
address4[1] = info[8*n+4];
address5[0] = 0x19;
address5[1] = info[8*n+5];
address6[0] = 0x19;
address6[1] = info[8*n+6];
memset(c,0,sizeof(c));
/*Routine used in initialization, photo download, and reset. */
m_read(port, c, 16);
m_command(port, start, 2, c);
m_command(port, do_something, 2, c);
m_command(port, address1, 2, c);
c[0] = 0;
gp_port_write(port, address2, 2);
/* Moving the memory cursor to the given address? */
while ((c[0] != 0xa)) {
if (m_read(port, c, 16) < 16)
break;
}
m_command(port, address3, 2, c);
m_command(port, address4, 2, c);
m_command(port, address5, 2, c);
m_command(port, address6, 2, c);
gp_port_write(port, "\x19", 1);
gp_port_read(port, c , 16);
/* Next thing is to switch the inep. Some cameras need a pause here */
usleep (MARS_SLEEP);
return(c[0]);
}
/*
* ========= White Balance / Color Enhance / Gamma adjust ===============
*
* Get histogram for each color plane
* Expand to reach 0.5% of white dots in image
*
* Get new histogram for each color plane
* Expand to reach 0.5% of black dots in image
*
* Get new histogram
* Calculate and apply gamma correction
*
* if not a dark image:
* For each dot, increases color separation
*
* ======================================================================
*/
int
histogram (unsigned char *data, unsigned int size, int *htable_r, int *htable_g, int *htable_b)
{
unsigned int x;
/* Initializations */
for (x = 0; x < 0x100; x++) {
htable_r[x] = 0;
htable_g[x] = 0;
htable_b[x] = 0;
}
/* Building the histograms */
for (x = 0; x < (size * 3); x += 3)
{
htable_r[data[x+0]]++; /* red histogram */
htable_g[data[x+1]]++; /* green histogram */
htable_b[data[x+2]]++; /* blue histogram */
}
return 0;
}
int
mars_white_balance (unsigned char *data, unsigned int size, float saturation,
float image_gamma)
{
unsigned int x, max;
int r, g, b, d;
double r_factor, g_factor, b_factor, max_factor;
int htable_r[0x100], htable_g[0x100], htable_b[0x100];
unsigned char gtable[0x100];
double new_gamma, gamma=1.0;
/* ------------------- GAMMA CORRECTION ------------------- */
histogram(data, size, htable_r, htable_g, htable_b);
x = 1;
for (d = 48; d < 208; d++)
{
x += htable_r[d];
x += htable_g[d];
x += htable_b[d];
}
new_gamma = sqrt((double) (x * 1.5) / (double) (size * 3));
x=0;
GP_DEBUG("Provisional gamma correction = %1.2f\n", new_gamma);
/* Recalculate saturation factor for later use. */
saturation=saturation*new_gamma*new_gamma;
GP_DEBUG("saturation = %1.2f\n", saturation);
if(new_gamma >= 1.0)
gamma = new_gamma;
else
gamma = image_gamma;
GP_DEBUG("Gamma correction = %1.2f\n", gamma);
gp_gamma_fill_table(gtable, gamma);
/* ---------------- BRIGHT DOTS ------------------- */
max = size / 200;
histogram(data, size, htable_r, htable_g, htable_b);
for (r=0xfe, x=0; (r > 32) && (x < max); r--)
x += htable_r[r];
for (g=0xfe, x=0; (g > 32) && (x < max); g--)
x += htable_g[g];
for (b=0xfe, x=0; (b > 32) && (x < max); b--)
x += htable_b[b];
r_factor = (double) 0xfd / r;
g_factor = (double) 0xfd / g;
b_factor = (double) 0xfd / b;
max_factor = r_factor;
if (g_factor > max_factor) max_factor = g_factor;
if (b_factor > max_factor) max_factor = b_factor;
if (max_factor >= 2.5) {
r_factor = (r_factor / max_factor) * 2.5;
g_factor = (g_factor / max_factor) * 2.5;
b_factor = (b_factor / max_factor) * 2.5;
}
GP_DEBUG("White balance (bright): r=%1d, g=%1d, b=%1d, fr=%1.3f, fg=%1.3f, fb=%1.3f\n", r, g, b, r_factor, g_factor, b_factor);
if (max_factor <= 2.5) {
for (x = 0; x < (size * 3); x += 3)
{
d = (data[x+0]<<8) * r_factor;
d >>=8;
if (d > 0xff) { d = 0xff; }
data[x+0] = d;
d = (data[x+1]<<8) * g_factor;
d >>=8;
if (d > 0xff) { d = 0xff; }
data[x+1] = d;
d = (data[x+2]<<8) * b_factor;
d >>=8;
if (d > 0xff) { d = 0xff; }
data[x+2] = d;
}
}
/* ---------------- DARK DOTS ------------------- */
max = size / 200; /* 1/200 = 0.5% */
histogram(data, size, htable_r, htable_g, htable_b);
for (r=0, x=0; (r < 96) && (x < max); r++)
x += htable_r[r];
for (g=0, x=0; (g < 96) && (x < max); g++)
x += htable_g[g];
for (b=0, x=0; (b < 96) && (x < max); b++)
x += htable_b[b];
r_factor = (double) 0xfe / (0xff-r);
g_factor = (double) 0xfe / (0xff-g);
b_factor = (double) 0xfe / (0xff-b);
max_factor = r_factor;
if (g_factor > max_factor) max_factor = g_factor;
if (b_factor > max_factor) max_factor = b_factor;
if (max_factor >= 1.15) {
r_factor = (r_factor / max_factor) * 1.15;
g_factor = (g_factor / max_factor) * 1.15;
b_factor = (b_factor / max_factor) * 1.15;
}
GP_DEBUG(
"White balance (dark): r=%1d, g=%1d, b=%1d, fr=%1.3f, fg=%1.3f, fb=%1.3f\n",
r, g, b, r_factor, g_factor, b_factor);
for (x = 0; x < (size * 3); x += 3)
{
d = (int) 0xff08-(((0xff-data[x+0])<<8) * r_factor);
d >>= 8;
if (d < 0) { d = 0; }
data[x+0] = d;
d = (int) 0xff08-(((0xff-data[x+1])<<8) * g_factor);
d >>= 8;
if (d < 0) { d = 0; }
data[x+1] = d;
d = (int) 0xff08-(((0xff-data[x+2])<<8) * b_factor);
d >>= 8;
if (d < 0) { d = 0; }
data[x+2] = d;
}
/* ------------------ COLOR ENHANCE ------------------ */
if(saturation > 0.0) {
for (x = 0; x < (size * 3); x += 3)
{
r = data[x+0]; g = data[x+1]; b = data[x+2];
d = (int) (r + g + b) /3.;
if ( r > d )
r = r + (int) ((r - d) * (0xff-r)/(0x100-d) * saturation);
else
r = r + (int) ((r - d) * (0xff-d)/(0x100-r) * saturation);
if (g > d)
g = g + (int) ((g - d) * (0xff-g)/(0x100-d) * saturation);
else
g = g + (int) ((g - d) * (0xff-d)/(0x100-g) * saturation);
if (b > d)
b = b + (int) ((b - d) * (0xff-b)/(0x100-d) * saturation);
else
b = b + (int) ((b - d) * (0xff-d)/(0x100-b) * saturation);
data[x+0] = CLAMP(r);
data[x+1] = CLAMP(g);
data[x+2] = CLAMP(b);
}
}
return 0;
}