File: hacking.tex

package info (click to toggle)
darktable 5.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 62,864 kB
  • sloc: ansic: 361,898; cpp: 102,446; xml: 19,813; lisp: 14,539; sh: 3,771; javascript: 3,264; perl: 1,925; python: 1,485; ruby: 975; makefile: 543; asm: 46; sql: 38; awk: 21
file content (350 lines) | stat: -rw-r--r-- 12,723 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
\documentclass[a4paper,twoside]{scrartcl}

\usepackage{graphicx,color}
\graphicspath{{images/}{../htdocs/images/header/}}

\usepackage{mparhack}

% \usepackage[a4paper]{geometry}
% \geometry{%
% twoside,%
% %height=.7\paperheight,%
% %width=.7\paperwidth,%
% top=.1\paperheight,%
% bottom=.2\paperheight,%
% left=.1\paperwidth,%
% right=.2\paperwidth%
% %bindingoffset
% }

\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead{}
\fancyfoot{}
\fancyfoot[LE,RO]{\iffloatpage{}{\thepage}}
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0pt}
\setlength{\oddsidemargin}{.1\paperwidth}
\setlength{\evensidemargin}{.2\paperwidth}
\setlength{\headheight}{.1\paperheight}
\setlength{\headsep}{0pt}
\setlength{\topmargin}{0pt}
\setlength{\voffset}{-1in}
\setlength{\hoffset}{-1in}
\setlength{\textwidth}{.7\paperwidth}
\setlength{\textheight}{.7\paperheight}
\setlength{\marginparwidth}{.1\paperwidth}

\newcommand{\nicesection}[2]{%
\cleardoublepage
\fbox{\includegraphics[width=\linewidth]{#1}}%
\vspace*{-1em}%
\section{\hfill #2}
\hrule
\vspace*{\baselineskip}%
}

\fboxsep0pt
\setlength{\parindent}{0pt}

\newcommand{\todo}[1]{{\color{red}\bf TODO: #1}}
\newcommand{\comment}[1]{}
\definecolor{codecol}{rgb}{0.1,0.2,0.5}
\newcommand{\code}[1]{\texttt{\color{codecol}#1}}

\frenchspacing
% \usepackage[T1]{fontenc}
% \usepackage[condensed,math]{iwona}

%\usepackage[T1]{fontenc}
%\usepackage[urw-garamond]{mathdesign}

\usepackage[T1]{fontenc}
\usepackage[scaled]{helvet}
\renewcommand{\familydefault}{\sfdefault}

%\setkomafont{sectioning}{\sfdefault}


\title{darktable Programmer's Guide}
\author{hanatos}

\begin{document}

\fbox{\includegraphics[width=\linewidth]{header12}}%
\vspace*{-1em}%
\section*{\hfill darktable Programmer's Guide}
\hrule

\vspace*{4\baselineskip}

{\hfill version \input version.tex }

\thispagestyle{empty}

\newpage
\tableofcontents


\nicesection{header1}{Introduction}
\label{sec:introduction}


\nicesection{header2}{System Layout}

\resizebox{\linewidth}{!}{\input{graphs/system.pdftex_t}}

\subsection{Module Descriptions}

\begin{description}
  \item[gui] using gtk2 and cairo.
\end{description}
\begin{description}
  \item[control]
  \item[control, scheduler] using pthreads and a custom job queuing system.
\end{description}
\begin{description}
  \item[image]
  \item[image cache]
  \item[mipmap cache]
  \item[db]
  \item[imageio]
\end{description}
\begin{description}
  \item[library] this is the lighttable module.
  \item[film]
\end{description}
\begin{description}
  \item[develop] this implements the darktable.
  \item[pixelpipe]
  \item[image operation (iop) modules, aka plug-ins]
\end{description}

\newpage
\subsection{Image Loading Data Flow}

\paragraph{Related Modules}
\begin{itemize}
  \item imageio \code{dt\_imageio\_*}
  \item db (messily hidden in sqlite3 statements all over the place)
  \item image cache \code{dt\_image\_cache\_*}
  \item mip cache \code{dt\_mipmap\_cache\_*}
  \item image \code{dt\_image\_t}
\end{itemize}

\paragraph{in image cache}
\begin{itemize}
  \item \code{dt\_image\_import}

  db $\rightarrow$ image struct, trigger imageio disk $\rightarrow$ image entry in db if miss,
                metadata through libraw/magick
  
 
\end{itemize}

\paragraph{in mip cache}
\begin{itemize}
  \item \code{dt\_image\_get}

      db $\rightarrow$ mip[0--4], trigger imageio disk $\rightarrow$ mip4 and mip4 $\rightarrow$ mip[0-3] if miss.

  
      db $\rightarrow$ mipf, trigger mip4 $\rightarrow$ mipf or pixels $\rightarrow$ mipf if miss.
\end{itemize}

\paragraph{in imageio}
\begin{itemize}
  \item \code{dt\_imageio\_open\_preview}

    disk $\rightarrow$ mip[0--4] entries in db (load thumbnail).
    \begin{itemize}
      \item[\todo{}]  \code{dt\_imageio\_open\_ldr\_preview}
      \item \code{dt\_imageio\_open\_raw\_preview}
    \end{itemize}
  \item mip4 $\rightarrow$ mipf (by guessed reverse gamma) \code{dt\_image\_preview\_to\_raw}.
  \item full pixels $\rightarrow$ mipf (downscaling) \code{dt\_image\_raw\_to\_preview}.
  \item mip4 $\rightarrow$ mip[0--3] \code{dt\_image\_update\_mipmaps}.
\end{itemize}

image import: only load \code{dt\_image\_t} and mip[0--4] to database.

\code{dt\_image\_get}: check mipmap cache, check database, else \code{dt\_imageio\_open[\_preview]}.

The buffers are as follows:

\begin{description}
  \item[\code{DT\_IMAGE\_MIP0-4}] are used for rendering in light table mode. These are either loaded from the embedded
    thumbnail in the raw files (if the \code{never\_use\_embedded\_thumb} key is not set), or store small versions of
    processed buffers.

    The function \code{dt\_imageio\_open\_preview} will fill these low-dynamic range buffers ready for display. If a history
    stack is present (i.e.\ the image is {\em altered}), this function will load \code{MIPF} instead.

  \item[\code{DT\_IMAGE\_MIPF}] is used by the preview pipe or by pipelines spawned by the light table when creating
    \code{DT\_IMAGE\_MIP0-4}. It stores a capped-size four float per pixel representation of the input image.

    This buffer is needed to reduce the overall mem requirements and still process multiple thumbnails of large images
    in parallel. darktable rather stores and prefetches a few low-resolution \code{MIPF} buffers instead of full images.

    \code{MIPF} can never be explicitly loaded.

    \code{MIPF} are written if a prefetch is requested for fast darkroom mode entering later on, or by \code{dt\_imageio\_open\_preview}
    if the image is altered. It is also written if a full image is requested, to avoid duplicate file accesses in this case.

  \item[\code{DT\_IMAGE\_FULL}] is the full image buffer as read from disk. That is, raw images will store one \code{uint16\_t}
    per pixel, mosaiced input data, while high dynamic range input will result in a four float buffer.

\end{description}


\newpage
\subsection{Cache Interfaces}

\subsubsection{Image Cache}

\code{dt\_image\_cache\_t}

\subsubsection{Mipmap Cache}

\code{dt\_image\_t}

\begin{description}
  \item{\code{dt\_image\_get}} get buffer or, if missed, a lower resolution (launch job in bg for correct resolution)
  \item{\code{dt\_image\_load}} Load buffer in this thread, return exactly this resolution.
    No locking is performed, so be sure to acquire the lock using \code{dt\_image\_alloc} before.
\end{description}

\subsubsection{Homebrew Pixelpipe Cache}

\newpage
\subsection{Plug-in Interface}

For examples, have a look at \code{src/iop/*.\{h,c\}}, and also see the method declarations in \code{src/common/imageop.h}.

Pixel processing is done in pipelines (\code{src/develop/pixelpipe\_hb.c}) with fixed order of the modules,
observe the current status with e.g.

\code{grep priority src/iop/*.c | sort -t '=' -k 2}.

At the time of this writing, the main pixel pipeline stack is organised as follows:

\medskip

\begin{tabular}{lrl}
module name & priority & input color format \\
\hline
rawimport      &  100  &  - \\ 
exposure       &  150  &  fff input color space \\
temperature    &  200  &  fff input color space \\
highlights     &  250  &  fff input color space \\
basecurve      &  260  &  fff input color space \\
profile\_gamma &  299  &  fff input color space \\
colorin        &  300  &  fff input color space \\
colortransfer  &  350  &  fff $L^*a^*b^*$ \\
equalizer      &  500  &  fff $L^*a^*b^*$ \\
monochrome     &  550  &  fff $L^*a^*b^*$ \\
tonecurve      &  700  &  fff $L^*a^*b^*$ \\
colorzones     &  750  &  fff $L^*a^*b^*$ \\
colorcorrection&  800  &  fff $L^*a^*b^*$ \\
colorout       &  900  &  fff $L^*a^*b^*$ \\
lens           &  940  &  fff output color space \\
clipping       &  950  &  fff output color space \\
grain          &  965  &  fff output color space \\
clahe          &  966  &  fff output color space \\
velvia         &  967  &  fff output color space \\
splittoning    &  968  &  fff output color space \\
vignette       &  970  &  fff output color space \\
sharpen        &  990  &  fff output color space \\
gamma          & 1000  &  fff output color space \\
               &   -   &  ccc output color space \\
\end{tabular}

\medskip

where fff is $3\times32$ bit float, ccc is $3\times8$ bit int, and the input
color space depends on your camera or type of input data, and the output color space will
be sRGB (including gamma correction, i.e.\ it is non-linear) most of the time.

$L^*a^*b^*$ is a special variant of $L^*ab$, where $L^* \in [0, 100]$ and $a, b \in [-128, 128]$, but $a^* = a/L^*$ and $b^* = b/L^*$.
This makes sure that changes in $L^*$ transparently result in the correct adjustment in saturation:
$a_{out} = a_{in} \cdot L^*_{out}/L^*_{in}$ and
$b_{out} = b_{in} \cdot L^*_{out}/L^*_{in}$.


Each module has to implement a \code{process} function, which is responsible for processing of three types of
pipelines: preview, full, and export. Most of the time, this can be handled transparently, i.e.\ needs no special
handling in the module. The pipelines are as follows:

\begin{description}
  \item[preview] all of the image, but downsampled to low resolution for the navigation view, approximate full image statistics, and fast scrolling.
  \item[full] full resolution, but only the part that can currently be seen (the region of interest, roi, will be adjusted accordingly).
  \item[export] full image at full resolution, no gui data is inited for the module.
\end{description}

and can be identified by the pipeline struct, which carries a \code{pipe->type} flag. This struct can in turn be found
via the pipeline data piece which is passed to \code{process}: \code{piece->pipe}.

\paragraph{Regions of Interest}

A region of interest holds $x,y,w,h$, and scale information. The semantics are as follows: multiply the whole resolution image by
the scale value, then crop it to the window defined by $x, y, w, h$. The passed input buffer will be a contiguous block of values as defined by
the input color space, pixel by pixel and row by row. The output buffer should be in the same format, but the extent should match the
output region of interest.


\subsubsection{Most important Gui Callbacks}

\begin{description}
  \item \code{gui\_init} gui thread, init the widget (not called for export)
  \item \code{gui\_update} gui thread, make the gui match the modules parameters (not called for export)
  \item \code{commit\_params} core thread + gui thread in synch, copy module->params to module->data
  \item \code{process} core thread, execute the op on the input buffer
  \item \code{modify\_roi\_in}
  \item \code{modify\_roi\_out} core thread, optional, only needed if input and output buffers are of different size.
    For examples, see \code{src/iop/lens.c} and \code{src/iop/clipping.c}.
\end{description}

\subsubsection{Data Structures}

\begin{description}
  \item[\code{dt\_iop\_*\_params\_t module->\{params, default\_params, factory\_params\}}]

  This struct should only be modified by the gui thread. The three fields exist only once per module: \code{params}
  store the currently active parameters, \code{default\_params} are the default parameters (possibly adjusted by the
  user), and \code{factory\_params} are dt's factory defaults (automatically copied by the core after \code{init} has been
  called).

  Also, don't store pointers to additional memory in this struct. It will be
  stored in the database as blob and copied byte-wise as you defined it. This
  means that your pointer will point to garbage memory after leaving/re-entering
  darkroom mode, or during export.

  \item[\code{dt\_iop\_*\_data\_t piece->data}]
  This struct lives in pixel pipeline domain, and thus exists once for the full and once for the preview pipeline.
  It should only be modified by the core thread (which calls \code{commit\_params} and \code{process}).

  \item[\code{dt\_iop\_*\_gui\_data\_t module->gui\_data}]
  You can use this struct to store your gui data (from the gui thread, obviously). It exists once per module and should be inited in \code{gui\_init} and
  cleaned up in \code{gui\_cleanup}. Note that gtk+ widgets are cleaned up implicitly while the widget is destroyed.

  \item[\code{dt\_iop\_*\_global\_data\_t module->data}]
  Core thread global data for all pipes (such as lensfun description database).
\end{description}


\subsubsection{A most useless Example}


\todo{script to generate as up-to-date minimal dt header set to compile external plugins}

\todo{a silly template module line by line: render a checker board on top of your input image.}

See \code{src/iop/useless.c}.

Change \code{src/iop/Makefile.am}:
\begin{verbatim}
libuseless_la_SOURCES=useless.c
dtplugins_LTLIBRARIES=libtonecurve.la [..] libcolortransfer.la libuseless.la
\end{verbatim}

\end{document}