Index: dcraw/dcraw_lz.c
===================================================================
--- dcraw.orig/dcraw_lz.c
+++ dcraw/dcraw_lz.c
@@ -1,4 +1,8 @@
 /*
+ * OpenMP multithread version of dcraw
+ * based on UFRaw dcraw_indi.c by Udi Fuchs
+ */
+/*
    dcraw.c -- Dave Coffin's raw photo decoder
    Copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net
 
@@ -96,6 +100,10 @@ typedef unsigned long long UINT64;
 #define ushort unsigned short
 #endif
 
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
 /*
    All global variables are defined here, and all functions that
    access them are prefixed with "CLASS".  For thread-safety, all
@@ -4132,6 +4140,13 @@ void CLASS wavelet_denoise()
   merror (fimg, "wavelet_denoise()");
   temp = fimg + size*3;
   if ((nc = colors) == 3 && filters) nc++;
+#if defined(__sun) && !defined(__GNUC__)	/* Fix UFRaw bug #3205673 - NKBJ */
+    #pragma omp parallel for default(shared) \
+    private(c,i,hpass,lev,lpass,row,col,thold,fimg,temp)
+#else
+    #pragma omp parallel for default(shared) \
+    private(c,i,hpass,lev,lpass,row,col,thold,fimg,temp)
+#endif
   FORC(nc) {			/* denoise R,G1,B,G3 individually */
     for (i=0; i < size; i++)
       fimg[i] = 256 * sqrt(image[i][c] << scale);
@@ -4355,8 +4370,10 @@ void CLASS pre_interpolate()
 
 void CLASS border_interpolate (int border)
 {
-  unsigned row, col, y, x, f, c, sum[8];
+  int row;
+  unsigned col, y, x, f, c, sum[8];
 
+#pragma omp for
   for (row=0; row < height; row++)
     for (col=0; col < width; col++) {
       if (col==border && row >= border && row < height-border)
@@ -4383,7 +4400,11 @@ void CLASS lin_interpolate()
 
   if (verbose) fprintf (stderr,_("Bilinear interpolation...\n"));
   if (filters == 9) size = 6;
+#pragma omp parallel default(shared) \
+  private(ip, sum, f, c, i, x, y, row, col, shift, color, pix)
+{
   border_interpolate(1);
+#pragma omp for
   for (row=0; row < size; row++)
     for (col=0; col < size; col++) {
       ip = code[row][col]+1;
@@ -4406,6 +4427,7 @@ void CLASS lin_interpolate()
 	  *ip++ = 256 / sum[c];
 	}
     }
+#pragma omp for
   for (row=1; row < height-1; row++)
     for (col=1; col < width-1; col++) {
       pix = image[row*width+col];
@@ -4416,6 +4438,7 @@ void CLASS lin_interpolate()
       for (i=colors; --i; ip+=2)
 	pix[ip[0]] = sum[ip[0]] * ip[1] >> 8;
     }
+} /* pragma omp parallel */
 }
 
 /*
@@ -4496,10 +4519,16 @@ void CLASS vng_interpolate()
 	  *ip++ = 0;
       }
     }
+#pragma omp parallel default(shared) \
+  private(row,col,g,brow,pix,ip,gval,diff,gmin,gmax,thold,sum,color,num,c,t)
+{
   brow[4] = (ushort (*)[4]) calloc (width*3, sizeof **brow);
   merror (brow[4], "vng_interpolate()");
+  /* Do not use 'pragma omp for' here */
   for (row=0; row < 3; row++)
     brow[row] = brow[4] + row*width;
+  int slice_row = 0;
+#pragma omp for schedule(static) nowait
   for (row=2; row < height-2; row++) {		/* Do VNG interpolation */
     for (col=2; col < width-2; col++) {
       pix = image[row*width+col];
@@ -4544,14 +4573,18 @@ void CLASS vng_interpolate()
 	brow[2][col][c] = CLIP(t);
       }
     }
-    if (row > 3)				/* Write buffer to image */
+    if (slice_row > 1)			/* Write buffer to image */
       memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
     for (g=0; g < 4; g++)
       brow[(g-1) & 3] = brow[g];
+    slice_row++;
+  }
+  if (row == height - 2) {
+    memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
+    memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image);
   }
-  memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
-  memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image);
   free (brow[4]);
+} /* pragma omp parallel */
   free (code[0][0]);
 }
 
@@ -4564,10 +4597,13 @@ void CLASS ppg_interpolate()
   int row, col, diff[2], guess[2], c, d, i;
   ushort (*pix)[4];
 
-  border_interpolate(3);
   if (verbose) fprintf (stderr,_("PPG interpolation...\n"));
 
+#pragma omp parallel default(shared) private(row,col,i,d,c,pix,guess)
+{
+  border_interpolate(3);
 /*  Fill in the green layer with gradients and pattern recognition: */
+#pragma omp for
   for (row=3; row < height-3; row++)
     for (col=3+(FC(row,3) & 1), c=FC(row,col); col < width-3; col+=2) {
       pix = image + row*width+col;
@@ -4584,6 +4620,7 @@ void CLASS ppg_interpolate()
       pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]);
     }
 /*  Calculate red and blue for each green pixel:		*/
+#pragma omp for
   for (row=1; row < height-1; row++)
     for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) {
       pix = image + row*width+col;
@@ -4592,6 +4629,7 @@ void CLASS ppg_interpolate()
 			- pix[-d][1] - pix[d][1]) >> 1);
     }
 /*  Calculate blue for red pixels and vice versa:		*/
+#pragma omp for
   for (row=1; row < height-1; row++)
     for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) {
       pix = image + row*width+col;
@@ -4607,6 +4645,7 @@ void CLASS ppg_interpolate()
       else
 	pix[0][c] = CLIP((guess[0]+guess[1]) >> 2);
     }
+} /* pragma omp parallel */
 }
 
 void CLASS cielab (ushort rgb[3], short lab[3])
@@ -4616,13 +4655,16 @@ void CLASS cielab (ushort rgb[3], short
   static float cbrt[0x10000], xyz_cam[3][4];
 
   if (!rgb) {
+#pragma omp for
     for (i=0; i < 0x10000; i++) {
       r = i / 65535.0;
       cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0;
     }
+#pragma omp for
     for (i=0; i < 3; i++)
       for (j=0; j < colors; j++)
 	for (xyz_cam[i][j] = k=0; k < 3; k++)
+#pragma omp atomic
 	  xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i];
     return;
   }
@@ -4888,6 +4930,10 @@ void CLASS ahd_interpolate()
 
   if (verbose) fprintf (stderr,_("AHD interpolation...\n"));
 
+#pragma omp parallel default(shared) \
+  private(top,left,row,col,pix,rix,lix,c,val,d,tc,tr,i,j,ldiff,abdiff,leps, \
+          abeps,hm,buffer,rgb,lab,homo)
+{
   cielab (0,0);
   border_interpolate(5);
   buffer = (char *) malloc (26*TS*TS);
@@ -4896,6 +4942,7 @@ void CLASS ahd_interpolate()
   lab  = (short (*)[TS][TS][3])(buffer + 12*TS*TS);
   homo = (char  (*)[TS][TS])   (buffer + 24*TS*TS);
 
+#pragma omp for
   for (top=2; top < height-5; top += TS-6)
     for (left=2; left < width-5; left += TS-6) {
 
@@ -4978,6 +5025,7 @@ void CLASS ahd_interpolate()
       }
     }
   free (buffer);
+} /* pragma omp parallel */
 }
 #undef TS
 
@@ -9825,6 +9873,7 @@ void CLASS fuji_rotate()
   img = (ushort (*)[4]) calloc (high, wide*sizeof *img);
   merror (img, "fuji_rotate()");
 
+#pragma omp parallel for default(shared) private(row,col,ur,uc,r,c,fr,fc,pix,i)
   for (row=0; row < high; row++)
     for (col=0; col < wide; col++) {
       ur = r = fuji_width + (row-col)*step;
