bl_demo_image_view.cpp (5793B)
1 #include <blend2d.h> 2 3 #include "bl_qt_headers.h" 4 #include "bl_qt_canvas.h" 5 6 class MainWindow : public QWidget { 7 Q_OBJECT 8 9 public: 10 // Widgets. 11 QLineEdit* _file_selected {}; 12 QPushButton* _file_selected_button {}; 13 QCheckBox* _animate_check_box {}; 14 QCheckBox* _background_check_box {}; 15 QPushButton* _next_frame_button {}; 16 QBLCanvas* _canvas {}; 17 18 BLArray<uint8_t> _image_file_data; 19 BLImageDecoder _image_decoder; 20 BLImageInfo _loaded_image_info {}; 21 BLImage _loaded_image; 22 BLString _error_message; 23 24 QTimer _timer; 25 26 MainWindow() { 27 QVBoxLayout* vBox = new QVBoxLayout(); 28 vBox->setContentsMargins(0, 0, 0, 0); 29 vBox->setSpacing(0); 30 31 QGridLayout* grid = new QGridLayout(); 32 grid->setContentsMargins(5, 5, 5, 5); 33 grid->setSpacing(5); 34 35 _file_selected = new QLineEdit(""); 36 _file_selected_button = new QPushButton("Select..."); 37 _animate_check_box = new QCheckBox("Animate"); 38 _animate_check_box->setChecked(true); 39 _background_check_box = new QCheckBox("White"); 40 _next_frame_button = new QPushButton("Next"); 41 _canvas = new QBLCanvas(); 42 43 connect(_file_selected_button, SIGNAL(clicked()), SLOT(selectFile())); 44 connect(_file_selected, SIGNAL(textChanged(const QString&)), SLOT(fileChanged(const QString&))); 45 connect(&_timer, SIGNAL(timeout()), this, SLOT(onTimer())); 46 connect(_next_frame_button, SIGNAL(clicked()), SLOT(onNextFrame())); 47 connect(_background_check_box, SIGNAL(clicked()), SLOT(onRedraw())); 48 49 _canvas->on_render_blend2d = std::bind(&MainWindow::on_render_blend2d, this, std::placeholders::_1); 50 51 grid->addWidget(new QLabel("Image:"), 0, 0); 52 grid->addWidget(_file_selected, 0, 1, 1, 3); 53 grid->addWidget(_file_selected_button, 0, 4); 54 grid->addWidget(_animate_check_box, 0, 5); 55 grid->addWidget(_background_check_box, 0, 6); 56 grid->addWidget(_next_frame_button, 0, 7); 57 58 vBox->addItem(grid); 59 vBox->addWidget(_canvas); 60 61 setLayout(vBox); 62 _timer.setInterval(50); 63 } 64 65 void keyPressEvent(QKeyEvent *event) override {} 66 void mousePressEvent(QMouseEvent* event) override {} 67 void mouseReleaseEvent(QMouseEvent* event) override {} 68 void mouseMoveEvent(QMouseEvent* event) override {} 69 70 bool create_decoder(const char* file_name) { 71 _image_file_data.reset(); 72 _image_decoder.reset(); 73 _loaded_image_info.reset(); 74 _loaded_image.reset(); 75 _error_message.clear(); 76 77 if (BLFileSystem::read_file(file_name, _image_file_data) != BL_SUCCESS) { 78 _error_message.assign("Failed to read the file specified"); 79 return false; 80 } 81 82 BLImageCodec codec; 83 if (codec.find_by_data(_image_file_data) != BL_SUCCESS) { 84 _error_message.assign("Failed to find a codec for the given file"); 85 return false; 86 } 87 88 if (codec.create_decoder(&_image_decoder) != BL_SUCCESS) { 89 _error_message.assign("Failed to create a decoder for the given file"); 90 return false; 91 } 92 93 if (_image_decoder.read_info(_loaded_image_info, _image_file_data) != BL_SUCCESS) { 94 _error_message.assign("Failed to read image information"); 95 return false; 96 } 97 98 return true; 99 } 100 101 bool read_frame() { 102 if (_image_decoder.read_frame(_loaded_image, _image_file_data) != BL_SUCCESS) { 103 _error_message.assign("Failed to decode the image"); 104 return false; 105 } 106 107 return true; 108 } 109 110 void load_image(const char* file_name) { 111 if (create_decoder(file_name)) { 112 if (read_frame()) { 113 if (_loaded_image_info.frame_count > 1u) { 114 _timer.start(); 115 } 116 } 117 } 118 119 _updateTitle(); 120 } 121 122 Q_SLOT void selectFile() { 123 QString file_name = _file_selected->text(); 124 QFileDialog dialog(this); 125 126 if (!file_name.isEmpty()) 127 dialog.setDirectory(QFileInfo(file_name).absoluteDir().path()); 128 129 dialog.setAcceptMode(QFileDialog::AcceptOpen); 130 dialog.setFileMode(QFileDialog::ExistingFile); 131 dialog.setNameFilter(QString("Image File (*.apng *.bmp *.jpeg *.jpg *.png *.qoi)")); 132 dialog.setViewMode(QFileDialog::Detail); 133 134 if (dialog.exec() == QDialog::Accepted) { 135 file_name = dialog.selectedFiles()[0]; 136 _file_selected->setText(file_name); 137 } 138 } 139 140 Q_SLOT void fileChanged(const QString&) { 141 QByteArray file_name_utf8 = _file_selected->text().toUtf8(); 142 file_name_utf8.append('\0'); 143 144 load_image(file_name_utf8.constData()); 145 _canvas->update_canvas(); 146 } 147 148 Q_SLOT void onTimer() { 149 if (!_animate_check_box->isChecked()) { 150 return; 151 } 152 153 if (read_frame()) { 154 _canvas->update_canvas(); 155 } 156 else { 157 _timer.stop(); 158 } 159 } 160 161 Q_SLOT void onNextFrame() { 162 if (_loaded_image_info.frame_count > 1u) { 163 if (read_frame()) { 164 _canvas->update_canvas(); 165 } 166 } 167 } 168 169 Q_SLOT void onRedraw() { 170 _canvas->update_canvas(); 171 } 172 173 void on_render_blend2d(BLContext& ctx) noexcept { 174 BLRgba32 background = _background_check_box->isChecked() ? BLRgba32(0xFFFFFFFFu) : BLRgba32(0xFF000000u); 175 176 ctx.fill_all(background); 177 ctx.blit_image(BLPointI(0, 0), _loaded_image); 178 } 179 180 void _updateTitle() { 181 BLString s; 182 183 if (!_error_message.is_empty()) { 184 s.assign_format("Load ERROR=%s", _error_message.data()); 185 } 186 else { 187 s.assign_format("Image Size=[%dx%d] Format=%s Depth=%u Compression=%s Frames=%llu", 188 _loaded_image.width(), 189 _loaded_image.height(), 190 _loaded_image_info.format, 191 _loaded_image_info.depth, 192 _loaded_image_info.compression, 193 (unsigned long long)_loaded_image_info.frame_count); 194 } 195 196 setWindowTitle(QString::fromUtf8(s.data())); 197 } 198 }; 199 200 int main(int argc, char *argv[]) { 201 QApplication app(argc, argv); 202 MainWindow win; 203 204 win.resize(QSize(580, 520)); 205 win.show(); 206 207 return app.exec(); 208 } 209 210 #include "bl_demo_image_view.moc"