<html><body>---------- Původní e-mail ----------<br><aside>
Od: Olaf Meeuwissen <paddy-hack@member.fsf.org><br>
Komu: marcodv@seznam.cz<br>
Datum: 23. 3. 2019 12:55:56<br>
Předmět: Re: [sane-devel] support status
</aside><br><blockquote data-email="paddy-hack@member.fsf.org">Hi Marco,
<br>
<br>Sorry for the belated follow-up.
<br>
<br>marcodv@seznam.cz writes:
<br>
<br>> Hi,
<br>>
<br>> regarding those v700-v850: I was mainly interested whether it supports 16bpc
<br>> / infrared / dual lens. Unfortunately, when it comes to flatbed scanning of
<br>> analog film stock, the competition is essentially non-existent.
<br>>
<br>>
<br>> Thanks for the help, though. Regarding V600, 16bpc works on win and mac with
<br>> their Epson Scan. Unfortunately, for GNU/Linux, they provide an extremely
<br>> simplistic and practically useless (for analog negative scanning) utility
<br>> they call Image Scan.
<br>>
<br>> I've tried scanning as pnm - didn't work:
<br>
<br>:-((
<br>
<br>> $ SANE_DEBUG_DLL=3 scanimage --verbose --format=pnm --source 'Transparency
<br>> Unit' --depth 16 > test16bpcV2.pnm
<br>> [... snip ...]
<br>>
<br>> I've also tried setting SANE_DEBUG_EPKOWA=HEX to see, what comes out. (The
<br>> output is really long, I'm not sure if it'd be appropriate for a mailing
<br>> list to post it here in full, so I've rehosted it to https://gitlab.com/
<br>> snippets/1832781(https://gitlab.com/snippets/1832781)) - which might indeed
<br>> suggest that the bit depth is a problem somehow.
<br>
<br>Based on that log, the *device* does claim to support 16 bits input and
<br>output but does not say whether that bit depth is supported for which of
<br>the flatbed or the transparency unit or both.  Whatever that closed
<br>source module does when requesting 16 bits of output is ours to guess as
<br>well :-/
<br>
<br>Trudging through the log ... depth gets set to 16 bits[1] (with a pile
<br>of other settings) and scanner reports that succeeded[2]
<br>
<br> [1]: https://gitlab.com/snippets/1832781#L3512
<br> [2]: https://gitlab.com/snippets/1832781#L3515
<br>
<br>The read-back of those settings[3] doesn't reflect what was claimed to
<br>have been set successfully.  Somewhere in the back of my mind I vaguely
<br>remember that that result should not be trusted.  Ignoring that.
<br>
<br> [3]: https://gitlab.com/snippets/1832781#L3528
<br>
<br>Arriving at the final line[4] in the log
<br>
<br> [4]: https://gitlab.com/snippets/1832781#L3608
<br>
<br>  dip-obj.c:572: [epkowa][F] failed: require (8 == buf->ctx.depth)
<br>
<br>Urk!  That looks like the driver does not support digital image
<br>processing (DIP) for 16 bits when applying color profiles.  One possible
<br>fix is patching up dip_apply_color_profile to handle 16 bits/channel,
<br>another is avoiding the invocation of that function for your device and
<br>do any kind of colour correction by some other means (if necessary).
<br>
<br>> Also worth noting that Vuescan - proprietary paid scanning software, which
<br>> has a Linux version seems to support 16bpc just fine. I've just tried that
<br>> and while the result is watermarked, the tiff seems to be true 16bpc (and
<br>> not in a cheaty way).
<br>
<br>Where with "cheaty" you probably mean software-emulated ;-/
<br>
<br># Applying a color profile is done in software but the 16 bpc is not
<br># emulated (AFAICS).  That closed source module and the firmware are of
<br># course still "emulation suspects".
<br>
<br>> Is there anything I can try to make the V600 work with16bpc? Also, since you
<br>> mentioned that V700+ uses completely different backend, does that one
<br>> support 16bpc? (I don't have access to those scanners so I can't try).
<br>
<br>Hope this helps,
<br>--
<br>Olaf Meeuwissen, LPIC-2            FSF Associate Member since 2004-01-27
<br> GnuPG key: F84A2DD9/B3C0 2F47 EA19 64F4 9F13  F43E B8A4 A88A F84A 2DD9
<br> Support Free Software                        https://my.fsf.org/donate
<br> Join the Free Software Foundation              https://my.fsf.org/join
</blockquote><p> </p><p>Hello, thanks for looking into it. I've also noticed that line. In fact, if you look a few lines above in the same source file, you'll see:</p><pre><code>/*! \todo Add support for 16 bit color values (#816).
 */</code></pre><p>Which sure looks 'reassuring'. I almost gave up, but then I stumbled upon this git repo: https://github.com/hean01/iscan. Someone had the same exact problem five years ago, forked the original iscan and wrote a patch to support 16bpc scanning. So I played around with it a bit, used the fork to create a patch for the package in my distro and it actually worked! The scan no longer crashes and the output looks like true 16bpc. I can even use xsane to do the scanning.</p><p><br></p><p>I've included the patch as I've formatted it (I haven't tried to build straight from the repo (there are some open issues there claiming the build somehow fails), I used a distro build system, which built just fine and without errors).</p><p><br></p><p>If someone need a bit more info, here's the relevant forum thread: https://bbs.archlinux.org/viewtopic.php?pid=1835448#p1835448<br></p><p><br></p><p>Patch:<br></p><pre><code>--- backend/channel-usb.c
+++ backend/channel-usb.c
@@ -91,6 +91,7 @@ static ssize_t channel_usb_send (channel *, const void *,
 static ssize_t channel_usb_recv (channel *, void *,
                                  size_t, SANE_Status *);
 
+static size_t channel_usb_max_request_size (const channel *);
 
 channel *
 channel_usb_ctor (channel *self, const char *dev_name, SANE_Status *status)
@@ -119,7 +120,7 @@ channel_usb_ctor (channel *self, const char *dev_name, SANE_Status *status)
   self->send = channel_usb_send;
   self->recv = channel_usb_recv;
 
-  self->max_size = 128 * 1024;
+  self->max_request_size = channel_usb_max_request_size;
 
   return self;
 }
@@ -265,9 +266,6 @@ channel_interpreter_ctor (channel *self, const char *dev_name,
           self->dtor = channel_interpreter_dtor;
         }
     }
-
-  self->max_size = 32 * 1024;
-
   return self;
 }
 
@@ -283,3 +281,10 @@ channel_interpreter_dtor (channel *self)
   self->dtor = channel_dtor;
   return self->dtor (self);
 }
+
+static size_t
+channel_usb_max_request_size (const channel *self)
+{
+  return (self->interpreter ? 32 : 128) * 1024;
+}
+
--- backend/dip-obj.c
+++ backend/dip-obj.c
@@ -555,44 +555,70 @@ dip_change_GRB_to_RGB (const void *self, const buffer *buf)
   return;
 }
 
-/*! \todo Add support for 16 bit color values (#816).
- */
 void
 dip_apply_color_profile (const void *self, const buffer *buf,
                          const double profile[9])
 {
   SANE_Int i;
-  SANE_Byte *r_buf, *g_buf, *b_buf;
   double red, grn, blu;
 
-  SANE_Byte *data;
   SANE_Int size;
 
   require (dip == self && buf && profile);
-  require (8 == buf->ctx.depth);
+  require (buf->ctx.depth == 8 || buf->ctx.depth == 16);
 
   if (SANE_FRAME_RGB != buf->ctx.format)
     return;
 
-  data = buf->ptr;
-  size = buf->end - buf->ptr;
+  if (buf->ctx.depth == 8)
+  {
+    SANE_Byte *r_buf, *g_buf, *b_buf;
+    SANE_Byte *data;
+
+    data = buf->ptr;
+    size = buf->end - buf->ptr;
 
-  for (i = 0; i < size / 3; i++)
+    for (i = 0; i < size / 3; i++)
+    {
+      r_buf = data;
+      g_buf = data + 1;
+      b_buf = data + 2;
+
+      red =
+       profile[0] * (*r_buf) + profile[1] * (*g_buf) + profile[2] * (*b_buf);
+      grn =
+       profile[3] * (*r_buf) + profile[4] * (*g_buf) + profile[5] * (*b_buf);
+      blu =
+       profile[6] * (*r_buf) + profile[7] * (*g_buf) + profile[8] * (*b_buf);
+
+      *data++ = clamp (red, 0, 255);
+      *data++ = clamp (grn, 0, 255);
+      *data++ = clamp (blu, 0, 255);
+    }
+  }
+  else if (buf->ctx.depth == 16)
   {
-    r_buf = data;
-    g_buf = data + 1;
-    b_buf = data + 2;
-
-    red =
-      profile[0] * (*r_buf) + profile[1] * (*g_buf) + profile[2] * (*b_buf);
-    grn =
-      profile[3] * (*r_buf) + profile[4] * (*g_buf) + profile[5] * (*b_buf);
-    blu =
-      profile[6] * (*r_buf) + profile[7] * (*g_buf) + profile[8] * (*b_buf);
-
-    *data++ = clamp (red, 0, 255);
-    *data++ = clamp (grn, 0, 255);
-    *data++ = clamp (blu, 0, 255);
+    uint16_t *r_buf, *g_buf, *b_buf;
+    uint16_t *data;
+
+    data = (uint16_t *)buf->ptr;
+    while(data < buf->end)
+    {
+      r_buf = data;
+      g_buf = data + 1;
+      b_buf = data + 2;
+
+      red =
+       profile[0] * (*r_buf) + profile[1] * (*g_buf) + profile[2] * (*b_buf);
+      grn =
+       profile[3] * (*r_buf) + profile[4] * (*g_buf) + profile[5] * (*b_buf);
+      blu =
+       profile[6] * (*r_buf) + profile[7] * (*g_buf) + profile[8] * (*b_buf);
+
+      *data++ = clamp (red, 0, 65535);
+      *data++ = clamp (grn, 0, 65535);
+      *data++ = clamp (blu, 0, 65535);
+    }
   }
 }</code></pre><p><br></p><p>Regards, JonnyRobbie<br></p><p><br></p></body></html>