Program Listing for File canvasutility.cpp¶
↰ Return to documentation for file (src/utility/canvasutility.cpp
)
/*
* CanvasUtility - Tools for managing Canvases.
*/
#include <QColor>
#include <QImage>
#include <QImageReader>
#include "canvasutility.h"
#include "canvas/canvas.h"
#include "core/point.h"
namespace PixelMaestroStudio {
// TODO: Move to separate thread
void CanvasUtility::load_image(const QString& filename, Canvas& canvas, MaestroControlWidget* maestro_control) {
QImageReader image(filename, filename.right(3).toLocal8Bit());
QSize canvas_size(canvas.get_section().get_dimensions().x, canvas.get_section().get_dimensions().y);
image.setScaledSize(canvas_size);
/*
* Get the number of frames.
* imageCount() = 0 if the image isn't animated, so we set it to 1 here to run the loop at least once.
*/
int framecount = 1;
if (image.imageCount() > 0) {
framecount = image.imageCount();
}
maestro_control->run_cue(
maestro_control->canvas_handler->set_num_frames(
maestro_control->section_control_widget_->get_section_index(),
maestro_control->section_control_widget_->get_layer_index(),
framecount));
// Read each frame
for (uint16_t frame_index = 0; frame_index < framecount; frame_index++) {
QImage frame = image.read();
// NOTE: Scales the image while retaining proportions
// frame = frame.scaled(canvas_size, Qt::AspectRatioMode::KeepAspectRatio);
frame = frame.convertToFormat(QImage::Format_Indexed8);
/*
* Extract the frame's color table.
* We do this for every frame to ensure each Pixel is assigned a color index, even though we only use the first frame's color table as the Palette.
* We also make sure the color table is at most 255 colors to avoid transparency issues.
*/
QVector<QRgb> color_table = frame.colorTable();
while (color_table.size() >= 256) {
color_table.removeLast();
}
if (image.currentImageNumber() == 0) {
// Set the frame rate. Note that this doesn't account for images with different timings per frame.
if (framecount > 1) {
maestro_control->run_cue(
maestro_control->canvas_handler->set_frame_timer(
maestro_control->section_control_widget_->get_section_index(),
maestro_control->section_control_widget_->get_layer_index(),
static_cast<uint16_t>(image.nextImageDelay())));
}
/*
* Copy the color table into a temporary RGB array so we can translate it into a Cue.
* Note that this only takes the color table from the first frame, so if other frames use different color palettes, they won't come out as expected.
*/
QVector<Colors::RGB> color_table_rgb(color_table.size());
for (uint8_t color = 0; color < color_table.size() - 1; color++) {
color_table_rgb[color].r = static_cast<uint8_t>(qRed(color_table.at(color)));
color_table_rgb[color].g = static_cast<uint8_t>(qGreen(color_table.at(color)));
color_table_rgb[color].b = static_cast<uint8_t>(qBlue(color_table.at(color)));
}
Palette palette(&color_table_rgb[0], static_cast<uint8_t>(color_table.size()));
maestro_control->run_cue(
maestro_control->canvas_handler->set_palette(
maestro_control->section_control_widget_->get_section_index(),
maestro_control->section_control_widget_->get_layer_index(),
palette));
}
/*
* Get the index of each pixel's color in the frame's palette.
* Then, copy each index into a temporary frame.
* Finally, draw the frame to the Canvas.
*/
uint8_t color_table_indices[canvas_size.width() * canvas_size.height()];
for (uint16_t y = 0; y < canvas_size.height(); y++) {
for (uint16_t x = 0; x < canvas_size.width(); x++) {
if (canvas.get_section().get_dimensions().in_bounds(x, y)) {
QColor pix_color = frame.pixelColor(x, y);
color_table_indices[canvas.get_section().get_dimensions().get_inline_index(x, y)] = static_cast<uint8_t>(color_table.indexOf(pix_color.rgb()));
}
}
}
maestro_control->run_cue(
maestro_control->canvas_handler->draw_frame(
maestro_control->section_control_widget_->get_section_index(),
maestro_control->section_control_widget_->get_layer_index(),
frame_index,
canvas_size.width(),
canvas_size.height(),
&color_table_indices[0]
)
);
// If this is an animated image, move to the next frame.
if (frame_index < (framecount - 1)) {
image.jumpToNextImage();
}
}
}
}