#include "palette.h"
#include "timeline.h"
+enum thread_preview {
+ PREVIEW_OFF,
+ PREVIEW_NEW,
+ PREVIEW_ALLOC,
+ PREVIEW_ON,
+ PREVIEW_FREE,
+};
+
+static int thread_debug = 0;
+static int thread_running = 0;
+static enum thread_preview thread_preview = PREVIEW_OFF;
+
struct colorize_priv {
GtkWidget *window;
GdkPixbuf *pixbuf;
darrayDone();
}
+
+/* real time thread */
+
+enum thread_preview {
+ PREVIEW_OFF,
+ PREVIEW_NEW,
+ PREVIEW_ALLOC,
+ PREVIEW_ON,
+};
+
+static int thread_debug = 0;
+static int thread_running = 0;
+static enum thread_preview thread_preview = PREVIEW_OFF;
+
+static void *colorize_thread(void *arg)
+{
+ struct colorize *col = NULL;
+ darray_t *gI = NULL, *cI = NULL, *I = NULL, *mI = NULL;
+ unsigned char *mark_buffer = NULL;
+ int dims[4];
+ int features, change_bc = 0, change_alpha = 0;
+ char *feat_names[20];
+ int i, j;
+ int c;
+ int rc;
+ if (thread_debug)
+ printf("%s: thread entered\n", __func__);
+
+loop:
+ gdk_threads_enter();
+ if (thread_running < 1) {
+ if (thread_debug)
+ printf("%s: thread leaving\n", __func__);
+ thread_running = 0;
+ goto reset;
+ }
+ if (thread_preview == PREVIEW_NEW) {
+ thread_preview = PREVIEW_ALLOC;
+ goto reset;
+ }
+ if (thread_preview == PREVIEW_ALLOC) {
+ int width, height;
+
+ if (thread_debug)
+ printf("%s: new preview\n", __func__);
+ width = img_width;
+ height = img_height;
+
+ /* alloc gI and cI array */
+ dims[0] = width; dims[1] = height; dims[2] = 3; dims[3] = 1;
+ gI = darrayCreate(4, dims);
+ if (!gI) {
+ printerror("No memory: failed to create grey image array");
+ thread_preview = PREVIEW_OFF;
+ goto reset;
+ }
+ dims[0] = width; dims[1] = height; dims[2] = 3; dims[3] = 1;
+ cI = darrayCreate(4, dims);
+ if (!cI) {
+ printerror("No memory: failed to create marked image array");
+ thread_preview = PREVIEW_OFF;
+ goto reset;
+ }
+ mark_buffer = malloc(width*height);
+ if (!mark_buffer) {
+ printerror("No memory: failed to create marked index image");
+ thread_preview = PREVIEW_OFF;
+ goto reset;
+ }
+ thread_preview = PREVIEW_ON;
+ }
+ if (thread_preview == PREVIEW_ON) {
+ int width, height;
+ double *ptr_gI = NULL, *ptr_cI = NULL, *ptr_y = NULL, *ptr_u = NULL, *ptr_v = NULL, *ptr_a = NULL, *ptr_r = NULL, *ptr_b = NULL, *ptr_c = NULL, *ptr_m = NULL;
+
+ if (thread_debug)
+ printf("%s: prepare gI/cI\n", __func__);
+ width = img_width;
+ height = img_height;
+
+ /* generate grey image array */
+ ptr_gI = darrayGetPr(gI);
+ img2array_short(img_grey_buffer, width, height, ptr_gI, width, height);
+ /* generade marked color image */
+ ptr_cI = darrayGetPr(cI);
+ img2array_short(img_grey_buffer, width, height, ptr_cI, width, height);
+ /* copy mark buffer */
+ memcpy(mark_buffer, img_mark_buffer, width*height);
+
+ /* prepare while unlocked */
+ gdk_threads_leave();
+ /* apply marked pixles */
+ change_bc = change_alpha = 0;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ /* do not apply mask on index 0 */
+ c = mark_buffer[i*width+j];
+ if (c == 0)
+ continue;
+#if 0
+iterative colorization does not work with change_bc and change_alpha, because it alters I image before and after colorization
+ /* check for any brightness/contrast change */
+ if (mark_palette[c-1].bright != 0 || mark_palette[c-1].contrast != 1)
+ change_bc = 1;
+ /* check for any alpha change */
+ if (mark_palette[c-1].alpha < 1)
+ change_alpha = 1;
+#endif
+ /* do not apply white pixles, this meas: keep original color */
+ if (mark_palette[c-1].r == 255 && mark_palette[c-1].g == 255 && mark_palette[c-1].b == 255)
+ continue;
+ ptr_cI[i*width+j] = mark_palette[c-1].r / 255.0F;
+ ptr_cI[i*width+j + width*height] = mark_palette[c-1].g / 255.0F;
+ ptr_cI[i*width+j + width*height*2] = mark_palette[c-1].b / 255.0F;
+ }
+ }
+
+ rc = alloc_I_arrays(&I, &mI, width, height, 1, &features, feat_names, change_alpha, change_bc);
+ if (rc) {
+ printerror("No memory! Use smaller image or add more memory.");
+ thread_preview = PREVIEW_OFF;
+ goto reset;
+ }
+
+ set_I_ptr(I, mI, width, height, 0, features, change_alpha, change_bc, &ptr_y, &ptr_u, &ptr_v, &ptr_a, &ptr_r, &ptr_b, &ptr_c, &ptr_m);
+
+ // convert original image into YUV
+ rgb2yuv(ptr_gI, ptr_gI, width, height);
+ // convert maked image into YUV
+ rgb2yuv(ptr_cI, ptr_cI, width, height);
+
+ /* apply mask to mI */
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ /* do not apply mask on index 0 */
+ c = mark_buffer[i*width+j];
+ ptr_m[i*width+j] = (c == 0) ? 0.0F : 1.0F;
+ }
+ }
+
+ prepare_arrays(width, height, change_alpha, change_bc, mark_buffer, ptr_gI, ptr_cI, ptr_y, ptr_u, ptr_v, ptr_a, ptr_r, ptr_b, ptr_c, ptr_m, NO_TEST);
+
+ /* prepared, so we lock */
+ gdk_threads_enter();
+ }
+ if (thread_preview == PREVIEW_ON) {
+ int width, height;
+ double *ptr_gI = NULL, *ptr_y = NULL, *ptr_u = NULL, *ptr_v = NULL, *ptr_a = NULL, *ptr_r = NULL, *ptr_b = NULL, *ptr_c = NULL, *ptr_m = NULL;
+
+ if (thread_debug)
+ printf("%s: render preview\n", __func__);
+ width = img_width;
+ height = img_height;
+
+ /* render while unlocked */
+ gdk_threads_leave();
+
+ set_I_ptr(I, mI, width, height, 0, features, change_alpha, change_bc, &ptr_y, &ptr_u, &ptr_v, &ptr_a, &ptr_r, &ptr_b, &ptr_c, &ptr_m);
+
+ /* render u and v change */
+ rc = colorize(I, mI, NULL, NULL, 1, 1, 1, 0, feat_names, &col);
+ if (rc < 0) {
+ printerror("No memory! Use smaller image or add more memory.");
+ thread_preview = PREVIEW_OFF;
+ goto reset;
+ }
+
+ postpare_arrays(width, height, change_alpha, change_bc, ptr_y, ptr_u, ptr_v, ptr_a, ptr_r, ptr_b, ptr_c, ptr_m, NO_TEST);
+
+ /* convert YUV to RGB */
+ ptr_gI = darrayGetPr(gI);
+ yuv2rgb(ptr_y, ptr_gI, width, height);
+
+ /* create image */
+ if (change_alpha) {
+ /* simulate alpha by pattern */
+ double pat, a;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ pat = (((j>>3)&1) == ((i>>3)&1)) ? 0.5 : 0.75;
+ a = ptr_a[i*width+j];
+ ptr_gI[i*width+j] = a * ptr_gI[i*width+j] + (1.0 - a) * pat;
+ ptr_gI[i*width+j + width*height] = a * ptr_gI[i*width+j + width*height] + (1.0 - a) * pat;
+ ptr_gI[i*width+j + width*height*2] = a * ptr_gI[i*width+j + width*height*2] + (1.0 - a) * pat;
+ }
+ }
+ }
+
+ /* rendered, so we lock */
+ gdk_threads_enter();
+ }
+ if (thread_preview == PREVIEW_ON) {
+ int width, height;
+ double *ptr_gI = NULL;
+
+ width = img_width;
+ height = img_height;
+ ptr_gI = darrayGetPr(gI);
+ array2img_short(ptr_gI, width, height, img_preview_buffer, width, height, 0);
+ draw_image(0, 0, -1, -1);
+ }
+ gdk_threads_leave();
+
+ if (thread_preview == PREVIEW_OFF)
+ usleep(100000);
+
+ if (thread_preview == PREVIEW_FREE) {
+ thread_preview = PREVIEW_OFF;
+ goto reset;
+ }
+
+ goto loop;
+
+reset:
+ if (col) {
+ colorize_free(col);
+ col = NULL;
+ }
+ if (mark_buffer) {
+ free(mark_buffer);
+ mark_buffer = NULL;
+ }
+ darrayDestroy(gI);
+ gI = NULL;
+ darrayDestroy(cI);
+ cI = NULL;
+ darrayDestroy(mI);
+ mI = NULL;
+ darrayDestroy(I);
+ I = NULL;
+ darrayDone();
+ gdk_threads_leave();
+
+ if (thread_running)
+ goto loop;
+
+ return NULL;
+}
+
+
+
+int colorize_preview_init(void)
+{
+ pthread_t tid;
+
+ if (thread_running) {
+ /* we want an exit */
+ thread_running = -1;
+ if (thread_debug)
+ printf("%s: thread already running, terminating\n", __func__);
+ return -1;
+ }
+
+ if (pthread_create(&tid, NULL, colorize_thread, NULL) < 0) {
+ if (thread_debug)
+ printf("colorize thread creation failed!");
+ return -1;
+ }
+
+ if (thread_debug)
+ printf("%s: thread created\n", __func__);
+ thread_running = 1;
+
+ return 0;
+}
+
+void colorize_preview_terminate(void)
+{
+ colorize_preview_free();
+
+ if (thread_running > 0) {
+ if (thread_debug)
+ printf("%s: threaed is running\n", __func__);
+ thread_running = -1;
+ }
+ if (thread_running)
+ if (thread_debug)
+ printf("%s: waiting to terminate thread\n", __func__);
+ gdk_threads_leave();
+ while(thread_running) {
+ usleep(1000);
+ }
+ gdk_threads_enter();
+ if (thread_debug)
+ printf("%s: thread is terminated\n", __func__);
+}
+
+/* indicate a new preview image */
+void colorize_preview_alloc(void)
+{
+ thread_preview = PREVIEW_NEW;
+}
+
+/* indicate no preview image */
+void colorize_preview_free(void)
+{
+ if (thread_preview != PREVIEW_OFF)
+ if (thread_debug)
+ printf("%s: disable preview\n", __func__);
+ thread_preview = PREVIEW_FREE;
+}
+