File indexing completed on 2024-09-15 04:14:48
0001 /* 0002 * SPDX-FileCopyrightText: 2009 Kare Sars <kare dot sars at iki dot fi> 0003 * SPDX-FileCopyrightText: 2018 Alexander Volkov <a.volkov@rusbitech.ru> 0004 * SPDX-FileCopyrightText: 2021 Alexander Stippich <a.stippich@gmx.net> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "imagebuilder.h" 0010 0011 #include <QImage> 0012 0013 #include <ksanecore_debug.h> 0014 0015 namespace KSaneCore 0016 { 0017 ImageBuilder::ImageBuilder(QImage *image, int *dpi) 0018 : m_image(image), m_dpi(dpi) 0019 { 0020 m_pixelData[0] = 0; 0021 m_pixelData[1] = 0; 0022 m_pixelData[2] = 0; 0023 m_pixelData[3] = 0; 0024 m_pixelData[4] = 0; 0025 m_pixelData[5] = 0; 0026 } 0027 0028 void ImageBuilder::start(const SANE_Parameters ¶ms) 0029 { 0030 beginFrame(params); 0031 QImage::Format imageFormat = QImage::Format_RGB32; 0032 if (m_params.format == SANE_FRAME_GRAY) { 0033 switch (m_params.depth) { 0034 case 1: 0035 imageFormat = QImage::Format_Mono; 0036 break; 0037 case 16: 0038 imageFormat = QImage::Format_Grayscale16; 0039 break; 0040 default: 0041 imageFormat = QImage::Format_Grayscale8; 0042 break; 0043 } 0044 } else if (m_params.depth > 8) { 0045 imageFormat = QImage::Format_RGBX64; 0046 } 0047 // create a new image if necessary 0048 if ((m_image->height() != m_params.lines) || 0049 (m_image->width() != m_params.pixels_per_line) || m_image->format() != imageFormat) { 0050 // just hope that the frame size is not changed between different frames of the same image. 0051 0052 int pixelLines = m_params.lines; 0053 // handscanners have the number of lines -1 -> make room for something 0054 if (m_params.lines <= 0) { 0055 pixelLines = m_params.pixels_per_line; 0056 } 0057 *m_image = QImage(m_params.pixels_per_line, pixelLines, imageFormat); 0058 if (m_image->format() == QImage::Format_Mono) { 0059 m_image->setColorTable(QVector<QRgb>({0xFFFFFFFF,0xFF000000})); 0060 } 0061 int dpm = *m_dpi * (1000.0 / 25.4); 0062 m_image->setDotsPerMeterX(dpm); 0063 m_image->setDotsPerMeterY(dpm); 0064 } 0065 m_image->fill(0xFFFFFFFF); 0066 } 0067 0068 void ImageBuilder::beginFrame(const SANE_Parameters ¶ms) 0069 { 0070 m_params = params; 0071 m_frameRead = 0; 0072 m_pixelX = 0; 0073 m_pixelY = 0; 0074 m_pixelDataIndex = 0; 0075 } 0076 0077 bool ImageBuilder::copyToImage(const SANE_Byte readData[], int read_bytes) 0078 { 0079 switch (m_params.format) { 0080 case SANE_FRAME_GRAY: 0081 if (m_params.depth == 1) { 0082 for (int i = 0; i < read_bytes; i++) { 0083 if (m_pixelY >= m_image->height()) { 0084 renewImage(); 0085 } 0086 uchar *imageBits = m_image->scanLine(m_pixelY); 0087 imageBits[m_pixelX / 8] = readData[i]; 0088 m_pixelX += 8; 0089 if (m_pixelX >= m_params.pixels_per_line) { 0090 m_pixelX = 0; 0091 m_pixelY++; 0092 } 0093 m_frameRead++; 0094 } 0095 return true; 0096 } else if (m_params.depth == 8) { 0097 for (int i = 0; i < read_bytes; i++) { 0098 if (m_pixelY >= m_image->height()) { 0099 renewImage(); 0100 } 0101 uchar *grayScale = m_image->scanLine(m_pixelY); 0102 grayScale[m_pixelX] = readData[i]; 0103 incrementPixelData(); 0104 m_frameRead++; 0105 } 0106 return true; 0107 } else if (m_params.depth == 16) { 0108 for (int i = 0; i < read_bytes; i++) { 0109 m_pixelData[m_pixelDataIndex] = readData[i]; 0110 m_pixelDataIndex++; 0111 if (m_pixelDataIndex == 2) { 0112 m_pixelDataIndex = 0; 0113 } 0114 if (m_pixelDataIndex == 0) { 0115 if (m_pixelY >= m_image->height()) { 0116 renewImage(); 0117 } 0118 quint16 *grayScale = reinterpret_cast<quint16*>(m_image->scanLine(m_pixelY)); 0119 grayScale[m_pixelX] = m_pixelData[0] + (m_pixelData[1] << 8); 0120 incrementPixelData(); 0121 } 0122 m_frameRead++; 0123 } 0124 return true; 0125 } 0126 break; 0127 0128 case SANE_FRAME_RGB: 0129 if (m_params.depth == 8) { 0130 for (int i = 0; i < read_bytes; i++) { 0131 m_pixelData[m_pixelDataIndex] = readData[i]; 0132 m_pixelDataIndex++; 0133 if (m_pixelDataIndex == 3) { 0134 m_pixelDataIndex = 0; 0135 } 0136 if (m_pixelDataIndex == 0) { 0137 if (m_pixelY >= m_image->height()) { 0138 renewImage(); 0139 } 0140 QRgb *rgbData = reinterpret_cast<QRgb*>(m_image->scanLine(m_pixelY)); 0141 rgbData[m_pixelX] = qRgb(m_pixelData[0], m_pixelData[1], m_pixelData[2]); 0142 incrementPixelData(); 0143 } 0144 m_frameRead++; 0145 } 0146 return true; 0147 } else if (m_params.depth == 16) { 0148 for (int i = 0; i < read_bytes; i++) { 0149 m_pixelData[m_pixelDataIndex] = readData[i]; 0150 m_pixelDataIndex++; 0151 if (m_pixelDataIndex == 6) { 0152 m_pixelDataIndex = 0; 0153 } 0154 if (m_pixelDataIndex == 0) { 0155 if (m_pixelY >= m_image->height()) { 0156 renewImage(); 0157 } 0158 QRgba64 *rgbData = reinterpret_cast<QRgba64*>(m_image->scanLine(m_pixelY)); 0159 rgbData[m_pixelX] = QRgba64::fromRgba64((m_pixelData[0] + (m_pixelData[1] << 8)), 0160 (m_pixelData[2] + (m_pixelData[3] << 8)), 0161 (m_pixelData[4] + (m_pixelData[5] << 8)), 0162 0xFFFF); 0163 incrementPixelData(); 0164 } 0165 m_frameRead++; 0166 } 0167 return true; 0168 } 0169 break; 0170 0171 case SANE_FRAME_RED: { 0172 int index = 0; 0173 if (m_params.depth == 8) { 0174 for (int i = 0; i < read_bytes; i++) { 0175 index = m_frameRead * 4 + 2; 0176 if (index >= m_image->sizeInBytes()) { 0177 renewImage(); 0178 } 0179 m_image->bits()[index] = readData[i]; 0180 m_frameRead++; 0181 } 0182 return true; 0183 } else if (m_params.depth == 16) { 0184 for (int i = 0; i < read_bytes; i++) { 0185 index = (m_frameRead - m_frameRead % 2) * 4 + m_frameRead % 2; 0186 if (index >= m_image->sizeInBytes()) { 0187 renewImage(); 0188 } 0189 m_image->bits()[index] = readData[i]; 0190 m_frameRead++; 0191 } 0192 return true; 0193 } 0194 break; 0195 } 0196 case SANE_FRAME_GREEN: { 0197 int index = 0; 0198 if (m_params.depth == 8) { 0199 for (int i = 0; i < read_bytes; i++) { 0200 int index = m_frameRead * 4 + 1; 0201 if (index >= m_image->sizeInBytes()) { 0202 renewImage(); 0203 } 0204 m_image->bits()[index] = readData[i]; 0205 m_frameRead++; 0206 } 0207 return true; 0208 } else if (m_params.depth == 16) { 0209 for (int i = 0; i < read_bytes; i++) { 0210 index = (m_frameRead - m_frameRead % 2) * 4 + 2 + m_frameRead % 2; 0211 if (index >= m_image->sizeInBytes()) { 0212 renewImage(); 0213 } 0214 m_image->bits()[index] = readData[i]; 0215 m_frameRead++; 0216 } 0217 return true; 0218 } 0219 break; 0220 } 0221 case SANE_FRAME_BLUE: { 0222 int index = 0; 0223 if (m_params.depth == 8) { 0224 for (int i = 0; i < read_bytes; i++) { 0225 int index = m_frameRead * 4; 0226 if (index >= m_image->sizeInBytes()) { 0227 renewImage(); 0228 } 0229 m_image->bits()[index] = readData[i]; 0230 m_frameRead++; 0231 } 0232 return true; 0233 } else if (m_params.depth == 16) { 0234 for (int i = 0; i < read_bytes; i++) { 0235 index = (m_frameRead - m_frameRead % 2) * 4 + 4 + m_frameRead % 2; 0236 if (index >= m_image->sizeInBytes()) { 0237 renewImage(); 0238 } 0239 m_image->bits()[index] = readData[i]; 0240 m_frameRead++; 0241 } 0242 return true; 0243 } 0244 break; 0245 } 0246 } 0247 0248 qCWarning(KSANECORE_LOG) << "Format" << m_params.format << "and depth" << m_params.depth << "is not yet supported by libksane!"; 0249 return false; 0250 } 0251 0252 void ImageBuilder::renewImage() 0253 { 0254 int start = m_image->sizeInBytes(); 0255 0256 // resize the image 0257 *m_image = m_image->copy(0, 0, m_image->width(), m_image->height() + m_image->width()); 0258 0259 for (int i = start; i < m_image->sizeInBytes(); i++) { // New parts are filled with "transparent black" 0260 m_image->bits()[i] = 0xFF; // Change to opaque white (0xFFFFFFFF), or white, whatever the format is 0261 } 0262 } 0263 0264 void ImageBuilder::cropImagetoSize() 0265 { 0266 int height = m_pixelY ? m_pixelY : m_frameRead / m_params.bytes_per_line; 0267 if (m_image->height() == height) 0268 return; 0269 *m_image = m_image->copy(0, 0, m_image->width(), height); 0270 } 0271 0272 void ImageBuilder::incrementPixelData() 0273 { 0274 m_pixelX++; 0275 if (m_pixelX >= m_params.pixels_per_line) { 0276 m_pixelY++; 0277 m_pixelX=0; 0278 } 0279 } 0280 0281 } // namespace KSaneCore