Apply keyframes to the source frame (if any)
| 1322 | |
| 1323 | // Apply keyframes to the source frame (if any) |
| 1324 | void Clip::apply_keyframes(std::shared_ptr<Frame> frame, QSize timeline_size) { |
| 1325 | // Skip out if video was disabled or only an audio frame (no visualisation in use) |
| 1326 | if (!frame->has_image_data) { |
| 1327 | // Skip the rest of the image processing for performance reasons |
| 1328 | return; |
| 1329 | } |
| 1330 | |
| 1331 | // Get image from clip, and create transparent background image |
| 1332 | std::shared_ptr<QImage> source_image = frame->GetImage(); |
| 1333 | std::shared_ptr<QImage> background_canvas = std::make_shared<QImage>(timeline_size.width(), |
| 1334 | timeline_size.height(), |
| 1335 | QImage::Format_RGBA8888_Premultiplied); |
| 1336 | background_canvas->fill(QColor(Qt::transparent)); |
| 1337 | |
| 1338 | // Get transform from clip's keyframes |
| 1339 | QTransform transform = get_transform(frame, background_canvas->width(), background_canvas->height()); |
| 1340 | |
| 1341 | // Load timeline's new frame image into a QPainter |
| 1342 | QPainter painter(background_canvas.get()); |
| 1343 | painter.setRenderHint(QPainter::TextAntialiasing, true); |
| 1344 | if (!transform.isIdentity()) { |
| 1345 | painter.setRenderHint(QPainter::SmoothPixmapTransform, true); |
| 1346 | } |
| 1347 | // Apply transform (translate, rotate, scale) |
| 1348 | painter.setTransform(transform); |
| 1349 | |
| 1350 | // Composite a new layer onto the image |
| 1351 | painter.setCompositionMode(static_cast<QPainter::CompositionMode>(composite)); |
| 1352 | |
| 1353 | // Apply opacity via painter instead of per-pixel alpha manipulation |
| 1354 | const float alpha_value = alpha.GetValue(frame->number); |
| 1355 | if (alpha_value != 1.0f) { |
| 1356 | painter.setOpacity(alpha_value); |
| 1357 | painter.drawImage(0, 0, *source_image); |
| 1358 | // Reset so any subsequent drawing (e.g., overlays) isn’t faded |
| 1359 | painter.setOpacity(1.0); |
| 1360 | } else { |
| 1361 | painter.drawImage(0, 0, *source_image); |
| 1362 | } |
| 1363 | |
| 1364 | if (timeline) { |
| 1365 | Timeline *t = static_cast<Timeline *>(timeline); |
| 1366 | |
| 1367 | // Draw frame #'s on top of image (if needed) |
| 1368 | if (display != FRAME_DISPLAY_NONE) { |
| 1369 | std::stringstream frame_number_str; |
| 1370 | switch (display) { |
| 1371 | case (FRAME_DISPLAY_NONE): |
| 1372 | // This is only here to prevent unused-enum warnings |
| 1373 | break; |
| 1374 | |
| 1375 | case (FRAME_DISPLAY_CLIP): |
| 1376 | frame_number_str << frame->number; |
| 1377 | break; |
| 1378 | |
| 1379 | case (FRAME_DISPLAY_TIMELINE): |
| 1380 | frame_number_str << round((Position() - Start()) * t->info.fps.ToFloat()) + frame->number; |
| 1381 | break; |