Skip to content
Commits on Source (30)
view
cfl2png
viewer.inc
tags
*.swp
......
......@@ -41,7 +41,7 @@ endif
-include Makefile.local
all: view
all: view cfl2png
src/viewer.inc: src/viewer.ui
@echo "STRINGIFY(`cat src/viewer.ui`)" > src/viewer.inc
......@@ -49,10 +49,12 @@ src/viewer.inc: src/viewer.ui
view: src/main.c src/view.[ch] src/draw.[ch] src/viewer.inc
$(CC) $(CFLAGS) $(EXPDYN) -o view -I$(TOOLBOX_INC) `pkg-config --cflags gtk+-3.0` src/main.c src/view.c src/draw.c `pkg-config --libs gtk+-3.0` $(TOOLBOX_LIB)/libmisc.a $(TOOLBOX_LIB)/libnum.a -lm -lpng
cfl2png: src/cfl2png.c src/view.[ch] src/draw.[ch] src/viewer.inc
$(CC) $(CFLAGS) $(EXPDYN) -o cfl2png -I$(TOOLBOX_INC) src/cfl2png.c src/draw.c $(TOOLBOX_LIB)/libmisc.a $(TOOLBOX_LIB)/libnum.a -lm -lpng
install:
install view $(DESTDIR)/usr/lib/bart/commands/
clean:
rm -f view viewer.inc
rm -f view cfl2png viewer.inc
......@@ -6,7 +6,7 @@ the Berkeley Advanced Reconstruction Toolbox (BART).
https://mrirecon.github.io/bart/
Requires BART up to commit e4df99aa75e0344931ba2e76d9ae052b02da498f
Mac OS X:
......
Small image viewer for multi-dimensional files. Compiles
on Linux and Mac OS X. It needs some libraries from
the Berkeley Advanced Reconstruction Toolbox (BART).
https://mrirecon.github.io/bart/
![viewer](viewer.png)
Installation:
Requires BART up to commit e4df99aa75e0344931ba2e76d9ae052b02da498f
Mac OS X:
sudo port install pkgconfig
sudo port install gtk3
sudo port install adwaita-icon-theme
Linux:
sudo apt-get install libgtk-3-dev
Compile with make after setting the TOOLBOX_PATH
environment variable.
#include <stdio.h>
#include <assert.h>
#include <complex.h>
#include <string.h>
#include <strings.h>
#undef MAX
#undef MIN
#include "num/multind.h"
#include "num/init.h"
#include "misc/misc.h"
#include "misc/debug.h"
#include "misc/mmio.h"
#include "misc/opts.h"
#include "misc/png.h"
#include "draw.h"
#include "view.h"
#ifndef CFL_SIZE
#define CFL_SIZE sizeof(complex float)
#endif
void export_images(const char* output_prefix, int xdim, int ydim, float windowing[2], float zoom, enum mode_t mode, enum flip_t flip, enum interp_t interpolation, const long dims[DIMS], const complex float* idata);
static const char usage_str[] = "<input> <output_prefix>";
static const char help_str[] = "Export images to png.";
int main(int argc, char* argv[])
{
int xdim = 0;
int ydim = 0;
float windowing[2] = {0.f, 1.f};
enum mode_t mode = MAGN;
float zoom =2.f;
enum flip_t flip = OO;
enum interp_t interpolation = NLINEAR;
struct opt_s modeopt[] = {
OPT_SELECT('M', enum mode_t, &mode, MAGN, "magnitude gray (default) "),
OPT_SELECT('V', enum mode_t, &mode, MAGN_VIRIDS, "magnitude viridis"),
OPT_SELECT('C', enum mode_t, &mode, CMPL, "complex"),
OPT_SELECT('G', enum mode_t, &mode, CMPL_MYGBM, "complex MYGBM"),
OPT_SELECT('P', enum mode_t, &mode, PHSE, "phase"),
OPT_SELECT('Y', enum mode_t, &mode, PHSE_MYGBM, "phase MYGBM"),
OPT_SELECT('R', enum mode_t, &mode, REAL, "real"),
OPT_SELECT('F', enum mode_t, &mode, FLOW, "flow"),
};
struct opt_s flipopt[] = {
OPT_SELECT('O', enum flip_t, &flip, OO, "flip OO"),
OPT_SELECT('X', enum flip_t, &flip, XO, "flip XO"),
OPT_SELECT('Y', enum flip_t, &flip, OY, "flip OY"),
OPT_SELECT('Z', enum flip_t, &flip, XY, "flip XY"),
};
struct opt_s interpopt[] = {
OPT_SELECT('L', enum interp_t, &interpolation, NLINEAR, "n-linear interpolation"),
OPT_SELECT('N', enum interp_t, &interpolation, NEAREST, "nearest neighbor interpolation"),
};
const struct opt_s opts[] = {
OPT_INT('x', &xdim, "xdim", "output xdim (default: 0) "),
OPT_INT('y', &ydim, "ydim", "output ydim (default: 0). If both are zero, first two non-singleton dims are used."),
OPT_FLOAT('l', &windowing[0], "l", "lower windowing value"),
OPT_FLOAT('u', &windowing[1], "u", "upper windowing value"),
OPT_FLOAT('z', &zoom, "z", "zoom factor (default: 2) "),
OPT_SUBOPT('C', "cmap", "colormap. -Ch for help.", ARRAY_SIZE(modeopt), modeopt),
OPT_SUBOPT('F', "flip", "flip. -Fh for help.", ARRAY_SIZE(flipopt), flipopt),
OPT_SUBOPT('I', "interp", "interp. -Ih for help.", ARRAY_SIZE(interpopt), interpopt),
OPT_INT('d', &debug_level, "level", "Debug level"),
};
cmdline(&argc, argv, 2, 1000, usage_str, help_str, ARRAY_SIZE(opts), opts);
assert( (windowing[0] >= 0.f)
&& (windowing[1] <= 1.f)
&& (windowing[0] < windowing[1]));
const char* infile = argv[1];
const char* output_prefix = argv[2];
assert((0 <= xdim) && (xdim < DIMS));
assert((0 <= ydim) && (ydim < DIMS));
/*
* If the filename ends in ".hdr", ".cfl" or just "." (from
* tab-completion), just replace the "." with a \0-character.
*/
char* dot = strrchr(infile, '.');
if ( (NULL != dot)
&& ( !strcmp(dot, ".cfl")
|| !strcmp(dot, ".hdr")
|| !strcmp(dot, ".")))
*dot = '\0';
long dims[DIMS];
complex float* idata = load_cfl(infile, DIMS, dims);
char* ext = rindex(output_prefix, '.');
if (NULL != ext) {
if (0 != strcmp(ext, ".png"))
error("Unknown file extension.");
else
*ext = '\0';
}
export_images(output_prefix, xdim, ydim, windowing, zoom, mode, flip, interpolation, dims, idata);
unmap_cfl(DIMS, dims, idata);
return 0;
}
/**
* Convert flat index to pos
*
*/
static void unravel_index(unsigned int D, long pos[D], const long dims[D], long index)
{
for (unsigned int d = 0; d < D; ++d) {
if (1 == dims[d])
continue;
pos[d] = index % dims[d];
index /= dims[d];
}
}
void export_images(const char* output_prefix, int xdim, int ydim, float windowing[2], float zoom, enum mode_t mode, enum flip_t flip, enum interp_t interpolation, const long dims[DIMS], const complex float* idata)
{
if (xdim == ydim) {
long sq_dims[2] = { 0 };
int l = 0;
for (int i = 0; (i < DIMS) && (l < 2); i++)
if (1 != dims[i])
sq_dims[l++] = i;
assert(2 == l);
xdim = sq_dims[0];
ydim = sq_dims[1];
}
double max = 0.;
for (long j = 0; j < md_calc_size(DIMS, dims); j++)
if (max < cabsf(idata[j]))
max = cabsf(idata[j]);
if (0. == max)
max = 1.;
int rgbw = dims[xdim] * zoom;
int rgbh = dims[ydim] * zoom;
int rgbstr = 4 * rgbw;
unsigned char* rgb = xmalloc(rgbh * rgbstr);
complex float* buf = xmalloc(rgbh * rgbw * sizeof(complex float));
// loop over all dims other than xdim and ydim
long loopdims[DIMS];
unsigned long loopflags = (MD_BIT(xdim)|MD_BIT(ydim));
md_select_dims(DIMS, ~loopflags, loopdims, dims);
debug_printf(DP_DEBUG3, "flags: %lu\nloopdims: ", loopflags);
debug_print_dims(DP_DEBUG3, DIMS, loopdims);
long pos[DIMS] = { [0 ... DIMS - 1] = 0 };
long strs[DIMS];
md_calc_strides(DIMS, strs, dims, sizeof(complex float));
for (unsigned long d = 0l; d < md_calc_size(DIMS, loopdims); ++d){
unravel_index(DIMS, pos, loopdims, d);
debug_printf(DP_DEBUG3, "\ti: %lu\n\t", d);
debug_print_dims(DP_DEBUG3, DIMS, pos);
// Prepare output filename
unsigned int bufsize = 255;
char name[bufsize];
char* cur = name;
const char* end = name + bufsize;
cur += snprintf(cur, end - cur, "%s", output_prefix);
for (unsigned int i = 0; i < DIMS; i++) {
if (1 != loopdims[i])
cur += snprintf(cur, end - cur, "_%s_%04ld", get_spec(i), pos[i]);
}
cur += snprintf(cur, end - cur, ".png");
debug_printf(DP_DEBUG2, "\t%s\n", name);
update_buf(xdim, ydim, DIMS, dims, strs, pos, flip, interpolation, zoom, zoom,
rgbw, rgbh, idata, buf);
draw(rgbw, rgbh, rgbstr, (unsigned char(*)[rgbw][rgbstr / 4][4])rgb,
mode, 1. / max, windowing[0], windowing[1], 0,
rgbw, buf);
if (0 != png_write_bgr32(name, rgbw, rgbh, 0, rgb))
error("Error: writing image file.\n");
}
// free(source);
free(buf);
free(rgb);
}
// cyclic_mygbm is a phase colormap from the the
// "colorcet" project (https://github.com/bokeh/colorcet)
// using a transition from magenta through yellow, green, and blue back to
// magenta. More information can be found in:
// Peter Kovesi. Good Colour Maps: How to Design Them.
// arXiv:1509.03700 [cs.GR] 2015
// cyclic_mygbm by Peter Kovesi (http://www.peterkovesi.com) is licensed under the
// Creative Commons Attribution 4.0 International Public License (CC-BY)
// (https://creativecommons.org/licenses/by/4.0/)
// Direct link to the colormap is
// https://github.com/bokeh/colorcet/blob/master/assets/CETperceptual_csv_0_1/cyclic_mygbm_30-95_c78_n256_s25.csv
static const double cyclic_mygbm[256][3] = {
{0.18062, 0.13244, 0.91856},
{0.19173, 0.12446, 0.92396},
{0.20389, 0.11765, 0.92889},
{0.21681, 0.11214, 0.93335},
{0.23028, 0.10794, 0.93739},
{0.24417, 0.10525, 0.94101},
{0.25828, 0.10403, 0.94425},
{0.27246, 0.10417, 0.94716},
{0.28659, 0.10560, 0.94977},
{0.30059, 0.10807, 0.95212},
{0.31440, 0.11153, 0.95426},
{0.32796, 0.11565, 0.95622},
{0.34126, 0.12031, 0.95803},
{0.35426, 0.12544, 0.95973},
{0.36698, 0.13084, 0.96134},
{0.37942, 0.13637, 0.96288},
{0.39160, 0.14210, 0.96436},
{0.40352, 0.14786, 0.96581},
{0.41520, 0.15363, 0.96722},
{0.42669, 0.15941, 0.9686},
{0.43799, 0.16515, 0.96996},
{0.44913, 0.17088, 0.97129},
{0.46013, 0.17650, 0.97261},
{0.47106, 0.18204, 0.97389},
{0.48191, 0.18751, 0.97514},
{0.49273, 0.19280, 0.97635},
{0.50357, 0.19798, 0.97752},
{0.51446, 0.20302, 0.97863},
{0.52541, 0.20790, 0.97969},
{0.53647, 0.21259, 0.98067},
{0.54767, 0.21709, 0.98157},
{0.55903, 0.22137, 0.98238},
{0.57057, 0.22542, 0.9831},
{0.58230, 0.22925, 0.98372},
{0.59423, 0.23284, 0.98424},
{0.60636, 0.23623, 0.98465},
{0.61868, 0.23935, 0.98497},
{0.63116, 0.24227, 0.98518},
{0.64379, 0.24496, 0.9853},
{0.65656, 0.24750, 0.98533},
{0.66943, 0.24982, 0.98527},
{0.68237, 0.25203, 0.98515},
{0.69537, 0.25408, 0.98496},
{0.70839, 0.25601, 0.98471},
{0.72139, 0.25786, 0.98441},
{0.73437, 0.25968, 0.98405},
{0.74728, 0.26143, 0.98365},
{0.76012, 0.26319, 0.98321},
{0.77286, 0.26494, 0.98271},
{0.78548, 0.26676, 0.98216},
{0.79794, 0.26867, 0.98153},
{0.81023, 0.27069, 0.98082},
{0.82233, 0.27285, 0.98001},
{0.83418, 0.27525, 0.97905},
{0.84576, 0.27791, 0.97793},
{0.85702, 0.28089, 0.97661},
{0.86794, 0.28430, 0.97504},
{0.87845, 0.28819, 0.97317},
{0.88852, 0.29263, 0.97097},
{0.89810, 0.29768, 0.96837},
{0.90717, 0.30340, 0.96533},
{0.91567, 0.30984, 0.96182},
{0.92361, 0.31700, 0.9578},
{0.93095, 0.32489, 0.95323},
{0.93769, 0.33352, 0.94809},
{0.94383, 0.34283, 0.94239},
{0.94939, 0.35275, 0.93613},
{0.95439, 0.36323, 0.92931},
{0.95886, 0.37422, 0.92198},
{0.96283, 0.38558, 0.91416},
{0.96634, 0.39727, 0.90588},
{0.96944, 0.40921, 0.89721},
{0.97216, 0.42130, 0.88817},
{0.97454, 0.43350, 0.87883},
{0.97663, 0.44573, 0.86923},
{0.97845, 0.45797, 0.8594},
{0.98004, 0.47017, 0.84939},
{0.98142, 0.48228, 0.83922},
{0.98262, 0.49430, 0.82894},
{0.98364, 0.50620, 0.81854},
{0.98453, 0.51799, 0.80808},
{0.98527, 0.52964, 0.79753},
{0.98588, 0.54116, 0.78694},
{0.98637, 0.55255, 0.77629},
{0.98676, 0.56382, 0.76559},
{0.98704, 0.57494, 0.75486},
{0.98722, 0.58595, 0.74407},
{0.98733, 0.59683, 0.73326},
{0.98736, 0.60758, 0.72241},
{0.98732, 0.61821, 0.71153},
{0.98723, 0.62871, 0.7006},
{0.98710, 0.63909, 0.68965},
{0.98694, 0.64936, 0.67864},
{0.98677, 0.65949, 0.66762},
{0.98660, 0.66950, 0.65654},
{0.98644, 0.67938, 0.64543},
{0.98630, 0.68916, 0.63428},
{0.98621, 0.69879, 0.62309},
{0.98616, 0.70831, 0.61184},
{0.98617, 0.71772, 0.60055},
{0.98624, 0.72700, 0.5892},
{0.98636, 0.73618, 0.57779},
{0.98653, 0.74526, 0.56632},
{0.98675, 0.75426, 0.55476},
{0.98702, 0.76315, 0.54311},
{0.98731, 0.77198, 0.53134},
{0.98761, 0.78074, 0.51946},
{0.98792, 0.78944, 0.50744},
{0.98820, 0.79807, 0.49526},
{0.98845, 0.80666, 0.48291},
{0.98864, 0.81518, 0.47039},
{0.98875, 0.82365, 0.45765},
{0.98875, 0.83206, 0.4447},
{0.98863, 0.84039, 0.43151},
{0.98834, 0.84863, 0.41804},
{0.98786, 0.85677, 0.40433},
{0.98715, 0.86476, 0.39033},
{0.98616, 0.87259, 0.37607},
{0.98485, 0.88020, 0.36152},
{0.98316, 0.88754, 0.3467},
{0.98105, 0.89458, 0.33163},
{0.97845, 0.90123, 0.31637},
{0.97534, 0.90744, 0.30092},
{0.97166, 0.91315, 0.28537},
{0.96737, 0.91831, 0.26983},
{0.96244, 0.92285, 0.25432},
{0.95686, 0.92672, 0.23895},
{0.95064, 0.92990, 0.22388},
{0.94377, 0.93236, 0.2092},
{0.93628, 0.93410, 0.19506},
{0.92820, 0.93512, 0.18153},
{0.91959, 0.93544, 0.16884},
{0.91047, 0.93510, 0.15697},
{0.90091, 0.93414, 0.1461},
{0.89097, 0.93263, 0.13623},
{0.88070, 0.93061, 0.12747},
{0.87014, 0.92815, 0.11977},
{0.85937, 0.92531, 0.11315},
{0.84840, 0.92216, 0.10742},
{0.83729, 0.91874, 0.10257},
{0.82605, 0.91511, 0.098502},
{0.81472, 0.91132, 0.095091},
{0.80332, 0.90739, 0.092162},
{0.79187, 0.90336, 0.089659},
{0.78036, 0.89925, 0.087518},
{0.76881, 0.89508, 0.08551},
{0.75723, 0.89086, 0.083837},
{0.74562, 0.88662, 0.082243},
{0.73398, 0.88235, 0.080673},
{0.72230, 0.87807, 0.079194},
{0.71060, 0.87376, 0.077792},
{0.69886, 0.86946, 0.076415},
{0.68710, 0.86514, 0.075063},
{0.67529, 0.86082, 0.073757},
{0.66346, 0.85649, 0.072319},
{0.65156, 0.85215, 0.071005},
{0.63963, 0.84780, 0.069678},
{0.62764, 0.84345, 0.068313},
{0.61560, 0.83909, 0.066946},
{0.60351, 0.83473, 0.065602},
{0.59134, 0.83035, 0.064284},
{0.57911, 0.82597, 0.063016},
{0.56681, 0.82158, 0.061599},
{0.55443, 0.81718, 0.060374},
{0.54195, 0.81278, 0.059088},
{0.52940, 0.80837, 0.057695},
{0.51672, 0.80395, 0.056522},
{0.50395, 0.79952, 0.055189},
{0.49106, 0.79508, 0.053903},
{0.47801, 0.79064, 0.052644},
{0.46484, 0.78619, 0.051424},
{0.45151, 0.78173, 0.050257},
{0.43803, 0.77726, 0.04922},
{0.42437, 0.77277, 0.04812},
{0.41056, 0.76827, 0.047322},
{0.39656, 0.76375, 0.04674},
{0.38239, 0.75922, 0.046427},
{0.36808, 0.75466, 0.046596},
{0.35361, 0.75006, 0.047299},
{0.33906, 0.74543, 0.04874},
{0.32443, 0.74075, 0.050897},
{0.30984, 0.73602, 0.054069},
{0.29532, 0.73122, 0.058336},
{0.28105, 0.72634, 0.063783},
{0.26717, 0.72137, 0.070322},
{0.25387, 0.71631, 0.077992},
{0.24134, 0.71112, 0.08687},
{0.22981, 0.70580, 0.096608},
{0.21961, 0.70035, 0.10741},
{0.21092, 0.69475, 0.11899},
{0.20400, 0.68901, 0.13129},
{0.19894, 0.68310, 0.14422},
{0.19593, 0.67703, 0.15768},
{0.19486, 0.67081, 0.17161},
{0.19560, 0.66443, 0.18594},
{0.19795, 0.65791, 0.2005},
{0.20163, 0.65125, 0.21533},
{0.20639, 0.64446, 0.2303},
{0.21183, 0.63756, 0.24538},
{0.21771, 0.63057, 0.26052},
{0.22381, 0.62348, 0.27565},
{0.22992, 0.61632, 0.29071},
{0.23593, 0.60910, 0.30574},
{0.24162, 0.60182, 0.32064},
{0.24693, 0.59450, 0.33543},
{0.25184, 0.58716, 0.35008},
{0.25622, 0.57980, 0.36459},
{0.26011, 0.57242, 0.37897},
{0.26346, 0.56501, 0.3932},
{0.26624, 0.55762, 0.4073},
{0.26846, 0.55021, 0.42127},
{0.27013, 0.54280, 0.43513},
{0.27122, 0.53539, 0.44886},
{0.27173, 0.52798, 0.46247},
{0.27170, 0.52057, 0.476},
{0.27112, 0.51317, 0.48942},
{0.26997, 0.50576, 0.50275},
{0.26823, 0.49837, 0.516},
{0.26598, 0.49096, 0.52919},
{0.26316, 0.48352, 0.54228},
{0.25982, 0.47610, 0.55529},
{0.25594, 0.46864, 0.56822},
{0.25162, 0.46117, 0.58105},
{0.24680, 0.45365, 0.5938},
{0.24161, 0.44609, 0.60643},
{0.23605, 0.43849, 0.61894},
{0.23017, 0.43081, 0.63131},
{0.22410, 0.42303, 0.64353},
{0.21793, 0.41517, 0.6556},
{0.21170, 0.40718, 0.66749},
{0.20550, 0.39906, 0.67919},
{0.19945, 0.39079, 0.6907},
{0.19367, 0.38234, 0.70201},
{0.18818, 0.37372, 0.71312},
{0.18300, 0.36488, 0.72404},
{0.17829, 0.35585, 0.73477},
{0.17392, 0.34657, 0.7453},
{0.16999, 0.33707, 0.75566},
{0.16639, 0.32732, 0.76586},
{0.16312, 0.31735, 0.7759},
{0.16005, 0.30712, 0.78581},
{0.15724, 0.29667, 0.79557},
{0.15457, 0.28595, 0.80522},
{0.15202, 0.27505, 0.81474},
{0.14966, 0.26395, 0.82414},
{0.14744, 0.25264, 0.8334},
{0.14554, 0.24118, 0.84252},
{0.14402, 0.22960, 0.85145},
{0.14312, 0.21800, 0.86019},
{0.14305, 0.20639, 0.86869},
{0.14404, 0.19481, 0.87691},
{0.14630, 0.18336, 0.88484},
{0.15007, 0.17219, 0.89241},
{0.15537, 0.16140, 0.8996},
{0.16230, 0.15103, 0.90637},
{0.17075, 0.14136, 0.9127},
};
// viridis is the new default perceptually uniform colormap of the
// "matplotlib" project (http://matplotlib.org/)
// Direct link to the colormap is
// https://github.com/BIDS/colormap/blob/master/colormaps.py
// Viridis (and the other colormaps available at the link) are created by
// Nathaniel J. Smith, Stefan van der Walt, and (in the case of viridis) Eric Firing.
// The file (https://github.com/BIDS/colormap/blob/master/colormaps.py)
// and the colormaps in it are released under the CC0 license /
// public domain dedication. The authors would appreciate credit if you use or
// redistribute these colormaps, but do not impose any legal restrictions.
// See <http://creativecommons.org/publicdomain/zero/1.0/> for a copy
// of the CC0 license.
static const double viridis[256][3] = {
{0.267004, 0.004874, 0.329415},
{0.268510, 0.009605, 0.335427},
{0.269944, 0.014625, 0.341379},
{0.271305, 0.019942, 0.347269},
{0.272594, 0.025563, 0.353093},
{0.273809, 0.031497, 0.358853},
{0.274952, 0.037752, 0.364543},
{0.276022, 0.044167, 0.370164},
{0.277018, 0.050344, 0.375715},
{0.277941, 0.056324, 0.381191},
{0.278791, 0.062145, 0.386592},
{0.279566, 0.067836, 0.391917},
{0.280267, 0.073417, 0.397163},
{0.280894, 0.078907, 0.402329},
{0.281446, 0.084320, 0.407414},
{0.281924, 0.089666, 0.412415},
{0.282327, 0.094955, 0.417331},
{0.282656, 0.100196, 0.422160},
{0.282910, 0.105393, 0.426902},
{0.283091, 0.110553, 0.431554},
{0.283197, 0.115680, 0.436115},
{0.283229, 0.120777, 0.440584},
{0.283187, 0.125848, 0.444960},
{0.283072, 0.130895, 0.449241},
{0.282884, 0.135920, 0.453427},
{0.282623, 0.140926, 0.457517},
{0.282290, 0.145912, 0.461510},
{0.281887, 0.150881, 0.465405},
{0.281412, 0.155834, 0.469201},
{0.280868, 0.160771, 0.472899},
{0.280255, 0.165693, 0.476498},
{0.279574, 0.170599, 0.479997},
{0.278826, 0.175490, 0.483397},
{0.278012, 0.180367, 0.486697},
{0.277134, 0.185228, 0.489898},
{0.276194, 0.190074, 0.493001},
{0.275191, 0.194905, 0.496005},
{0.274128, 0.199721, 0.498911},
{0.273006, 0.204520, 0.501721},
{0.271828, 0.209303, 0.504434},
{0.270595, 0.214069, 0.507052},
{0.269308, 0.218818, 0.509577},
{0.267968, 0.223549, 0.512008},
{0.266580, 0.228262, 0.514349},
{0.265145, 0.232956, 0.516599},
{0.263663, 0.237631, 0.518762},
{0.262138, 0.242286, 0.520837},
{0.260571, 0.246922, 0.522828},
{0.258965, 0.251537, 0.524736},
{0.257322, 0.256130, 0.526563},
{0.255645, 0.260703, 0.528312},
{0.253935, 0.265254, 0.529983},
{0.252194, 0.269783, 0.531579},
{0.250425, 0.274290, 0.533103},
{0.248629, 0.278775, 0.534556},
{0.246811, 0.283237, 0.535941},
{0.244972, 0.287675, 0.537260},
{0.243113, 0.292092, 0.538516},
{0.241237, 0.296485, 0.539709},
{0.239346, 0.300855, 0.540844},
{0.237441, 0.305202, 0.541921},
{0.235526, 0.309527, 0.542944},
{0.233603, 0.313828, 0.543914},
{0.231674, 0.318106, 0.544834},
{0.229739, 0.322361, 0.545706},
{0.227802, 0.326594, 0.546532},
{0.225863, 0.330805, 0.547314},
{0.223925, 0.334994, 0.548053},
{0.221989, 0.339161, 0.548752},
{0.220057, 0.343307, 0.549413},
{0.218130, 0.347432, 0.550038},
{0.216210, 0.351535, 0.550627},
{0.214298, 0.355619, 0.551184},
{0.212395, 0.359683, 0.551710},
{0.210503, 0.363727, 0.552206},
{0.208623, 0.367752, 0.552675},
{0.206756, 0.371758, 0.553117},
{0.204903, 0.375746, 0.553533},
{0.203063, 0.379716, 0.553925},
{0.201239, 0.383670, 0.554294},
{0.199430, 0.387607, 0.554642},
{0.197636, 0.391528, 0.554969},
{0.195860, 0.395433, 0.555276},
{0.194100, 0.399323, 0.555565},
{0.192357, 0.403199, 0.555836},
{0.190631, 0.407061, 0.556089},
{0.188923, 0.410910, 0.556326},
{0.187231, 0.414746, 0.556547},
{0.185556, 0.418570, 0.556753},
{0.183898, 0.422383, 0.556944},
{0.182256, 0.426184, 0.557120},
{0.180629, 0.429975, 0.557282},
{0.179019, 0.433756, 0.557430},
{0.177423, 0.437527, 0.557565},
{0.175841, 0.441290, 0.557685},
{0.174274, 0.445044, 0.557792},
{0.172719, 0.448791, 0.557885},
{0.171176, 0.452530, 0.557965},
{0.169646, 0.456262, 0.558030},
{0.168126, 0.459988, 0.558082},
{0.166617, 0.463708, 0.558119},
{0.165117, 0.467423, 0.558141},
{0.163625, 0.471133, 0.558148},
{0.162142, 0.474838, 0.558140},
{0.160665, 0.478540, 0.558115},
{0.159194, 0.482237, 0.558073},
{0.157729, 0.485932, 0.558013},
{0.156270, 0.489624, 0.557936},
{0.154815, 0.493313, 0.557840},
{0.153364, 0.497000, 0.557724},
{0.151918, 0.500685, 0.557587},
{0.150476, 0.504369, 0.557430},
{0.149039, 0.508051, 0.557250},
{0.147607, 0.511733, 0.557049},
{0.146180, 0.515413, 0.556823},
{0.144759, 0.519093, 0.556572},
{0.143343, 0.522773, 0.556295},
{0.141935, 0.526453, 0.555991},
{0.140536, 0.530132, 0.555659},
{0.139147, 0.533812, 0.555298},
{0.137770, 0.537492, 0.554906},
{0.136408, 0.541173, 0.554483},
{0.135066, 0.544853, 0.554029},
{0.133743, 0.548535, 0.553541},
{0.132444, 0.552216, 0.553018},
{0.131172, 0.555899, 0.552459},
{0.129933, 0.559582, 0.551864},
{0.128729, 0.563265, 0.551229},
{0.127568, 0.566949, 0.550556},
{0.126453, 0.570633, 0.549841},
{0.125394, 0.574318, 0.549086},
{0.124395, 0.578002, 0.548287},
{0.123463, 0.581687, 0.547445},
{0.122606, 0.585371, 0.546557},
{0.121831, 0.589055, 0.545623},
{0.121148, 0.592739, 0.544641},
{0.120565, 0.596422, 0.543611},
{0.120092, 0.600104, 0.542530},
{0.119738, 0.603785, 0.541400},
{0.119512, 0.607464, 0.540218},
{0.119423, 0.611141, 0.538982},
{0.119483, 0.614817, 0.537692},
{0.119699, 0.618490, 0.536347},
{0.120081, 0.622161, 0.534946},
{0.120638, 0.625828, 0.533488},
{0.121380, 0.629492, 0.531973},
{0.122312, 0.633153, 0.530398},
{0.123444, 0.636809, 0.528763},
{0.124780, 0.640461, 0.527068},
{0.126326, 0.644107, 0.525311},
{0.128087, 0.647749, 0.523491},
{0.130067, 0.651384, 0.521608},
{0.132268, 0.655014, 0.519661},
{0.134692, 0.658636, 0.517649},
{0.137339, 0.662252, 0.515571},
{0.140210, 0.665859, 0.513427},
{0.143303, 0.669459, 0.511215},
{0.146616, 0.673050, 0.508936},
{0.150148, 0.676631, 0.506589},
{0.153894, 0.680203, 0.504172},
{0.157851, 0.683765, 0.501686},
{0.162016, 0.687316, 0.499129},
{0.166383, 0.690856, 0.496502},
{0.170948, 0.694384, 0.493803},
{0.175707, 0.697900, 0.491033},
{0.180653, 0.701402, 0.488189},
{0.185783, 0.704891, 0.485273},
{0.191090, 0.708366, 0.482284},
{0.196571, 0.711827, 0.479221},
{0.202219, 0.715272, 0.476084},
{0.208030, 0.718701, 0.472873},
{0.214000, 0.722114, 0.469588},
{0.220124, 0.725509, 0.466226},
{0.226397, 0.728888, 0.462789},
{0.232815, 0.732247, 0.459277},
{0.239374, 0.735588, 0.455688},
{0.246070, 0.738910, 0.452024},
{0.252899, 0.742211, 0.448284},
{0.259857, 0.745492, 0.444467},
{0.266941, 0.748751, 0.440573},
{0.274149, 0.751988, 0.436601},
{0.281477, 0.755203, 0.432552},
{0.288921, 0.758394, 0.428426},
{0.296479, 0.761561, 0.424223},
{0.304148, 0.764704, 0.419943},
{0.311925, 0.767822, 0.415586},
{0.319809, 0.770914, 0.411152},
{0.327796, 0.773980, 0.406640},
{0.335885, 0.777018, 0.402049},
{0.344074, 0.780029, 0.397381},
{0.352360, 0.783011, 0.392636},
{0.360741, 0.785964, 0.387814},
{0.369214, 0.788888, 0.382914},
{0.377779, 0.791781, 0.377939},
{0.386433, 0.794644, 0.372886},
{0.395174, 0.797475, 0.367757},
{0.404001, 0.800275, 0.362552},
{0.412913, 0.803041, 0.357269},
{0.421908, 0.805774, 0.351910},
{0.430983, 0.808473, 0.346476},
{0.440137, 0.811138, 0.340967},
{0.449368, 0.813768, 0.335384},
{0.458674, 0.816363, 0.329727},
{0.468053, 0.818921, 0.323998},
{0.477504, 0.821444, 0.318195},
{0.487026, 0.823929, 0.312321},
{0.496615, 0.826376, 0.306377},
{0.506271, 0.828786, 0.300362},
{0.515992, 0.831158, 0.294279},
{0.525776, 0.833491, 0.288127},
{0.535621, 0.835785, 0.281908},
{0.545524, 0.838039, 0.275626},
{0.555484, 0.840254, 0.269281},
{0.565498, 0.842430, 0.262877},
{0.575563, 0.844566, 0.256415},
{0.585678, 0.846661, 0.249897},
{0.595839, 0.848717, 0.243329},
{0.606045, 0.850733, 0.236712},
{0.616293, 0.852709, 0.230052},
{0.626579, 0.854645, 0.223353},
{0.636902, 0.856542, 0.216620},
{0.647257, 0.858400, 0.209861},
{0.657642, 0.860219, 0.203082},
{0.668054, 0.861999, 0.196293},
{0.678489, 0.863742, 0.189503},
{0.688944, 0.865448, 0.182725},
{0.699415, 0.867117, 0.175971},
{0.709898, 0.868751, 0.169257},
{0.720391, 0.870350, 0.162603},
{0.730889, 0.871916, 0.156029},
{0.741388, 0.873449, 0.149561},
{0.751884, 0.874951, 0.143228},
{0.762373, 0.876424, 0.137064},
{0.772852, 0.877868, 0.131109},
{0.783315, 0.879285, 0.125405},
{0.793760, 0.880678, 0.120005},
{0.804182, 0.882046, 0.114965},
{0.814576, 0.883393, 0.110347},
{0.824940, 0.884720, 0.106217},
{0.835270, 0.886029, 0.102646},
{0.845561, 0.887322, 0.099702},
{0.855810, 0.888601, 0.097452},
{0.866013, 0.889868, 0.095953},
{0.876168, 0.891125, 0.095250},
{0.886271, 0.892374, 0.095374},
{0.896320, 0.893616, 0.096335},
{0.906311, 0.894855, 0.098125},
{0.916242, 0.896091, 0.100717},
{0.926106, 0.897330, 0.104071},
{0.935904, 0.898570, 0.108131},
{0.945636, 0.899815, 0.112838},
{0.955300, 0.901065, 0.118128},
{0.964894, 0.902323, 0.123941},
{0.974417, 0.903590, 0.130215},
{0.983868, 0.904867, 0.136897},
{0.993248, 0.906157, 0.143936},
};
/* Copyright 2015. Martin Uecker.
/* Copyright 2015-2016. Martin Uecker.
* All rights reserved. Use of this source code is governed by
* a BSD-style license which can be found in the LICENSE file.
*
* Author:
* 2015 Martin Uecker <martin.uecker@med.uni-goettingen.de>
* 2015-2016 Martin Uecker <martin.uecker@med.uni-goettingen.de>
*/
#include <math.h>
......@@ -14,6 +14,8 @@
#include "draw.h"
#include "colormaps.inc"
// multind.h
#define MD_BIT(x) (1u << (x))
#define MD_IS_SET(x, y) ((x) & MD_BIT(y))
......@@ -39,6 +41,21 @@ static void trans_magnitude(double rgb[3], double a, double b, complex double va
rgb[2] *= magn;
}
static void trans_magnitude_viridis(double rgb[3], double a, double b, complex double value)
{
double magn = window(a, b, cabs(value));
// since window returns nonsense (NaN) if a == b, and since casting nonsense to int
// and using it as an array subscript is bound to lead to segfaults,
// we catch that case here
if ( isfinite(magn) ) {
int subscript = magn*255.;
rgb[0] *= viridis[subscript][0];
rgb[1] *= viridis[subscript][1];
rgb[2] *= viridis[subscript][2];
}
}
static void trans_real(double rgb[3], double a, double b, complex double value)
{
rgb[0] *= window(a, b, +creal(value));
......@@ -48,17 +65,40 @@ static void trans_real(double rgb[3], double a, double b, complex double value)
static void trans_phase(double rgb[3], double a, double b, complex double value)
{
UNUSED(a);
UNUSED(b);
rgb[0] *= (1. + sin(carg(value) + 0. * 2. * M_PI / 3.)) / 2.;
rgb[1] *= (1. + sin(carg(value) + 1. * 2. * M_PI / 3.)) / 2.;
rgb[2] *= (1. + sin(carg(value) + 2. * 2. * M_PI / 3.)) / 2.;
}
static void trans_phase_MYGBM(double rgb[3], double a, double b, complex double value)
{
UNUSED(a);
UNUSED(b);
double arg = carg(value);
if (isfinite(arg)) {
int subscript = (arg+M_PI)/2./M_PI*255.;
assert( (0 <= subscript) && (subscript <=255) );
rgb[0] *= cyclic_mygbm[subscript][0];
rgb[1] *= cyclic_mygbm[subscript][1];
rgb[2] *= cyclic_mygbm[subscript][2];
}
}
static void trans_complex(double rgb[3], double a, double b, complex double value)
{
trans_magnitude(rgb, a, b, value);
trans_phase(rgb, a, b, value);
}
static void trans_complex_MYGBM(double rgb[3], double a, double b, complex double value)
{
trans_magnitude(rgb, a, b, value);
trans_phase_MYGBM(rgb, a, b, value);
}
static void trans_flow(double rgb[3], double a, double b, complex double value)
{
trans_magnitude(rgb, a, b, value);
......@@ -81,7 +121,17 @@ static complex float int_nlinear(int N, const float x[N], const long strs[N], co
}
complex float sample(int N, const float pos[N], const long dims[N], const long strs[N], const complex float* in)
static complex float int_nearest(int N, const float x[N], const long strs[N], const complex float* in)
{
size_t offs = 0;
for (int i = 0; i < N; ++i)
offs += round(x[i]) * strs[i];
return *(in + offs);
}
complex float sample(int N, const float pos[N], const long dims[N], const long strs[N], enum interp_t interpolation, const complex float* in)
{
float rem[N];
int div[N];
......@@ -96,8 +146,19 @@ complex float sample(int N, const float pos[N], const long dims[N], const long s
if (dims[i] > 1) {
float xrem = 0.;
// values outside of valid range set to the edge values
if (pos[i] < 0.) {
div[i] = 0.;
} else if (pos[i] > (dims[i] - 1)) {
div[i] = dims[i] - 1;
} else {
div[i] = truncf(pos[i]);
float xrem = pos[i] - truncf(pos[i]);
xrem = pos[i] - truncf(pos[i]);
}
if (xrem != 0.) {
......@@ -105,8 +166,6 @@ complex float sample(int N, const float pos[N], const long dims[N], const long s
rem[D++] = xrem;
}
//printf("%d\n", div[i]);
if ((div[i] < 0) || (div[i] >= dims[i]) || ((div[i] >= dims[i] - 1) && (xrem > 0.)))
return 0.;
}
......@@ -117,22 +176,41 @@ complex float sample(int N, const float pos[N], const long dims[N], const long s
for (int i = 0; i < N; i++)
off0 += div[i] * strs[i];
return int_nlinear(D, rem, strs2, (const complex float*)(((char*)in) + off0));
}
switch (interpolation) {
case NLINEAR: return int_nlinear(D, rem, strs2, (const complex float*)(((char*)in) + off0));
case NEAREST: return int_nearest(D, rem, strs2, (const complex float*)(((char*)in) + off0));
default: assert(0);
}
}
// The idea is the following:
// samples sit in the middle of their pixels, so for even zoom factors,
// the original values are between adjacent pixels, with pixels outside
// of the valid range (negative pos2 and pos2 greater than dim-1) set to the
// corresponding values. Therefore we need to start the pos2 array at negative
// positions.
extern void resample(int X, int Y, long str, complex float* buf,
int N, const double pos[N], const double dx[N], const double dy[N],
const long dims[N], const long strs[N], const complex float* in)
const long dims[N], const long strs[N], enum interp_t interpolation, const complex float* in)
{
for (int x = 0; x < X; x++) {
for (int y = 0; y < Y; y++) {
float pos2[N];
for (int i = 0; i < N; i++)
pos2[i] = pos[i] + x * dx[i] + y * dy[i];
for (int i = 0; i < N; i++) {
buf[str * y + x] = sample(N, pos2, dims, strs, in);
// start is only != 0 if dx or dy are != 0.
// Further, for negative dx/dy, it needs the same sign.
// ....0.......1.... d (|d| - 1.) / 2.
// |---*---|---*---| 1.00 -> -0.000
// |-*-|-*-|-*-|-*-| 0.50 -> -0.250
// |*|*|*|*|*|*|*|*| 0.25 -> -0.375
double start = - (dx[i] != 0.) * copysign((fabs(dx[i]) - 1.) / 2., dx[i])
- (dy[i] != 0.) * copysign((fabs(dy[i]) - 1.) / 2., dy[i]);
pos2[i] = pos[i] + start + x * dx[i] + y * dy[i];
}
buf[str * y + x] = sample(N, pos2, dims, strs, interpolation, in);
}
}
}
......@@ -140,7 +218,7 @@ extern void resample(int X, int Y, long str, complex float* buf,
extern void draw(int X, int Y, int rgbstr, unsigned char* rgbbuf,
extern void draw(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4],
enum mode_t mode, float scale, float winlow, float winhigh, float phrot,
long str, const complex float* buf)
{
......@@ -156,17 +234,144 @@ extern void draw(int X, int Y, int rgbstr, unsigned char* rgbbuf,
switch (mode) {
case MAGN: trans_magnitude(rgb, winlow, winhigh, val); break;
case MAGN_VIRIDS: trans_magnitude_viridis(rgb, winlow, winhigh, val); break;
case PHSE: trans_phase(rgb, winlow, winhigh, val); break;
case PHSE_MYGBM: trans_phase_MYGBM(rgb, winlow, winhigh, val); break;
case CMPL: trans_complex(rgb, winlow, winhigh, val); break;
case CMPL_MYGBM: trans_complex_MYGBM(rgb, winlow, winhigh, val); break;
case REAL: trans_real(rgb, winlow, winhigh, val); break;
case FLOW: trans_flow(rgb, winlow, winhigh, val); break;
default: assert(0);
}
rgbbuf[y * rgbstr + x * 4 + 0] = 255. * rgb[2];
rgbbuf[y * rgbstr + x * 4 + 1] = 255. * rgb[1];
rgbbuf[y * rgbstr + x * 4 + 2] = 255. * rgb[0];
rgbbuf[y * rgbstr + x * 4 + 3] = 0.;
(*rgbbuf)[y][x][0] = 255. * rgb[2];
(*rgbbuf)[y][x][1] = 255. * rgb[1];
(*rgbbuf)[y][x][2] = 255. * rgb[0];
(*rgbbuf)[y][x][3] = 255.;
}
}
}
void update_buf(long xdim, long ydim, int N, const long dims[N], const long strs[N], const long pos[N],
enum flip_t flip, enum interp_t interpolation, double xzoom, double yzoom,
long rgbw, long rgbh, const complex float* data, complex float* buf)
{
double dpos[N];
for (int i = 0; i < N; i++)
dpos[i] = pos[i];
dpos[xdim] = 0.;
dpos[ydim] = 0.;
double dx[N];
for (int i = 0; i < N; i++)
dx[i] = 0.;
double dy[N];
for (int i = 0; i < N; i++)
dy[i] = 0.;
dx[xdim] = 1.;
dy[ydim] = 1.;
if ((XY == flip) || (XO == flip)) {
dpos[xdim] = dims[xdim] - 1;
dx[xdim] *= -1.;
}
if ((XY == flip) || (OY == flip)) {
dpos[ydim] = dims[ydim] - 1;
dy[ydim] *= -1.;
}
dx[xdim] = dx[xdim] / xzoom;
dy[ydim] = dy[ydim] / yzoom;
resample(rgbw, rgbh, rgbw, buf,
N, dpos, dx, dy, dims, strs, interpolation, data);
}
// Get dimension specifier for filename
extern char* get_spec(int i)
{
switch(i) {
case 0: return "x"; break;
case 1: return "y"; break;
case 2: return "z"; break;
case 3: return "coil"; break;
case 4: return "map"; break;
case 5: return "n"; break;
case 6: return "o"; break;
case 7: return "p"; break;
case 8: return "q"; break;
case 9: return "slice"; break;
case 10: return "frame"; break;
case 11: return "s"; break;
case 12: return "t"; break;
case 13: return "u"; break;
case 14: return "v"; break;
case 15: return "w"; break;
default: error("Invalid dimension!");
}
return "";
}
const char color_white[3] = { 255, 255, 255 };
const char color_blue[3] = { 255, 0, 0 };
const char color_red[3] = { 0, 0, 255 };
extern void draw_line(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4], float x0, float y0, float x1, float y1, const char (*color)[3])
{
float stepx = x1 - x0;
float stepy = y1 - y0;
float max = 1.44 * sqrtf(powf(stepx, 2.) + powf(stepy, 2.));
stepx /= max;
stepy /= max;
for (unsigned int i = 0; i < max; i++) {
int xi = (int)roundf(x0 + i * stepx);
int yi = (int)roundf(y0 + i * stepy);
if ((0 <= xi) && (xi < X) && (0 <= yi) && (yi < Y)) {
(*rgbbuf)[yi][xi][0] = (*color)[0];
(*rgbbuf)[yi][xi][1] = (*color)[1];
(*rgbbuf)[yi][xi][2] = (*color)[2];
}
}
}
extern void draw_grid(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4], const float (*coord)[4][2], int divs, const char (*color)[3])
{
for (int i = 0; i <= divs; i++) {
for (int j = 0; j <= divs; j++) {
float x0 = (*coord)[0][0] + i * ((*coord)[1][0] - (*coord)[0][0]) / divs;
float y0 = (*coord)[0][1] + i * ((*coord)[1][1] - (*coord)[0][1]) / divs;
float x1 = (*coord)[2][0] + i * ((*coord)[3][0] - (*coord)[2][0]) / divs;
float y1 = (*coord)[2][1] + i * ((*coord)[3][1] - (*coord)[2][1]) / divs;
draw_line(X, Y, rgbstr, rgbbuf, x0, y0, x1, y1, color);
x0 = (*coord)[0][0] + i * ((*coord)[2][0] - (*coord)[0][0]) / divs;
y0 = (*coord)[0][1] + i * ((*coord)[2][1] - (*coord)[0][1]) / divs;
x1 = (*coord)[1][0] + i * ((*coord)[3][0] - (*coord)[1][0]) / divs;
y1 = (*coord)[1][1] + i * ((*coord)[3][1] - (*coord)[1][1]) / divs;
draw_line(X, Y, rgbstr, rgbbuf, x0, y0, x1, y1, color);
}
}
}
......
......@@ -2,16 +2,29 @@
#include <complex.h>
enum mode_t { MAGN, CMPL, PHSE, REAL, FLOW };
enum mode_t { MAGN, MAGN_VIRIDS, CMPL, CMPL_MYGBM, PHSE, PHSE_MYGBM, REAL, FLOW };
enum flip_t { OO, XO, OY, XY };
enum interp_t { NLINEAR, NEAREST };
extern complex float sample(int N, const float pos[N], const long dims[N], const long strs[N], const complex float* in);
extern complex float sample(int N, const float pos[N], const long dims[N], const long strs[N], enum interp_t interpolation, const complex float* in);
extern void resample(int X, int Y, long str, complex float* buf,
int N, const double pos[N], const double dx[N], const double dy[N],
const long dims[N], const long strs[N], const complex float* in);
const long dims[N], const long strs[N], enum interp_t interpolation, const complex float* in);
extern void draw(int X, int Y, int rgbstr, unsigned char* rgbbuf,
extern void draw(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4],
enum mode_t mode, float scale, float winlow, float winhigh, float phrot,
long str, const complex float* buf);
extern void update_buf(long xdim, long ydim, int N, const long dims[N], const long strs[N], const long pos[N], enum flip_t flip, enum interp_t interpolation, double xzoom, double yzoom,
long rgbw, long rgbh, const complex float* data, complex float* buf);
extern char* get_spec(int i);
extern void draw_line(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4], float x0, float y0, float x1, float y1, const char (*color)[3]);
extern void draw_grid(int X, int Y, int rgbstr, unsigned char (*rgbbuf)[Y][rgbstr / 4][4], const float (*coord)[4][2], int divs, const char (*color)[3]);
extern const char color_white[3];
extern const char color_red[3];
extern const char color_blue[3];
......@@ -11,6 +11,8 @@
#include <complex.h>
#include <stdbool.h>
#include <libgen.h>
#include <gtk/gtk.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>
......@@ -44,6 +46,8 @@ struct view_s {
struct view_s* prev;
bool sync;
bool cross_hair;
const char* name;
// geometry
......@@ -52,7 +56,7 @@ struct view_s {
int ydim;
double xzoom;
double yzoom;
enum flip_t { OO, XO, OY, XY } flip;
enum flip_t flip;
bool transpose;
// representation
......@@ -61,6 +65,7 @@ struct view_s {
double winlow;
double phrot;
double max;
enum interp_t interpolation;
complex float* buf;
......@@ -82,6 +87,7 @@ struct view_s {
// widgets
GtkComboBox* gtk_mode;
GtkComboBox* gtk_flip;
GtkComboBox* gtk_interp;
GtkWidget* gtk_drawingarea;
GtkWidget* gtk_viewport;
GtkAdjustment* gtk_winlow;
......@@ -90,10 +96,15 @@ struct view_s {
GtkAdjustment* gtk_aniso;
GtkEntry* gtk_entry;
GtkToggleToolButton* gtk_transpose;
GtkToggleToolButton* gtk_fit;
GtkAdjustment* gtk_posall[DIMS];
GtkCheckButton* gtk_checkall[DIMS];
GtkWidget *dialog; // Save dialog
GtkFileChooser *chooser; // Save dialog
GtkWindow *window;
// windowing
int lastx;
int lasty;
......@@ -157,8 +168,14 @@ extern gboolean update_view(struct view_s* v)
extern gboolean fit_callback(GtkWidget *widget, gpointer data)
{
UNUSED(widget);
struct view_s* v = data;
gboolean flag = gtk_toggle_tool_button_get_active(v->gtk_fit);
if (!flag)
return FALSE;
double aniso = gtk_adjustment_get_value(v->gtk_aniso);
GtkAllocation alloc;
......@@ -176,10 +193,31 @@ extern gboolean fit_callback(GtkWidget *widget, gpointer data)
}
extern gboolean refresh_callback(GtkWidget *widget, gpointer data)
extern gboolean configure_callback(GtkWidget *widget, GdkEvent* event, gpointer data)
{
struct view_s* v = data;
UNUSED(event);
return fit_callback(widget, data);
}
extern void view_setpos(struct view_s* v, unsigned int flags, const long pos[DIMS])
{
for (unsigned int i = 0; i < DIMS; i++) {
if (MD_IS_SET(flags, i)) {
gtk_adjustment_set_value(v->gtk_posall[i], pos[i]);
for (struct view_s* v2 = v->next; v2 != v; v2 = v2->next)
if (v->sync && v2->sync)
gtk_adjustment_set_value(v2->gtk_posall[i], pos[i]);
}
}
}
extern void view_refresh(struct view_s* v)
{
v->invalid = true;
long size = md_calc_size(DIMS, v->dims);
......@@ -194,13 +232,19 @@ extern gboolean refresh_callback(GtkWidget *widget, gpointer data)
v->max = max;
update_view(v);
}
extern gboolean refresh_callback(GtkWidget *widget, gpointer data)
{
UNUSED(widget);
view_refresh(data);
return FALSE;
}
extern gboolean geom_callback(GtkWidget *widget, gpointer data)
{
UNUSED(widget);
struct view_s* v = data;
for (int j = 0; j < DIMS; j++) {
......@@ -245,6 +289,7 @@ extern gboolean geom_callback(GtkWidget *widget, gpointer data)
v->yzoom = zoom;
v->flip = gtk_combo_box_get_active(v->gtk_flip);
v->interpolation = gtk_combo_box_get_active(v->gtk_interp);
v->transpose = gtk_toggle_tool_button_get_active(v->gtk_transpose);
if (v->transpose) {
......@@ -278,6 +323,7 @@ extern gboolean geom_callback(GtkWidget *widget, gpointer data)
extern gboolean window_callback(GtkWidget *widget, gpointer data)
{
UNUSED(widget);
struct view_s* v = data;
v->mode = gtk_combo_box_get_active(v->gtk_mode);
......@@ -301,61 +347,172 @@ extern gboolean window_callback(GtkWidget *widget, gpointer data)
return FALSE;
}
static void update_buf_view(struct view_s* v)
{
update_buf(v->xdim, v->ydim, DIMS, v->dims, v->strs, v->pos, v->flip, v->interpolation, v->xzoom, v->yzoom,
v->rgbw, v->rgbh, v->data, v->buf);
}
extern gboolean save_callback(GtkWidget *widget, gpointer data)
{
UNUSED(widget);
struct view_s* v = data;
if (CAIRO_STATUS_SUCCESS != cairo_surface_write_to_png(v->source, "save.png"))
// Prepare output filename
unsigned int bufsize = 255;
char name[bufsize];
char* cur = name;
const char* end = name + bufsize;
cur += snprintf(cur, end - cur, "%s", v->name);
char dir[bufsize];
strncpy(dir, v->name, bufsize);
for ( int i = 0; i < DIMS; i++) {
if ( v->dims[i] != 1 && i != v->xdim && i != v->ydim ){
cur += snprintf(cur, end - cur, "_%s_%04ld", get_spec(i), v->pos[i]);
}
}
cur += snprintf(cur, end - cur, ".png");
v->dialog = gtk_file_chooser_dialog_new ("Save File",
v->window,
GTK_FILE_CHOOSER_ACTION_SAVE,
"Cancel",
GTK_RESPONSE_CANCEL,
"Save",
GTK_RESPONSE_ACCEPT,
NULL);
v->chooser = GTK_FILE_CHOOSER (v->dialog);
gtk_file_chooser_set_current_name (v->chooser, basename(name));
// Outputfolder = Inputfolder
gtk_file_chooser_set_current_folder (v->chooser, dirname(dir));
gtk_file_chooser_set_do_overwrite_confirmation (v->chooser, TRUE);
gint res = gtk_dialog_run (GTK_DIALOG (v->dialog));
if (res == GTK_RESPONSE_ACCEPT) {
// export single image
char *filename = gtk_file_chooser_get_filename (v->chooser);
if (CAIRO_STATUS_SUCCESS != cairo_surface_write_to_png(v->source, filename))
gtk_entry_set_text(v->gtk_entry, "Error: writing image file.\n");
gtk_entry_set_text(v->gtk_entry, "Saved to: save.png");
gtk_entry_set_text(v->gtk_entry, "Saved!");
g_free (filename);
}
gtk_widget_destroy (v->dialog);
return FALSE;
}
extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
extern gboolean save_movie_callback(GtkWidget *widget, gpointer data)
{
UNUSED(widget);
struct view_s* v = data;
if (v->invalid) {
unsigned int bufsize = 255;
char dir[bufsize];
strncpy(dir, v->name, bufsize);
double dpos[DIMS];
for (int i = 0; i < DIMS; i++)
dpos[i] = v->pos[i];
int frame_dim = 10;
dpos[v->xdim] = 0.;
dpos[v->ydim] = 0.;
v->dialog = gtk_file_chooser_dialog_new("Export movie to folder",
v->window,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
"Cancel",
GTK_RESPONSE_CANCEL,
"Export",
GTK_RESPONSE_ACCEPT,
NULL);
double dx[DIMS];
for (int i = 0; i < DIMS; i++)
dx[i] = 0.;
v->chooser = GTK_FILE_CHOOSER(v->dialog);
// Outputfolder = Inputfolder
gtk_file_chooser_set_current_folder(v->chooser, dirname(dir));
gint res = gtk_dialog_run (GTK_DIALOG (v->dialog));
if (res == GTK_RESPONSE_ACCEPT) {
char *chosen_dir = gtk_file_chooser_get_filename(v->chooser);
char output_name[bufsize];
for (unsigned int f = 0; f < v->dims[frame_dim]; f++) {
v->pos[frame_dim] = f;
update_buf_view(v);
draw(v->rgbw, v->rgbh, v->rgbstr, (unsigned char(*)[v->rgbw][v->rgbstr / 4][4])v->rgb,
v->mode, 1. / v->max, v->winlow, v->winhigh, v->phrot,
v->rgbw, v->buf);
char suff[16];
snprintf(suff, 16, "/mov-%04d.png", f);
strncpy(output_name, chosen_dir, bufsize - 16);
strncat(output_name, suff, 16);
if (CAIRO_STATUS_SUCCESS != cairo_surface_write_to_png(v->source, output_name))
gtk_entry_set_text(v->gtk_entry, "Error: writing image file.\n");
}
g_free(chosen_dir);
gtk_entry_set_text(v->gtk_entry, "Movie exported.");
}
gtk_widget_destroy (v->dialog);
return FALSE;
}
double dy[DIMS];
for (int i = 0; i < DIMS; i++)
dy[i] = 0.;
dx[v->xdim] = 1.;
dy[v->ydim] = 1.;
struct xy_s { float x; float y; };
static struct xy_s pos2screen(const struct view_s* v, /*const+*/float (*pos)[DIMS])
{
float x = (*pos)[v->xdim];
float y = (*pos)[v->ydim];
if ((XY == v->flip) || (XO == v->flip))
x = v->dims[v->xdim] - 1 - x;
if ((XY == v->flip) || (XO == v->flip)) {
if ((XY == v->flip) || (OY == v->flip))
y = v->dims[v->ydim] - 1 - y;
dpos[v->xdim] = v->dims[v->xdim] - 1;
dx[v->xdim] *= -1.;
x *= v->xzoom;
y *= v->yzoom;
return (struct xy_s){ x, y };
}
if ((XY == v->flip) || (OY == v->flip)) {
static void screen2pos(const struct view_s* v, float (*pos)[DIMS], struct xy_s xy)
{
for (unsigned int i = 0; i < DIMS; i++)
(*pos)[i] = v->pos[i];
float x = xy.x / v->xzoom;
float y = xy.y / v->yzoom;
if ((XY == v->flip) || (XO == v->flip))
x = v->dims[v->xdim] - 1 - x;
dpos[v->ydim] = v->dims[v->ydim] - 1;
dy[v->ydim] *= -1.;
if ((XY == v->flip) || (OY == v->flip))
y = v->dims[v->ydim] - 1 - y;
(*pos)[v->xdim] = x;
(*pos)[v->ydim] = y;
}
dx[v->xdim] = dx[v->xdim] / v->xzoom;
dy[v->ydim] = dy[v->ydim] / v->yzoom;
extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
{
UNUSED(widget);
struct view_s* v = data;
if (v->invalid) {
resample(v->rgbw, v->rgbh, v->rgbw, v->buf,
DIMS, dpos, dx, dy, v->dims, v->strs, v->data);
update_buf_view(v);
v->invalid = false;
v->rgb_invalid = true;
......@@ -363,7 +520,7 @@ extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
if (v->rgb_invalid) {
draw(v->rgbw, v->rgbh, v->rgbstr, v->rgb,
draw(v->rgbw, v->rgbh, v->rgbstr, (unsigned char(*)[v->rgbw][v->rgbstr / 4][4])v->rgb,
v->mode, 1. / v->max, v->winlow, v->winhigh, v->phrot,
v->rgbw, v->buf);
......@@ -374,6 +531,24 @@ extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
// add_text(v->source, 3, 3, 10, v->name);
if (v->cross_hair) {
float posi[DIMS];
for (unsigned int i = 0; i < DIMS; i++)
posi[i] = v->pos[i];
struct xy_s xy = pos2screen(v, &posi);
draw_line(v->rgbw, v->rgbh, v->rgbstr, (unsigned char (*)[v->rgbw][v->rgbstr / 4][4])v->rgb,
0, (int)xy.y, v->rgbw - 1, (int)xy.y, (v->xdim > v->ydim) ? &color_red : &color_blue);
draw_line(v->rgbw, v->rgbh, v->rgbstr, (unsigned char (*)[v->rgbw][v->rgbstr / 4][4])v->rgb,
(int)xy.x, 0, (int)xy.x, v->rgbh - 1, (v->xdim < v->ydim) ? &color_red : &color_blue);
// float coords[4][2] = { { 0, 0 }, { 100, 0 }, { 0, 100 }, { 100, 100 } };
// draw_grid(v->rgbw, v->rgbh, v->rgbstr, (unsigned char (*)[v->rgbw][v->rgbstr / 4][4])v->rgb, &coords, 4, &color_white);
}
cairo_set_source_surface(cr, v->source, 0, 0);
cairo_paint(cr);
return FALSE;
......@@ -382,7 +557,7 @@ extern gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
struct view_s* create_view(const char* name, long* pos, const long dims[DIMS], const complex float* data)
struct view_s* create_view(const char* name, const long pos[DIMS], const long dims[DIMS], const complex float* data)
{
long sq_dims[2] = { 0 };
......@@ -399,13 +574,16 @@ struct view_s* create_view(const char* name, long* pos, const long dims[DIMS], c
v->next = v->prev = v;
v->sync = true;
v->cross_hair = false;
v->name = name;
v->pos = pos;
v->max = 1.;
if (NULL == v->pos)
v->pos = xmalloc(DIMS * sizeof(long));
for (int i = 0; i < DIMS; i++)
v->pos[i] = (NULL != pos) ? pos[i] : 0;
v->xdim = sq_dims[0];
v->ydim = sq_dims[1];
......@@ -421,10 +599,6 @@ struct view_s* create_view(const char* name, long* pos, const long dims[DIMS], c
md_calc_strides(DIMS, v->strs, dims, sizeof(complex float));
v->data = data;
for (int i = 0; i < DIMS; i++)
v->pos[i] = 0;
v->winlow = 0.;
v->winhigh = 1.;
v->phrot = 0.;
......@@ -453,8 +627,9 @@ static void delete_view(struct view_s* v)
}
extern gboolean toggle_sync(GtkWidget *widget, GtkToggleButton* button, gpointer data)
extern gboolean toggle_sync(GtkToggleButton* button, gpointer data)
{
UNUSED(button);
struct view_s* v = data;
v->sync = !v->sync;
......@@ -462,17 +637,15 @@ extern gboolean toggle_sync(GtkWidget *widget, GtkToggleButton* button, gpointer
}
static void update_status_bar(struct view_s* v, int x2, int y2)
static void update_status_bar(struct view_s* v, /*const*/ float (*pos)[DIMS])
{
float pos[DIMS];
for (int i = 0; i < DIMS; i++)
pos[i] = v->pos[i];
int x2 = (*pos)[v->xdim];
int y2 = (*pos)[v->ydim];
pos[v->xdim] = x2;
pos[v->ydim] = y2;
(*pos)[v->xdim] = x2;
(*pos)[v->ydim] = y2;
complex float val = sample(DIMS, pos, v->dims, v->strs, v->data);
complex float val = sample(DIMS, *pos, v->dims, v->strs, v->interpolation, v->data);
// FIXME: make sure this matches exactly the pixel
char buf[100];
......@@ -483,37 +656,50 @@ static void update_status_bar(struct view_s* v, int x2, int y2)
}
extern void set_position(struct view_s* v, unsigned int dim, unsigned int p)
{
v->pos[dim] = p;
gtk_adjustment_set_value(v->gtk_posall[dim], p);
for (struct view_s* v2 = v->next; v2 != v; v2 = v2->next)
if (v->sync && v2->sync)
gtk_adjustment_set_value(v2->gtk_posall[dim], p);
}
extern gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
UNUSED(widget);
struct view_s* v = data;
int y = event->y;
int x = event->x;
struct xy_s xy = { event->x, event->y };
int x2 = x / v->xzoom;
int y2 = y / v->yzoom;
float pos[DIMS];
screen2pos(v, &pos, xy);
if (event->button == GDK_BUTTON_SECONDARY) {
if (event->button == GDK_BUTTON_PRIMARY) {
v->pos[v->xdim] = x2;
v->pos[v->ydim] = y2;
v->cross_hair = false;
gtk_adjustment_set_value(v->gtk_posall[v->xdim], x2);
gtk_adjustment_set_value(v->gtk_posall[v->ydim], y2);
v->rgb_invalid = true;
update_view(v);
}
update_status_bar(v, x2, y2);
if (event->button == GDK_BUTTON_SECONDARY) {
for (struct view_s* v2 = v->next; v2 != v; v2 = v2->next) {
v->cross_hair = true;
if (v->sync && v2->sync) {
set_position(v, v->xdim, pos[v->xdim]);
set_position(v, v->ydim, pos[v->ydim]);
gtk_adjustment_set_value(v2->gtk_posall[v->xdim], x2);
gtk_adjustment_set_value(v2->gtk_posall[v->ydim], y2);
update_status_bar(v, &pos);
update_status_bar(v2, x2, y2);
}
}
for (struct view_s* v2 = v->next; v2 != v; v2 = v2->next)
if (v->sync && v2->sync)
update_status_bar(v2, &pos);
}
return FALSE;
}
......@@ -521,6 +707,7 @@ extern gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpo
extern gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
{
UNUSED(widget);
struct view_s* v = data;
int y = event->y;
......@@ -578,6 +765,8 @@ static int nr_windows = 0;
extern gboolean window_close(GtkWidget *widget, GdkEvent* event, gpointer data)
{
UNUSED(widget);
UNUSED(event);
struct view_s* v = data;
delete_view(v);
......@@ -591,7 +780,7 @@ extern gboolean window_close(GtkWidget *widget, GdkEvent* event, gpointer data)
extern struct view_s* window_new(const char* name, long* pos, const long dims[DIMS], const complex float* x)
extern struct view_s* window_new(const char* name, const long pos[DIMS], const long dims[DIMS], const complex float* x)
{
struct view_s* v = create_view(name, pos, dims, x);
......@@ -622,7 +811,12 @@ extern struct view_s* window_new(const char* name, long* pos, const long dims[DI
v->gtk_flip = GTK_COMBO_BOX(gtk_builder_get_object(builder, "flip"));
gtk_combo_box_set_active(v->gtk_flip, 0);
v->gtk_interp = GTK_COMBO_BOX(gtk_builder_get_object(builder, "interp"));
gtk_combo_box_set_active(v->gtk_interp, 0);
v->gtk_transpose = GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(builder, "transpose"));
v->gtk_fit = GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(builder, "fit"));
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(v->gtk_fit), TRUE);
for (int j = 0; j < DIMS; j++) {
......@@ -630,7 +824,7 @@ extern struct view_s* window_new(const char* name, long* pos, const long dims[DI
snprintf(pname, 10, "pos%02d", j);
v->gtk_posall[j] = GTK_ADJUSTMENT(gtk_builder_get_object(builder, pname));
gtk_adjustment_set_upper(v->gtk_posall[j], v->dims[j] - 1);
gtk_adjustment_set_value(v->gtk_posall[j], 0);
gtk_adjustment_set_value(v->gtk_posall[j], v->pos[j]);
snprintf(pname, 10, "check%02d", j);
v->gtk_checkall[j] = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, pname));
......@@ -639,17 +833,22 @@ extern struct view_s* window_new(const char* name, long* pos, const long dims[DI
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(v->gtk_checkall[v->xdim]), TRUE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(v->gtk_checkall[v->ydim]), TRUE);
#if 0
gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "toolbar1")));
gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "toolbar2")));
gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "entry")));
#endif
gtk_builder_connect_signals(builder, v);
GtkWindow* window = GTK_WINDOW(gtk_builder_get_object(builder, "window1"));
g_object_unref(G_OBJECT(builder));
v->window = window;
gtk_window_set_title(window, name);
gtk_widget_show(GTK_WIDGET(window));
nr_windows++;
// fit_callback(NULL, v);
refresh_callback(NULL, v);
geom_callback(NULL, v);
window_callback(NULL, v);
......@@ -657,7 +856,6 @@ extern struct view_s* window_new(const char* name, long* pos, const long dims[DI
return v;
}
void window_connect_sync(struct view_s* v, struct view_s* v2)
{
// add to linked list for sync
......@@ -669,17 +867,23 @@ void window_connect_sync(struct view_s* v, struct view_s* v2)
window_callback(NULL, v);
}
extern gboolean window_clone(GtkWidget *widget, gpointer data)
struct view_s* view_clone(struct view_s* v, const long pos[DIMS])
{
struct view_s* v = data;
struct view_s* v2 = window_new(v->name, v->pos, v->dims, v->data);
struct view_s* v2 = window_new(v->name, pos, v->dims, v->data);
window_connect_sync(v, v2);
return FALSE;
return v2;
}
extern gboolean window_clone(GtkWidget *widget, gpointer data)
{
UNUSED(widget);
struct view_s* v = data;
view_clone(v, v->pos);
return FALSE;
}
......@@ -5,6 +5,10 @@
struct view_s;
extern struct view_s* window_new(const char* name, long* pos, const long dims[DIMS], const complex float* x);
extern struct view_s* window_new(const char* name, const long pos[DIMS], const long dims[DIMS], const complex float* x);
extern void window_connect_sync(struct view_s* a, struct view_s* b);
extern void view_refresh(struct view_s* v);
extern void view_setpos(struct view_s* v, unsigned int flags, const long pos[DIMS]);
extern struct view_s* view_clone(struct view_s* v, const long pos[DIMS]);
......@@ -15,14 +15,23 @@
</columns>
<data>
<row>
<col id="0" translatable="yes">MAGNITUDE</col>
<col id="0" translatable="yes">MAGNITUDE (gray)</col>
</row>
<row>
<col id="0" translatable="yes">MAGNITUDE (viridis)</col>
</row>
<row>
<col id="0" translatable="yes">COMPLEX</col>
</row>
<row>
<col id="0" translatable="yes">COMPLEX (MYGBM)</col>
</row>
<row>
<col id="0" translatable="yes">PHASE</col>
</row>
<row>
<col id="0" translatable="yes">PHASE (MYGBM)</col>
</row>
<row>
<col id="0" translatable="yes">REAL</col>
</row>
......@@ -51,6 +60,20 @@
</row>
</data>
</object>
<object class="GtkListStore" id="liststore3">
<columns>
<!-- column-name text -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">NLIN</col>
</row>
<row>
<col id="0" translatable="yes">NEAREST</col>
</row>
</data>
</object>
<object class="GtkAdjustment" id="pos00">
<property name="step_increment">1</property>
<property name="page_increment">10</property>
......@@ -134,6 +157,8 @@
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="default_height">600</property>
<property name="default_width">600</property>
<signal name="delete-event" handler="window_close" swapped="no"/>
<child>
<object class="GtkBox" id="box1">
......@@ -196,21 +221,36 @@
</packing>
</child>
<child>
<object class="GtkToolItem" id="toolbutton4">
<object class="GtkToggleToolButton" id="fit">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">fit</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-zoom-fit</property>
<signal name="clicked" handler="fit_callback" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="fit">
<object class="GtkToolItem" id="toolbutton11">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<signal name="clicked" handler="fit_callback" swapped="no"/>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="image2">
<object class="GtkComboBox" id="flip">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-zoom-fit</property>
</object>
<property name="halign">start</property>
<property name="model">liststore2</property>
<property name="active">0</property>
<signal name="changed" handler="geom_callback" swapped="no"/>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
......@@ -221,19 +261,19 @@
</packing>
</child>
<child>
<object class="GtkToolItem" id="toolbutton11">
<object class="GtkToolItem" id="toolbutton15">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkComboBox" id="flip">
<object class="GtkComboBox" id="interp">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="model">liststore2</property>
<property name="model">liststore3</property>
<property name="active">0</property>
<signal name="changed" handler="geom_callback" swapped="no"/>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2"/>
<object class="GtkCellRendererText" id="cellrenderertext3"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
......@@ -285,6 +325,31 @@
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolItem" id="toolbutton14">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button3">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="save_movie_callback" swapped="no"/>
<child>
<object class="GtkImage" id="image4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon-name">media-record</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="toolbutton12">
<property name="visible">True</property>
......@@ -489,7 +554,7 @@
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="min_content_width">100</property>
<property name="min_content_height">200</property>
<property name="min_content_height">100</property>
<child>
<object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
......@@ -502,6 +567,7 @@
<signal name="button-press-event" handler="button_press_event" swapped="no"/>
<signal name="draw" handler="draw_callback" swapped="no"/>
<signal name="motion-notify-event" handler="motion_notify_event" swapped="no"/>
<signal name="configure-event" handler="configure_callback" swapped="no"/>
</object>
</child>
</object>
......