--- dcraw.c	2007-03-26 01:26:49.000000000 +0200
+++ dcraw_new.c	2007-04-15 06:40:51.000000000 +0200
@@ -108,11 +108,12 @@ double pixel_aspect;
 int zero_after_ff, is_raw, dng_version, is_foveon, data_error;
 ushort (*image)[4], white[8][8], curve[0x1000], cr2_slice[3];
 float bright=1, user_mul[4]={0,0,0,0}, threshold=0;
-int half_size=0, four_color_rgb=0, document_mode=0, highlight=0;
+int half_size=0, four_color_rgb=0, document_mode=0, highlight=0, blend_highlight=0;
 int verbose=0, use_auto_wb=0, use_camera_wb=0;
 int output_color=1, output_bps=8, output_tiff=0;
 int fuji_layout, fuji_secondary, shot_select=0;
 float cam_mul[4], pre_mul[4], rgb_cam[3][4];	/* RGB from camera color */
+float scale_correction = 1;
 const double xyz_rgb[3][3] = {			/* XYZ from RGB */
   { 0.412453, 0.357580, 0.180423 },
   { 0.212671, 0.715160, 0.072169 },
@@ -3437,7 +3438,9 @@ skip_block:
     if (dmax < pre_mul[c])
 	dmax = pre_mul[c];
   }
-  if (!highlight) dmax = dmin;
+  if (blend_highlight)
+    scale_correction = dmax / dmin;
+  else if (!highlight) dmax = dmin;
   FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum;
   if (verbose) {
     fprintf (stderr,_("Scaling with black %d, multipliers"), dblack);
@@ -3819,6 +3822,75 @@ void CLASS ahd_interpolate()
 }
 #undef TS
 
+void CLASS cam_to_lab(ushort cam[4], float lab[3])
+{
+  lab[0] = cam[0] + cam[1] + cam[2];
+  lab[1] = (cam[0] - cam[1])*sqrt(3.0);
+  lab[2] = 2.0*cam[2] - cam[0] - cam[1];
+}
+
+void CLASS lab_to_cam(ushort cam[4], float lab[3])
+{
+  cam[0] = (2.0*lab[0] + sqrt(3.0)*lab[1] - lab[2])/6.0;
+  cam[1] = (2.0*lab[0] - sqrt(3.0)*lab[1] - lab[2])/6.0;
+  cam[2] = (lab[0] + lab[2])/3.0;
+}
+
+void CLASS lab_to_lch (float lab[3], float lch[3])
+{
+  lch[0] = lab[0];
+  lch[1] = sqrt (lab[1]*lab[1] + lab[2]*lab[2]);
+  lch[2] = atan2 (lab[2], lab[1]);
+}
+
+void CLASS lch_to_lab (float lab[3], float lch[3])
+{
+  lab[0] = lch[0];
+  lab[1] = lch[1] * cos(lch[2]);
+  lab[2] = lch[1] * sin(lch[2]);
+}
+
+void CLASS recover_highlights_blend()
+{
+  float lab[3], lch[3], lch_clip[3];
+  ushort pix_clipped[4];
+  int val, c, pix_diff, is_sat;
+  unsigned row, col;
+
+  if (verbose) fprintf (stderr, "Highlight recovery: LCh blending...\n");
+
+  for(row=0; row<height; row++)
+  {
+    for(col=0; col<width; col++)
+    {
+      is_sat=0;
+      FORC4 {
+        val = CLIP(image[row*width+col][c] * scale_correction);
+	pix_clipped[c] = CLIP(val / scale_correction);
+	pix_diff = image[row*width+col][c] - pix_clipped[c];
+	if(pix_diff>2 || pix_diff<-2) is_sat=1;
+      }
+
+      if (is_sat)
+      {
+	cam_to_lab (image[row*width+col], lab);
+	lab_to_lch (lab, lch);
+
+	cam_to_lab (pix_clipped, lab);
+	lab_to_lch (lab, lch_clip);
+
+	if(lch[1]>lch_clip[1])
+	  lch[1]=lch_clip[1];
+	if(lch[0]<lch_clip[0])
+	  lch[0]=lch_clip[0];
+
+	lch_to_lab(lab, lch);
+	lab_to_cam(image[row*width+col], lab);
+      }
+    }
+  }
+}
+
 #define SCALE (4 >> shrink)
 void CLASS recover_highlights()
 {
@@ -7219,6 +7291,7 @@ int CLASS main (int argc, char **argv)
     puts(_("-k <num>  Set black point"));
     puts(_("-K <file> Subtract dark frame (16-bit raw PGM)"));
     puts(_("-H [0-9]  Highlight mode (0=clip, 1=no clip, 2+=recover)"));
+    puts(_("-G        LCH blending highlight recovery"));
     puts(_("-t [0-7]  Flip image (0=none, 3=180, 5=90CCW, 6=90CW)"));
     puts(_("-o [0-5]  Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)"));
 #ifndef NO_LCMS
@@ -7278,6 +7351,7 @@ int CLASS main (int argc, char **argv)
       case 'w':  use_camera_wb     = 1;  break;
       case 'D':
       case 'd':  document_mode = 1 + (opt == 'D');
+      case 'G':  blend_highlight   = 1;  break;
       case 'j':  use_fuji_rotate   = 0;  break;
       case 'm':  output_color      = 0;  break;
       case 'T':  output_tiff       = 1;  break;
@@ -7454,7 +7528,8 @@ next:
 	   vng_interpolate();
       else ahd_interpolate();
     }
-    if (!is_foveon && highlight > 1) recover_highlights();
+    if (blend_highlight) recover_highlights_blend();
+    else if (!is_foveon && highlight > 1) recover_highlights();
     if (use_fuji_rotate) fuji_rotate();
     if (mix_green && (colors = 3))
       for (i=0; i < height*width; i++)
