File indexing completed on 2025-02-02 04:11:04
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "bitmap.hpp" 0008 #include <QPainter> 0009 #include <QImageWriter> 0010 #include <QImageReader> 0011 #include <QFileInfo> 0012 #include <QBuffer> 0013 #include <QUrl> 0014 0015 #include "model/document.hpp" 0016 #include "model/assets/assets.hpp" 0017 #include "command/object_list_commands.hpp" 0018 0019 GLAXNIMATE_OBJECT_IMPL(glaxnimate::model::Bitmap) 0020 0021 void glaxnimate::model::Bitmap::paint(QPainter* painter) const 0022 { 0023 painter->drawPixmap(0, 0, image); 0024 } 0025 0026 void glaxnimate::model::Bitmap::refresh(bool rebuild_embedded) 0027 { 0028 QImageReader reader; 0029 QImage qimage; 0030 0031 bool load_data = true; 0032 0033 if ( rebuild_embedded || data.get().isEmpty() ) 0034 { 0035 if ( !filename.get().isEmpty() ) 0036 { 0037 QFileInfo finfo = file_info(); 0038 if ( !finfo.isFile() ) 0039 return; 0040 reader.setFileName(finfo.absoluteFilePath()); 0041 format.set(reader.format()); 0042 qimage = reader.read(); 0043 if ( rebuild_embedded && embedded() ) 0044 data.set(build_embedded(qimage)); 0045 load_data = false; 0046 } 0047 else if ( !url.get().isEmpty() ) 0048 { 0049 document()->assets()->network_downloader.get(QUrl(url.get()), [this, rebuild_embedded](QByteArray response){ 0050 QImageReader reader; 0051 QImage qimage; 0052 QBuffer buf(&response); 0053 buf.open(QIODevice::ReadOnly); 0054 reader.setDevice(&buf); 0055 format.set(reader.format()); 0056 qimage = reader.read(); 0057 if ( rebuild_embedded && embedded() ) 0058 data.set(build_embedded(qimage)); 0059 0060 image = QPixmap::fromImage(qimage); 0061 width.set(image.width()); 0062 height.set(image.height()); 0063 0064 document()->graphics_invalidated(); 0065 Q_EMIT loaded(); 0066 }, this); 0067 return; 0068 } 0069 } 0070 0071 if ( load_data ) 0072 { 0073 QBuffer buf(const_cast<QByteArray*>(&data.get())); 0074 buf.open(QIODevice::ReadOnly); 0075 reader.setDevice(&buf); 0076 format.set(reader.format()); 0077 qimage = reader.read(); 0078 } 0079 0080 image = QPixmap::fromImage(qimage); 0081 width.set(image.width()); 0082 height.set(image.height()); 0083 0084 Q_EMIT loaded(); 0085 } 0086 0087 QByteArray glaxnimate::model::Bitmap::build_embedded(const QImage& img) const 0088 { 0089 QByteArray new_data; 0090 QBuffer buf(&new_data); 0091 buf.open(QIODevice::WriteOnly); 0092 QImageWriter writer(&buf, format.get().toLatin1()); 0093 writer.write(img); 0094 return new_data; 0095 } 0096 0097 bool glaxnimate::model::Bitmap::embedded() const 0098 { 0099 return !data.get().isEmpty(); 0100 } 0101 0102 void glaxnimate::model::Bitmap::embed(bool embedded) 0103 { 0104 if ( embedded == this->embedded() ) 0105 return; 0106 0107 if ( !embedded ) 0108 data.set_undoable({}); 0109 else 0110 data.set_undoable(build_embedded(image.toImage())); 0111 } 0112 0113 void glaxnimate::model::Bitmap::on_refresh() 0114 { 0115 refresh(false); 0116 } 0117 0118 QIcon glaxnimate::model::Bitmap::instance_icon() const 0119 { 0120 return image; 0121 } 0122 0123 bool glaxnimate::model::Bitmap::from_url(const QUrl& url) 0124 { 0125 if ( url.scheme().isEmpty() || url.scheme() == "file" ) 0126 return from_file(url.path()); 0127 0128 if ( url.scheme() == "data" ) 0129 return from_base64(url.path()); 0130 0131 this->url.set(url.toString()); 0132 0133 return true; 0134 } 0135 0136 bool glaxnimate::model::Bitmap::from_file(const QString& file) 0137 { 0138 filename.set(file); 0139 return !image.isNull(); 0140 } 0141 0142 bool glaxnimate::model::Bitmap::from_base64(const QString& data) 0143 { 0144 auto chunks = data.split(','); 0145 if ( chunks.size() != 2 ) 0146 return false; 0147 auto mime_settings = chunks[0].split(';'); 0148 if ( mime_settings.size() != 2 || mime_settings[1] != "base64" ) 0149 return false; 0150 0151 auto formats = QImageReader::imageFormatsForMimeType(mime_settings[0].toLatin1()); 0152 if ( formats.empty() ) 0153 return false; 0154 0155 auto decoded = QByteArray::fromBase64(chunks[1].toLatin1()); 0156 format.set(formats[0]); 0157 this->data.set(decoded); 0158 return !image.isNull(); 0159 } 0160 0161 0162 bool glaxnimate::model::Bitmap::from_raw_data(const QByteArray& data) 0163 { 0164 QBuffer buf(const_cast<QByteArray*>(&data)); 0165 buf.open(QBuffer::ReadOnly); 0166 auto format = QImageReader::imageFormat(&buf); 0167 if ( format.isEmpty() ) 0168 return false; 0169 0170 this->format.set(format); 0171 this->data.set(data); 0172 return !image.isNull(); 0173 0174 } 0175 0176 QUrl glaxnimate::model::Bitmap::to_url() const 0177 { 0178 if ( !embedded() ) 0179 { 0180 return QUrl::fromLocalFile(file_info().absoluteFilePath()); 0181 } 0182 0183 QByteArray fmt = format.get().toLatin1(); 0184 QByteArray mime_type; 0185 for ( const auto& mime : QImageWriter::supportedMimeTypes() ) 0186 if ( QImageWriter::imageFormatsForMimeType(mime).contains(fmt) ) 0187 { 0188 mime_type = mime; 0189 break; 0190 } 0191 0192 if ( mime_type.isEmpty() ) 0193 return {}; 0194 0195 QString data_url = "data:"; 0196 data_url += mime_type; 0197 data_url += ";base64,"; 0198 data_url += data.get().toBase64(); 0199 return QUrl(data_url); 0200 } 0201 0202 QString glaxnimate::model::Bitmap::object_name() const 0203 { 0204 if ( embedded() ) 0205 return i18n("Embedded image"); 0206 return QFileInfo(filename.get()).fileName(); 0207 } 0208 0209 0210 QFileInfo glaxnimate::model::Bitmap::file_info() const 0211 { 0212 return QFileInfo(document()->io_options().path, filename.get()); 0213 } 0214 0215 0216 bool glaxnimate::model::Bitmap::remove_if_unused(bool) 0217 { 0218 if ( users().empty() ) 0219 { 0220 document()->push_command(new command::RemoveObject( 0221 this, 0222 &document()->assets()->images->values 0223 )); 0224 return true; 0225 } 0226 return false; 0227 } 0228 0229 void glaxnimate::model::Bitmap::set_pixmap(const QImage& pix, const QString& format) 0230 { 0231 this->format.set(format); 0232 data.set(build_embedded(pix)); 0233 } 0234 0235 QByteArray glaxnimate::model::Bitmap::image_data() const 0236 { 0237 if ( !data.get().isEmpty() ) 0238 return data.get(); 0239 0240 if ( image.isNull() ) 0241 return {}; 0242 0243 return build_embedded(image.toImage()); 0244 } 0245 0246 QSize glaxnimate::model::Bitmap::size() const 0247 { 0248 return {width.get(), height.get()}; 0249 }