File indexing completed on 2024-04-21 12:17:20

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 &params)
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 &params)
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