KSaneCore

imagebuilder.cpp
1/*
2 * SPDX-FileCopyrightText: 2009 Kare Sars <kare dot sars at iki dot fi>
3 * SPDX-FileCopyrightText: 2018 Alexander Volkov <a.volkov@rusbitech.ru>
4 * SPDX-FileCopyrightText: 2021 Alexander Stippich <a.stippich@gmx.net>
5 *
6 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8
9#include "imagebuilder.h"
10
11#include <QImage>
12
13#include <ksanecore_debug.h>
14
15namespace KSaneCore
16{
17ImageBuilder::ImageBuilder(QImage *image, int *dpi)
18 : m_image(image), m_dpi(dpi)
19{
20 m_pixelData[0] = 0;
21 m_pixelData[1] = 0;
22 m_pixelData[2] = 0;
23 m_pixelData[3] = 0;
24 m_pixelData[4] = 0;
25 m_pixelData[5] = 0;
26}
27
28void ImageBuilder::start(const SANE_Parameters &params)
29{
30 beginFrame(params);
32 if (m_params.format == SANE_FRAME_GRAY) {
33 switch (m_params.depth) {
34 case 1:
35 imageFormat = QImage::Format_Mono;
36 break;
37 case 16:
38 imageFormat = QImage::Format_Grayscale16;
39 break;
40 default:
41 imageFormat = QImage::Format_Grayscale8;
42 break;
43 }
44 } else if (m_params.depth > 8) {
45 imageFormat = QImage::Format_RGBX64;
46 }
47 // create a new image if necessary
48 if ((m_image->height() != m_params.lines) ||
49 (m_image->width() != m_params.pixels_per_line) || m_image->format() != imageFormat) {
50 // just hope that the frame size is not changed between different frames of the same image.
51
52 int pixelLines = m_params.lines;
53 // handscanners have the number of lines -1 -> make room for something
54 if (m_params.lines <= 0) {
55 pixelLines = m_params.pixels_per_line;
56 }
57 *m_image = QImage(m_params.pixels_per_line, pixelLines, imageFormat);
58 if (m_image->format() == QImage::Format_Mono) {
59 m_image->setColorTable(QVector<QRgb>({0xFFFFFFFF,0xFF000000}));
60 }
61 int dpm = *m_dpi * (1000.0 / 25.4);
62 m_image->setDotsPerMeterX(dpm);
63 m_image->setDotsPerMeterY(dpm);
64 }
65 m_image->fill(0xFFFFFFFF);
66}
67
68void ImageBuilder::beginFrame(const SANE_Parameters &params)
69{
70 m_params = params;
71 m_frameRead = 0;
72 m_pixelX = 0;
73 m_pixelY = 0;
74 m_pixelDataIndex = 0;
75}
76
77bool ImageBuilder::copyToImage(const SANE_Byte readData[], int read_bytes)
78{
79 switch (m_params.format) {
80 case SANE_FRAME_GRAY:
81 if (m_params.depth == 1) {
82 for (int i = 0; i < read_bytes; i++) {
83 if (m_pixelY >= m_image->height()) {
84 renewImage();
85 }
86 uchar *imageBits = m_image->scanLine(m_pixelY);
87 imageBits[m_pixelX / 8] = readData[i];
88 m_pixelX += 8;
89 if (m_pixelX >= m_params.pixels_per_line) {
90 m_pixelX = 0;
91 m_pixelY++;
92 }
93 m_frameRead++;
94 }
95 return true;
96 } else if (m_params.depth == 8) {
97 for (int i = 0; i < read_bytes; i++) {
98 if (m_pixelY >= m_image->height()) {
99 renewImage();
100 }
101 uchar *grayScale = m_image->scanLine(m_pixelY);
102 grayScale[m_pixelX] = readData[i];
103 incrementPixelData();
104 m_frameRead++;
105 }
106 return true;
107 } else if (m_params.depth == 16) {
108 for (int i = 0; i < read_bytes; i++) {
109 m_pixelData[m_pixelDataIndex] = readData[i];
110 m_pixelDataIndex++;
111 if (m_pixelDataIndex == 2) {
112 m_pixelDataIndex = 0;
113 }
114 if (m_pixelDataIndex == 0) {
115 if (m_pixelY >= m_image->height()) {
116 renewImage();
117 }
118 quint16 *grayScale = reinterpret_cast<quint16*>(m_image->scanLine(m_pixelY));
119 grayScale[m_pixelX] = m_pixelData[0] + (m_pixelData[1] << 8);
120 incrementPixelData();
121 }
122 m_frameRead++;
123 }
124 return true;
125 }
126 break;
127
128 case SANE_FRAME_RGB:
129 if (m_params.depth == 8) {
130 for (int i = 0; i < read_bytes; i++) {
131 m_pixelData[m_pixelDataIndex] = readData[i];
132 m_pixelDataIndex++;
133 if (m_pixelDataIndex == 3) {
134 m_pixelDataIndex = 0;
135 }
136 if (m_pixelDataIndex == 0) {
137 if (m_pixelY >= m_image->height()) {
138 renewImage();
139 }
140 QRgb *rgbData = reinterpret_cast<QRgb*>(m_image->scanLine(m_pixelY));
141 rgbData[m_pixelX] = qRgb(m_pixelData[0], m_pixelData[1], m_pixelData[2]);
142 incrementPixelData();
143 }
144 m_frameRead++;
145 }
146 return true;
147 } else if (m_params.depth == 16) {
148 for (int i = 0; i < read_bytes; i++) {
149 m_pixelData[m_pixelDataIndex] = readData[i];
150 m_pixelDataIndex++;
151 if (m_pixelDataIndex == 6) {
152 m_pixelDataIndex = 0;
153 }
154 if (m_pixelDataIndex == 0) {
155 if (m_pixelY >= m_image->height()) {
156 renewImage();
157 }
158 QRgba64 *rgbData = reinterpret_cast<QRgba64*>(m_image->scanLine(m_pixelY));
159 rgbData[m_pixelX] = QRgba64::fromRgba64((m_pixelData[0] + (m_pixelData[1] << 8)),
160 (m_pixelData[2] + (m_pixelData[3] << 8)),
161 (m_pixelData[4] + (m_pixelData[5] << 8)),
162 0xFFFF);
163 incrementPixelData();
164 }
165 m_frameRead++;
166 }
167 return true;
168 }
169 break;
170
171 case SANE_FRAME_RED: {
172 int index = 0;
173 if (m_params.depth == 8) {
174 for (int i = 0; i < read_bytes; i++) {
175 index = m_frameRead * 4 + 2;
176 if (index >= m_image->sizeInBytes()) {
177 renewImage();
178 }
179 m_image->bits()[index] = readData[i];
180 m_frameRead++;
181 }
182 return true;
183 } else if (m_params.depth == 16) {
184 for (int i = 0; i < read_bytes; i++) {
185 index = (m_frameRead - m_frameRead % 2) * 4 + m_frameRead % 2;
186 if (index >= m_image->sizeInBytes()) {
187 renewImage();
188 }
189 m_image->bits()[index] = readData[i];
190 m_frameRead++;
191 }
192 return true;
193 }
194 break;
195 }
196 case SANE_FRAME_GREEN: {
197 int index = 0;
198 if (m_params.depth == 8) {
199 for (int i = 0; i < read_bytes; i++) {
200 int index = m_frameRead * 4 + 1;
201 if (index >= m_image->sizeInBytes()) {
202 renewImage();
203 }
204 m_image->bits()[index] = readData[i];
205 m_frameRead++;
206 }
207 return true;
208 } else if (m_params.depth == 16) {
209 for (int i = 0; i < read_bytes; i++) {
210 index = (m_frameRead - m_frameRead % 2) * 4 + 2 + m_frameRead % 2;
211 if (index >= m_image->sizeInBytes()) {
212 renewImage();
213 }
214 m_image->bits()[index] = readData[i];
215 m_frameRead++;
216 }
217 return true;
218 }
219 break;
220 }
221 case SANE_FRAME_BLUE: {
222 int index = 0;
223 if (m_params.depth == 8) {
224 for (int i = 0; i < read_bytes; i++) {
225 int index = m_frameRead * 4;
226 if (index >= m_image->sizeInBytes()) {
227 renewImage();
228 }
229 m_image->bits()[index] = readData[i];
230 m_frameRead++;
231 }
232 return true;
233 } else if (m_params.depth == 16) {
234 for (int i = 0; i < read_bytes; i++) {
235 index = (m_frameRead - m_frameRead % 2) * 4 + 4 + m_frameRead % 2;
236 if (index >= m_image->sizeInBytes()) {
237 renewImage();
238 }
239 m_image->bits()[index] = readData[i];
240 m_frameRead++;
241 }
242 return true;
243 }
244 break;
245 }
246 }
247
248 qCWarning(KSANECORE_LOG) << "Format" << m_params.format << "and depth" << m_params.depth << "is not yet supported by libksane!";
249 return false;
250}
251
252void ImageBuilder::renewImage()
253{
254 int start = m_image->sizeInBytes();
255
256 // resize the image
257 *m_image = m_image->copy(0, 0, m_image->width(), m_image->height() + m_image->width());
258
259 for (int i = start; i < m_image->sizeInBytes(); i++) { // New parts are filled with "transparent black"
260 m_image->bits()[i] = 0xFF; // Change to opaque white (0xFFFFFFFF), or white, whatever the format is
261 }
262}
263
264void ImageBuilder::cropImagetoSize()
265{
266 int height = m_pixelY ? m_pixelY : m_frameRead / m_params.bytes_per_line;
267 if (m_image->height() == height)
268 return;
269 *m_image = m_image->copy(0, 0, m_image->width(), height);
270}
271
272void ImageBuilder::incrementPixelData()
273{
274 m_pixelX++;
275 if (m_pixelX >= m_params.pixels_per_line) {
276 m_pixelY++;
277 m_pixelX=0;
278 }
279}
280
281} // namespace KSaneCore
Q_SCRIPTABLE Q_NOREPLY void start()
QRgba64 fromRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:34 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.