odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

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"