• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdegraphics API Reference
  • KDE Home
  • Contact Us
 

libs/libksane/libksane

  • sources
  • kde-4.14
  • kdegraphics
  • libs
  • libksane
  • libksane
ksane_preview_thread.cpp
Go to the documentation of this file.
1 /* ============================================================
2 *
3 * This file is part of the KDE project
4 *
5 * Date : 2009-11-13
6 * Description : Sane interface for KDE
7 *
8 * Copyright (C) 2009 by Kare Sars <kare dot sars at iki dot fi>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) version 3, or any
14 * later version accepted by the membership of KDE e.V. (or its
15 * successor approved by the membership of KDE e.V.), which shall
16 * act as a proxy defined in Section 6 of version 3 of the license.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this program. If not, see <http://www.gnu.org/licenses/>.
25 *
26 * ============================================================ */
27 
28 // Local includes
29 #include "ksane_preview_thread.moc"
30 
31 #include <KDebug>
32 #include <QMutexLocker>
33 
34 
35 namespace KSaneIface
36 {
37  KSanePreviewThread::KSanePreviewThread(SANE_Handle handle, QImage *img):
38  QThread(),
39  status(SANE_STATUS_GOOD),
40  m_frameSize(0),
41  m_frameRead(0),
42  m_dataSize(0),
43  m_frame_t_count(0),
44  m_pixel_x(0),
45  m_pixel_y(0),
46  m_px_c_index(0),
47  m_img(img),
48  m_saneHandle(handle),
49  m_invertColors(false),
50  m_readStatus(READ_READY),
51 // m_scanProgress(0),
52  m_saneStartDone(false),
53  m_imageResized(false)
54  {
55  m_px_colors[0] = 0;
56  m_px_colors[1] = 0;
57  m_px_colors[2] = 0;
58  }
59 
60  void KSanePreviewThread::setPreviewInverted(bool inverted)
61  {
62  m_invertColors = inverted;
63  }
64 
65  void KSanePreviewThread::cancelScan()
66  {
67  m_readStatus = READ_CANCEL;
68  }
69 
70  void KSanePreviewThread::run()
71  {
72  m_dataSize = 0;
73  m_readStatus = READ_ON_GOING;
74  m_saneStartDone = false;
75 
76  // Start the scanning with sane_start
77  status = sane_start(m_saneHandle);
78 
79  if (status != SANE_STATUS_GOOD) {
80  kDebug() << "sane_start=" << sane_strstatus(status);
81  sane_cancel(m_saneHandle);
82  m_readStatus = READ_ERROR;
83  return;
84  }
85 
86  // Read image parameters
87  status = sane_get_parameters(m_saneHandle, &m_params);
88  if (status != SANE_STATUS_GOOD) {
89  kDebug() << "sane_get_parameters=" << sane_strstatus(status);
90  sane_cancel(m_saneHandle);
91  m_readStatus = READ_ERROR;
92  return;
93  }
94 
95  // calculate data size
96  m_frameSize = m_params.lines * m_params.bytes_per_line;
97  if ((m_params.format == SANE_FRAME_RED) ||
98  (m_params.format == SANE_FRAME_GREEN) ||
99  (m_params.format == SANE_FRAME_BLUE))
100  {
101  // this is unfortunately calculated again for every frame....
102  m_dataSize = m_frameSize*3;
103  }
104  else {
105  m_dataSize = m_frameSize;
106  }
107 
108  // create a new image if necessary
109  if ((m_img->height() != m_params.lines) ||
110  (m_img->width() != m_params.pixels_per_line))
111  {
112  // just hope that the frame size is not changed between different frames of the same image.
113  if (m_params.lines > 0) {
114  *m_img = QImage(m_params.pixels_per_line, m_params.lines, QImage::Format_RGB32);
115  }
116  else {
117  // handscanners have the number of lines -1 -> make room for something
118  *m_img = QImage(m_params.pixels_per_line, m_params.pixels_per_line, QImage::Format_RGB32);
119  }
120  m_img->fill(0xFFFFFFFF);
121  }
122  m_imageResized = false;
123  m_pixel_x = 0;
124  m_pixel_y = 0;
125  m_frameRead = 0;
126  m_px_c_index = 0;
127  m_frame_t_count = 0;
128 
129  // set the m_saneStartDone here so the new QImage gets allocated before updating the preview.
130  m_saneStartDone = true;
131 
132 
133  while (m_readStatus == READ_ON_GOING) {
134  readData();
135  }
136  }
137 
138  int KSanePreviewThread::scanProgress()
139  {
140  // handscanners have negative data size
141  if (m_dataSize <= 0) return 0;
142 
143  int bytesRead;
144 
145  if (m_frameSize < m_dataSize) {
146  bytesRead = m_frameRead + (m_frameSize * m_frame_t_count);
147  }
148  else {
149  bytesRead = m_frameRead;
150  }
151 
152  return (int)(((float)bytesRead * 100.0)/m_dataSize);
153  }
154 
155  void KSanePreviewThread::readData()
156  {
157  SANE_Int readBytes;
158  status = sane_read(m_saneHandle, m_readData, PREVIEW_READ_CHUNK_SIZE, &readBytes);
159 
160  switch (status)
161  {
162  case SANE_STATUS_GOOD:
163  // continue to parsing the data
164  break;
165 
166  case SANE_STATUS_EOF:
167  // (handscanners have negative frame size)
168  if (m_frameRead < m_frameSize) {
169  kDebug() << "frameRead =" << m_frameRead << ", frameSize =" << m_frameSize;
170  m_readStatus = READ_ERROR;
171  return;
172  }
173  if (m_params.last_frame == SANE_TRUE) {
174  // this is where it all ends well :)
175  m_readStatus = READ_READY;
176  return;
177  }
178  else {
179  // start reading next frame
180  SANE_Status status = sane_start(m_saneHandle);
181  if (status != SANE_STATUS_GOOD) {
182  kDebug() << "sane_start =" << sane_strstatus(status);
183  m_readStatus = READ_ERROR;
184  return;
185  }
186  status = sane_get_parameters(m_saneHandle, &m_params);
187  if (status != SANE_STATUS_GOOD) {
188  kDebug() << "sane_get_parameters =" << sane_strstatus(status);
189  m_readStatus = READ_ERROR;
190  sane_cancel(m_saneHandle);
191  return;
192  }
193  //kDebug() << "New Frame";
194  m_frameRead = 0;
195  m_pixel_x = 0;
196  m_pixel_y = 0;
197  m_px_c_index = 0;
198  m_frame_t_count++;
199  break;
200  }
201  default:
202  kDebug() << "sane_read=" << status << "=" << sane_strstatus(status);
203  m_readStatus = READ_ERROR;
204  sane_cancel(m_saneHandle);
205  return;
206  }
207 
208  copyToPreviewImg(readBytes);
209  }
210 
211  #define inc_pixel(x,y,ppl) { x++; if (x>=ppl) { y++; x=0;} }
212  #define inc_color_index(index) { index++; if (index==3) index=0;}
213 
214  #define index_red8_to_argb8(i) (i*4 + 2)
215  #define index_red16_to_argb8(i) (i*2 + 2)
216 
217  #define index_green8_to_argb8(i) (i*4 + 1)
218  #define index_green16_to_argb8(i) (i*2 + 1)
219 
220  #define index_blue8_to_argb8(i) (i*4)
221  #define index_blue16_to_argb8(i) (i*2)
222 
223  void KSanePreviewThread::copyToPreviewImg(int read_bytes)
224  {
225  QMutexLocker locker(&imgMutex);
226  int index;
227  uchar *imgBits = m_img->bits();
228  if (m_invertColors) {
229  if (m_params.depth >= 8) {
230  for(int i=0; i<read_bytes; i++) {
231  m_readData[i] = 255 - m_readData[i];
232  }
233  }
234  if (m_params.depth == 1) {
235  for(int i=0; i<read_bytes; i++) {
236  m_readData[i] = ~m_readData[i];
237  }
238  }
239  }
240  switch (m_params.format)
241  {
242  case SANE_FRAME_GRAY:
243  if (m_params.depth == 1) {
244  int i, j;
245  for (i=0; i<read_bytes; i++) {
246  if (m_pixel_y >= m_img->height()) {
247  // resize the image
248  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
249  m_imageResized = true;
250  }
251  for (j=7; j>=0; --j) {
252  if ((m_readData[i] & (1<<j)) == 0) {
253  m_img->setPixel(m_pixel_x,
254  m_pixel_y,
255  qRgb(255,255,255));
256  }
257  else {
258  m_img->setPixel(m_pixel_x,
259  m_pixel_y,
260  qRgb(0,0,0));
261  }
262  m_pixel_x++;
263  if(m_pixel_x >= m_params.pixels_per_line) {
264  m_pixel_x = 0;
265  m_pixel_y++;
266  break;
267  }
268  if (m_pixel_y >= m_params.lines) break;
269  }
270  m_frameRead++;
271  }
272  return;
273  }
274  else if (m_params.depth == 8) {
275  for (int i=0; i<read_bytes; i++) {
276  index = m_frameRead * 4;
277  if ((index + 2) >m_img->numBytes()) {
278  // resize the image
279  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
280  imgBits = m_img->bits();
281  m_imageResized = true;
282  }
283  imgBits[index ] = m_readData[i];
284  imgBits[index + 1] = m_readData[i];
285  imgBits[index + 2] = m_readData[i];
286  m_frameRead++;
287  }
288  return;
289  }
290  else if (m_params.depth == 16) {
291  for (int i=0; i<read_bytes; i++) {
292  if (m_frameRead%2 == 0) {
293  index = m_frameRead * 2;
294  if ((index + 2) > m_img->numBytes()) {
295  // resize the image
296  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
297  imgBits = m_img->bits();
298  m_imageResized = true;
299  }
300  imgBits[index ] = m_readData[i+1];
301  imgBits[index + 1] = m_readData[i+1];
302  imgBits[index + 2] = m_readData[i+1];
303  }
304  m_frameRead++;
305  }
306  return;
307  }
308  break;
309 
310  case SANE_FRAME_RGB:
311  if (m_params.depth == 8) {
312  for (int i=0; i<read_bytes; i++) {
313  m_px_colors[m_px_c_index] = m_readData[i];
314  inc_color_index(m_px_c_index);
315  m_frameRead++;
316  if (m_px_c_index == 0) {
317  if (m_pixel_y >= m_img->height()) {
318  // resize the image
319  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
320  m_imageResized = true;
321  }
322  m_img->setPixel(m_pixel_x,
323  m_pixel_y,
324  qRgb(m_px_colors[0],
325  m_px_colors[1],
326  m_px_colors[2]));
327  inc_pixel(m_pixel_x, m_pixel_y, m_params.pixels_per_line);
328  }
329  }
330  return;
331  }
332  else if (m_params.depth == 16) {
333  for (int i=0; i<read_bytes; i++) {
334  m_frameRead++;
335  if (m_frameRead%2==0) {
336  m_px_colors[m_px_c_index] = m_readData[i];
337  inc_color_index(m_px_c_index);
338  if (m_px_c_index == 0) {
339  if (m_pixel_y >= m_img->height()) {
340  // resize the image
341  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
342  m_imageResized = true;
343  }
344  m_img->setPixel(m_pixel_x,
345  m_pixel_y,
346  qRgb(m_px_colors[0],
347  m_px_colors[1],
348  m_px_colors[2]));
349  inc_pixel(m_pixel_x, m_pixel_y, m_params.pixels_per_line);
350  }
351  }
352  }
353  return;
354  }
355  break;
356 
357  case SANE_FRAME_RED:
358  if (m_params.depth == 8) {
359  for (int i=0; i<read_bytes; i++) {
360  if (index_red8_to_argb8(m_frameRead) > m_img->numBytes()) {
361  // resize the image
362  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
363  imgBits = m_img->bits();
364  m_imageResized = true;
365  }
366  imgBits[index_red8_to_argb8(m_frameRead)] = m_readData[i];
367  m_frameRead++;
368  }
369  return;
370  }
371  else if (m_params.depth == 16) {
372  for (int i=0; i<read_bytes; i++) {
373  if (m_frameRead%2 == 0) {
374  if (index_red16_to_argb8(m_frameRead) > m_img->numBytes()) {
375  // resize the image
376  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
377  imgBits = m_img->bits();
378  m_imageResized = true;
379  }
380  imgBits[index_red16_to_argb8(m_frameRead)] = m_readData[i+1];
381  }
382  m_frameRead++;
383  }
384  return;
385  }
386  break;
387 
388  case SANE_FRAME_GREEN:
389  if (m_params.depth == 8) {
390  for (int i=0; i<read_bytes; i++) {
391  if (index_green8_to_argb8(m_frameRead) > m_img->numBytes()) {
392  // resize the image
393  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
394  imgBits = m_img->bits();
395  m_imageResized = true;
396  }
397  imgBits[index_green8_to_argb8(m_frameRead)] = m_readData[i];
398  m_frameRead++;
399  }
400  return;
401  }
402  else if (m_params.depth == 16) {
403  for (int i=0; i<read_bytes; i++) {
404  if (m_frameRead%2 == 0) {
405  if (index_green16_to_argb8(m_frameRead) > m_img->numBytes()) {
406  // resize the image
407  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
408  imgBits = m_img->bits();
409  m_imageResized = true;
410  }
411  imgBits[index_green16_to_argb8(m_frameRead)] = m_readData[i+1];
412  }
413  m_frameRead++;
414  }
415  return;
416  }
417  break;
418 
419  case SANE_FRAME_BLUE:
420  if (m_params.depth == 8) {
421  for (int i=0; i<read_bytes; i++) {
422  if (index_blue8_to_argb8(m_frameRead) > m_img->numBytes()) {
423  // resize the image
424  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
425  imgBits = m_img->bits();
426  m_imageResized = true;
427  }
428  imgBits[index_blue8_to_argb8(m_frameRead)] = m_readData[i];
429  m_frameRead++;
430  }
431  return;
432  }
433  else if (m_params.depth == 16) {
434  for (int i=0; i<read_bytes; i++) {
435  if (m_frameRead%2 == 0) {
436  if (index_blue16_to_argb8(m_frameRead) > m_img->numBytes()) {
437  // resize the image
438  *m_img = m_img->copy(0, 0, m_img->width(), m_img->height() + m_img->width());
439  imgBits = m_img->bits();
440  m_imageResized = true;
441  }
442  imgBits[index_blue16_to_argb8(m_frameRead)] = m_readData[i+1];
443  }
444  m_frameRead++;
445  }
446  return;
447  }
448  break;
449  }
450 
451  kWarning() << "Format" << m_params.format
452  << "and depth" << m_params.format
453  << "is not yet suppoeted by libksane!";
454  m_readStatus = READ_ERROR;
455  return;
456  }
457 
458  bool KSanePreviewThread::saneStartDone()
459  {
460  return m_saneStartDone;
461  }
462 
463  bool KSanePreviewThread::imageResized()
464  {
465  if (m_imageResized) {
466  m_imageResized = false;
467  return true;
468  }
469  return false;
470  }
471 
472 } // NameSpace KSaneIface
index_blue8_to_argb8
#define index_blue8_to_argb8(i)
Definition: ksane_preview_thread.cpp:220
inc_color_index
#define inc_color_index(index)
Definition: ksane_preview_thread.cpp:212
inc_pixel
#define inc_pixel(x, y, ppl)
Definition: ksane_preview_thread.cpp:211
KSaneIface::KSanePreviewThread::cancelScan
void cancelScan()
Definition: ksane_preview_thread.cpp:65
KSaneIface::KSanePreviewThread::status
SANE_Status status
Definition: ksane_preview_thread.h:66
QImage::setPixel
void setPixel(int x, int y, uint index_or_rgb)
index_red16_to_argb8
#define index_red16_to_argb8(i)
Definition: ksane_preview_thread.cpp:215
QImage::copy
QImage copy(const QRect &rectangle) const
index_blue16_to_argb8
#define index_blue16_to_argb8(i)
Definition: ksane_preview_thread.cpp:221
KSaneIface::KSanePreviewThread::imageResized
bool imageResized()
Definition: ksane_preview_thread.cpp:463
KSaneIface::KSanePreviewThread::READ_ERROR
Definition: ksane_preview_thread.h:53
KSaneIface::KSanePreviewThread::run
void run()
Definition: ksane_preview_thread.cpp:70
KSaneIface::KSanePreviewThread::KSanePreviewThread
KSanePreviewThread(SANE_Handle handle, QImage *img)
Definition: ksane_preview_thread.cpp:37
index_red8_to_argb8
#define index_red8_to_argb8(i)
Definition: ksane_preview_thread.cpp:214
index_green8_to_argb8
#define index_green8_to_argb8(i)
Definition: ksane_preview_thread.cpp:217
KSaneIface::KSanePreviewThread::saneStartDone
bool saneStartDone()
Definition: ksane_preview_thread.cpp:458
QImage::fill
void fill(uint pixelValue)
PREVIEW_READ_CHUNK_SIZE
#define PREVIEW_READ_CHUNK_SIZE
Definition: ksane_preview_thread.h:42
QImage::width
int width() const
KSaneIface::KSanePreviewThread::READ_READY
Definition: ksane_preview_thread.h:55
KSaneIface::KSanePreviewThread::imgMutex
QMutex imgMutex
Definition: ksane_preview_thread.h:67
KSaneIface::KSanePreviewThread::scanProgress
int scanProgress()
Definition: ksane_preview_thread.cpp:138
KSaneIface::KSanePreviewThread::READ_ON_GOING
Definition: ksane_preview_thread.h:52
QImage::numBytes
int numBytes() const
QImage
QMutexLocker
KSaneIface::KSanePreviewThread::READ_CANCEL
Definition: ksane_preview_thread.h:54
QImage::bits
uchar * bits()
QImage::height
int height() const
KSaneIface::KSanePreviewThread::setPreviewInverted
void setPreviewInverted(bool)
Definition: ksane_preview_thread.cpp:60
QThread
index_green16_to_argb8
#define index_green16_to_argb8(i)
Definition: ksane_preview_thread.cpp:218
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:19:47 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

libs/libksane/libksane

Skip menu "libs/libksane/libksane"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdegraphics API Reference

Skip menu "kdegraphics API Reference"
  •     libkdcraw
  •     libkexiv2
  •     libkipi
  •     libksane
  • okular

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal