当前位置: 首页 > article >正文

FLTK - FLTK1.4.1 - demo - animgifimage-play

文章目录

    • FLTK - FLTK1.4.1 - demo - animgifimage-play
    • 概述
    • 笔记
    • END

FLTK - FLTK1.4.1 - demo - animgifimage-play

概述

看的官方demo越多,在每个新demo中能看到的新增知识点越少。这是好事。
不可能一次将细节都记住,只要知道每个官方demo能干啥,有些啥新增知识点,这就够了。
就像一本好书一样,至少也要看几遍。
再不济,翻一遍,知道有啥,等需要的时候,再来拿。

// 播放多张gif, 并能控制(缩放,速度,正反向播放, 下一张图片)

// 新增知识点
// gif图像切换当前帧
// 所有的新窗体,都是作为当前窗体的子窗体存在, 所以fltk的窗体不用指定父窗体是谁

笔记

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    char* argv[4] = {};
    argv[0] = (char*)"app-name";
    argv[1] = (char*)"003_ over_rest.gif";
    argv[2] = (char*)"004_no_contact.gif";
    argv[3] = (char*)"005_bonded.gif";
    return fl_demo_main(4, argv);

    // return 0;
}
// FLTK - FLTK1.4.1 - demo - animgifimage-play

// 播放多张gif, 并能控制(缩放,速度,正反向播放, 下一张图片)

// 新增知识点
// gif图像切换当前帧
// 所有的新窗体,都是作为当前窗体的子窗体存在, 所以fltk的窗体不用指定父窗体是谁

#include "fltk_test.h"

// 如果要将fl demo的实现搬过来测试,就注释掉下面的宏
// #define DONT_USE_FL_DEMO

#ifdef DONT_USE_FL_DEMO
int fl_demo_main(int argc, char** argv)
{
	return 0;
}

#else

#endif // TEST_FL_DEMO

//
//  Demonstrates how to play an animated GIF file
//  under application control frame by frame if
//  this is needed.
//  Also demonstrates how to use a single animation
//  object to load multiple animations.
//
//  animgifimage <file> [-r] [-s speed_factor]
//
//  Multiple files can be specified e.g. testsuite/*
//
//  Use keys '+'/'-'/Enter to change speed, ' ' to pause.
//  Right key changes to next frame in paused mode.
//  'n' changes to next file, 'r' toggles reverse play.
//
#include <FL/Fl_Anim_GIF_Image.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl.H>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static double speed_factor = 1.; // slow down/speed up playback by factor
static bool reverse = false;  // true = play animation backwards
static bool paused = false;  // flag for paused animation
static bool frame_info = true; // flag to update current frame info in title
static Fl_Anim_GIF_Image animgif; // the animation object
static char** Argv = 0; // copy of main() argv[]
static int Argc = 0;    // copy of main() argc
static int current_arg = 0; // current index in argv[]

static int next_arg() {
    while (1) {
        current_arg++;
        if (current_arg >= Argc) {
            current_arg = 1;
        }
        if (Argv[current_arg]) break;
    }
    return current_arg;
}

static const char* next_file() {
    while (Argv[next_arg()][0] == '-');
    return Argv[current_arg];
}

static void set_title() {
    char buf[200];
    char fi[50];
    if (frame_info)
        snprintf(fi, sizeof(fi), "frame %d/%d", animgif.frame() + 1, animgif.frames());
    else
        snprintf(fi, sizeof(fi), "%d frames", animgif.frames());
    snprintf(buf, sizeof(buf), "%s (%s) x %3.2f %s%s",
        Argv[current_arg], fi,
        speed_factor, reverse ? "reverse" : "",
        paused ? " PAUSED" : "");

    Fl::first_window()->copy_label(buf);
}

static void cb_anim(void* d_) {
    Fl_Anim_GIF_Image* animgif = (Fl_Anim_GIF_Image*)d_;
    int frame{ animgif->frame() };

    // switch to next/previous frame
    if (reverse) {
        animgif->canvas()->window()->redraw();
        frame--;
        if (frame < 0) {
            frame = animgif->frames() - 1;
        }
    }
    else {
        frame++;
        if (frame >= animgif->frames()) {
            frame = 0;
        }
    }
    // set the frame (and update canvas)
    // gif图像切换当前帧
    animgif->frame(frame);

    // setup timer for next frame
    if (!paused && animgif->delay(frame)) {
        Fl::repeat_timeout(animgif->delay(frame) / speed_factor, cb_anim, d_);
    }
    if (frame_info)
        set_title();
}

static void next_frame() {
    cb_anim(&animgif);
}

static void toggle_pause() {
    paused = !paused;
    set_title();
    if (paused)
        Fl::remove_timeout(cb_anim, &animgif);
    else
        next_frame();
    set_title();
}

static void toggle_info() {
    frame_info = !frame_info;
    set_title();
}

static void toggle_reverse() {
    reverse = !reverse;
    set_title();
}

static void zoom(bool out) {
    int W = animgif.w();
    int H = animgif.h();
    // Note: deliberately no range check (use key 'N' to reset)
    static const double f = 1.05;
    // 设置图像在画布上的大小
    if (out)
        animgif.resize(int(W / f), int(H / f));
    else
        animgif.resize(int(f * W), int(f * H));
}

static void change_speed(int dir_) {
    if (dir_ > 0) {
        speed_factor += (speed_factor < 1) ? 0.01 : 0.1;
        if (speed_factor > 100)
            speed_factor = 100.;
    }
    else if (dir_ < 0) {
        speed_factor -= (speed_factor > 1) ? 0.1 : 0.01;
        if (speed_factor < 0.01)
            speed_factor = 0.01;
    }
    else {
        speed_factor = 1.;
    }
    set_title();
}

static void load_next() {
    Fl::remove_timeout(cb_anim, &animgif);
    paused = false;
    animgif.load(next_file());
    animgif.canvas()->window()->redraw();
    // check if loading succeeded
    printf("valid: %d frames: %d\n", animgif.valid(), animgif.frames());
    if (animgif.valid()) {
        printf("play '%s'%s with %3.2f x speed\n", animgif.name(),
            (reverse ? " reverse" : ""), speed_factor);
        animgif.frame(reverse ? animgif.frames() - 1 : 0);
        // setup first timeout, but check for zero-delay (normal GIF)!
        if (animgif.delay(animgif.frame())) {
            Fl::add_timeout(animgif.delay(animgif.frame()) / speed_factor, cb_anim, &animgif);
        }
    }
    set_title();
}

static int events(int event_) {
    if (event_ == FL_SHORTCUT && Fl::first_window()) {
        switch (Fl::event_key()) {
        case '+': change_speed(1); break;
        case '-': change_speed(-1); break;
        case FL_Enter: change_speed(0); break;
        case 'n': load_next(); break;
        case 'z': zoom(Fl::event_shift()); break;
        case 'i': toggle_info(); break; // Note: this can raise cpu usage considerably!
        case 'r': toggle_reverse(); break;
        case ' ': toggle_pause(); break;
        case FL_Right:
            if (paused && Fl::get_key(FL_Right)) next_frame();
            break;
        default:
            return 0;
        }
        Fl::first_window()->redraw();
        return 1;
    }
    return 0;
}

int fl_demo_main(int argc, char* argv[]) {
    // setup play parameters from args
    Argv = argv;
    Argc = argc;
    int n = 0;
    for (int i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "-r"))
            reverse = !reverse;
        else if (!strcmp(argv[i], "-s") && i + 1 < argc) {
            i++;
            speed_factor = atof(argv[i]);
            argv[i] = 0;
        }
        else if (argv[i][0] != '-') {
            n++;
            continue;
        }
        else {
            printf("Invalid argument: '%s'\n", argv[i]);
            exit(1);
        }
    }
    if (!n) {
        fprintf(stderr, "Test program for application controlled GIF animation.\n");
        fprintf(stderr, "Please specify one or more image files!\n");
        exit(0);
    }
    if (speed_factor < 0.01 || speed_factor > 100)
        speed_factor = 1.;

    Fl_Double_Window win(800, 600);

    // prepare a canvas for the animation
    // (we want to show it in the center of the window)
    Fl_Box canvas(0, 0, win.w(), win.h());
    // 所有的新窗体,都是作为当前窗体的子窗体存在, 所以fltk的窗体不用指定父窗体是谁
    Fl_Box help(0, win.h() - 20, win.w(), 20, "Keys: N=next file, I=toggle info, R=play reverse, +/-/Enter/Space=change speed, Z=Zoom");
    win.resizable(win);

    win.end();
    win.show();
    Fl::add_handler(events);

    // use the 'DONT_RESIZE_CANVAS' flag to tell the animation
    // not to change the canvas size (which is the default).
    unsigned short flags = Fl_Anim_GIF_Image::DONT_RESIZE_CANVAS;
    //  flags |= Fl_Anim_GIF_Image::DEBUG_FLAG|Fl_Anim_GIF_Image::LOG_FLAG;
    animgif.canvas(&canvas, flags);

    load_next();
    return Fl::run();
}

END


http://www.kler.cn/a/523540.html

相关文章:

  • HttpClient学习
  • Leetcode刷题-不定长滑动窗口
  • 关于el-table翻页后序号列递增的组件封装
  • 园区管理智能化创新引领企业效能提升与风险控制新趋势
  • SpringBoot统一数据返回格式 统一异常处理
  • JMeter插件 Arrivals Thread Group 源码解析:实现原理与性能测试中的应用
  • FLTK - FLTK1.4.1 - demo - animgifimage
  • 漂亮数 (线性筛+前缀和)
  • 【小白学AI系列】NLP 核心知识点(五)Transformer介绍
  • 99.19 金融难点通俗解释:营业总收入vs归母净利润vs扣非净利润
  • 新鲜速递:DeepSeek-R1开源大模型本地部署实战—Ollama + MaxKB 搭建RAG检索增强生成应用
  • 数论问题75
  • LeetCode题练习与总结:N 叉树的后序遍历--590
  • 2025年AI Agent(智能体)的发展机会
  • C语言连接Mysql
  • PCIe基础分享
  • TensorFlow实现逻辑回归模型
  • 本地部署 DeepSeek-R1 大模型指南:基于 Ollama 的完整流程
  • Cyber Security 101-Build Your Cyber Security Career-Security Principles(安全原则)
  • 软件工程-软件开发模型
  • RoboMaster- RDK X5能量机关实现案例(一)识别
  • .~C#循环结构
  • Vue学习四—— Home主体页面
  • 数据结构与算法分析:专题内容——人工智能中的寻路4之A*搜索(代码详解)
  • 智慧园区系统分类及其在提升企业管理效率中的创新应用探讨
  • 软件工程概论试题一