From 9d9989f177c243511fb92c678a28a51347b9b85e Mon Sep 17 00:00:00 2001 From: bmdeeal Date: Thu, 10 Mar 2022 03:16:04 -0500 Subject: [PATCH] First version First version of CE-Flipper. Should be feature complete, although there may be a few little changes here and there if I notice anything odd. --- .gitignore | 4 + AssemblyInfo.cs | 51 +++++++ Form1.cs | 305 ++++++++++++++++++++++++++++++++++++++++ Form1.resx | 217 ++++++++++++++++++++++++++++ ce-flipper-conv.sh | 57 ++++++++ ce-flipper.csdproj | 164 +++++++++++++++++++++ ce-flipper.csdproj.user | 55 ++++++++ ce-flipper.sln | 23 +++ img.anim | 1 + img.anim-00001.bmp | Bin 0 -> 3902 bytes img.anim-00002.bmp | Bin 0 -> 3902 bytes img.anim-00003.bmp | Bin 0 -> 3902 bytes license.txt | 7 + readme.txt | 92 ++++++++++++ 14 files changed, 976 insertions(+) create mode 100644 .gitignore create mode 100644 AssemblyInfo.cs create mode 100644 Form1.cs create mode 100644 Form1.resx create mode 100644 ce-flipper-conv.sh create mode 100644 ce-flipper.csdproj create mode 100644 ce-flipper.csdproj.user create mode 100644 ce-flipper.sln create mode 100644 img.anim create mode 100644 img.anim-00001.bmp create mode 100644 img.anim-00002.bmp create mode 100644 img.anim-00003.bmp create mode 100644 license.txt create mode 100644 readme.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e29e6a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.exe +*.suo +bin/ +obj/ diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs new file mode 100644 index 0000000..1b3bd70 --- /dev/null +++ b/AssemblyInfo.cs @@ -0,0 +1,51 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified - the assembly cannot be signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. +// (*) If the key file and a key name attributes are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP - that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the file is installed into the CSP and used. +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/Form1.cs b/Form1.cs new file mode 100644 index 0000000..f832532 --- /dev/null +++ b/Form1.cs @@ -0,0 +1,305 @@ +using System; +using System.Drawing; +using System.Collections; +using System.Windows.Forms; +using System.Data; + +/* + CE-Flipper -- a really, really basic animation program for Windows CE. + (C) 2022 B.M.Deeal + Tested on a device running CE2.0 with the .NET Compact Framework installed. + + The file format is extremely simple: + * a .anim file (eg, "my-anim.anim") + * a set of .bmp format images (eg, "my-anim.anim-00001.bmp") + All must be in the same folder. The drawing area is 240x120 -- larger images will be cropped. + The .anim file contains no information inside and is just used to identify an image set as an animation. + + By default, animations run with about 330ms of delay between frames. This can be changed in the menu. + + This program was written for a particularly slow handheld system and is a quick and dirty hack. + Faster CE devices can just use a real video player like TCPMP and real video formats. +*/ +namespace ce_flipper +{ + /// + /// Main form + /// + public class Form1 : System.Windows.Forms.Form + { + private string loaded=""; + private bool ready=false; + private Bitmap current; + private Bitmap previous; + private bool loop=false; + private int frame=1; + + private System.Windows.Forms.PictureBox pictureBoxArea; + private System.Windows.Forms.Timer timer1; + private System.Windows.Forms.MainMenu mainMenu1; + private System.Windows.Forms.MenuItem menuItem1; + private System.Windows.Forms.MenuItem menuItem2; + private System.Windows.Forms.MenuItem menuItem3; + private System.Windows.Forms.MenuItem menuItem4; + private System.Windows.Forms.MenuItem menuItem5; + private System.Windows.Forms.MenuItem menuItem6; + private System.Windows.Forms.MenuItem menuItemLoop; + private System.Windows.Forms.MenuItem menuItem7; + private System.Windows.Forms.MenuItem menuItem8; + private System.Windows.Forms.MenuItem menuItem9; + + public Form1() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + // + // TODO: Add any constructor code after InitializeComponent call + // + } + /// + /// Clean up any resources being used. + /// + protected override void Dispose( bool disposing ) + { + base.Dispose( disposing ); + } + #region Windows Form Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.timer1 = new System.Windows.Forms.Timer(); + this.pictureBoxArea = new System.Windows.Forms.PictureBox(); + this.mainMenu1 = new System.Windows.Forms.MainMenu(); + this.menuItem1 = new System.Windows.Forms.MenuItem(); + this.menuItem2 = new System.Windows.Forms.MenuItem(); + this.menuItem4 = new System.Windows.Forms.MenuItem(); + this.menuItem3 = new System.Windows.Forms.MenuItem(); + this.menuItem5 = new System.Windows.Forms.MenuItem(); + this.menuItem6 = new System.Windows.Forms.MenuItem(); + this.menuItemLoop = new System.Windows.Forms.MenuItem(); + this.menuItem7 = new System.Windows.Forms.MenuItem(); + this.menuItem8 = new System.Windows.Forms.MenuItem(); + this.menuItem9 = new System.Windows.Forms.MenuItem(); + // + // timer1 + // + this.timer1.Enabled = true; + this.timer1.Interval = 330; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // pictureBoxArea + // + this.pictureBoxArea.Location = new System.Drawing.Point(8, 32); + this.pictureBoxArea.Size = new System.Drawing.Size(240, 120); + // + // mainMenu1 + // + this.mainMenu1.MenuItems.Add(this.menuItem1); + this.mainMenu1.MenuItems.Add(this.menuItem6); + // + // menuItem1 + // + this.menuItem1.MenuItems.Add(this.menuItem2); + this.menuItem1.MenuItems.Add(this.menuItem5); + this.menuItem1.MenuItems.Add(this.menuItem4); + this.menuItem1.MenuItems.Add(this.menuItem3); + this.menuItem1.Text = "File"; + this.menuItem1.Click += new System.EventHandler(this.menuItem1_Click); + // + // menuItem2 + // + this.menuItem2.Text = "Load"; + this.menuItem2.Click += new System.EventHandler(this.menuItem2_Click); + // + // menuItem4 + // + this.menuItem4.Text = "Stop"; + this.menuItem4.Click += new System.EventHandler(this.menuItem4_Click); + // + // menuItem3 + // + this.menuItem3.Text = "Exit"; + this.menuItem3.Click += new System.EventHandler(this.menuItem3_Click); + // + // menuItem5 + // + this.menuItem5.Text = "Play"; + this.menuItem5.Click += new System.EventHandler(this.menuItem5_Click); + // + // menuItem6 + // + this.menuItem6.MenuItems.Add(this.menuItemLoop); + this.menuItem6.MenuItems.Add(this.menuItem7); + this.menuItem6.MenuItems.Add(this.menuItem8); + this.menuItem6.MenuItems.Add(this.menuItem9); + this.menuItem6.Text = "Options"; + // + // menuItemLoop + // + this.menuItemLoop.Text = "Loop"; + this.menuItemLoop.Click += new System.EventHandler(this.menuItemLoop_Click); + // + // menuItem7 + // + this.menuItem7.Text = "Delay 330ms (normal)"; + this.menuItem7.Click += new System.EventHandler(this.menuItem7_Click); + // + // menuItem8 + // + this.menuItem8.Text = "Delay 110ms (fast)"; + this.menuItem8.Click += new System.EventHandler(this.menuItem8_Click); + // + // menuItem9 + // + this.menuItem9.Text = "Delay 660ms (slow)"; + this.menuItem9.Click += new System.EventHandler(this.menuItem9_Click); + // + // Form1 + // + this.BackColor = System.Drawing.Color.Black; + this.ClientSize = new System.Drawing.Size(258, 175); + this.Controls.Add(this.pictureBoxArea); + this.Menu = this.mainMenu1; + this.Text = "CE-Flipper Animation Player"; + this.Load += new System.EventHandler(this.Form1_Load); + + } + #endregion + + /// + /// The main entry point for the application. + /// + + static void Main() + { + Application.Run(new Form1()); + } + + private void Form1_Load(object sender, System.EventArgs e) + { + + } + + private void timer1_Tick(object sender, System.EventArgs e) + { + timer1.Enabled=false; + if (ready) + { + try + { + previous=current; + current = new Bitmap(loaded+"-"+frame.ToString("D5")+".bmp"); + pictureBoxArea.Image = current; + previous.Dispose(); + frame=frame+1; + timer1.Enabled=true; + } + //deal with problems + catch (Exception) + { + //if we have a problem on the first frame, complain loudly + if (frame==1) + { + MessageBox.Show("Error playing animation!"); + ready=false; + } + //if we're not looping, stop playback + else if (!loop) + { + ready=false; + } + //if we are looping, go back to the start + else + { + frame=1; + timer1.Enabled=true; + } + } + } + } + + //load menu option + private void menuItem2_Click(object sender, System.EventArgs e) + { + //ask for the file + OpenFileDialog dialog=new OpenFileDialog(); + dialog.Filter="CE-Flipper Animations (*.anim)|*.anim|All files (*.*)|*.*"; + dialog.ShowDialog(); + if (dialog.FileName!="") + { + frame=1; + loaded=dialog.FileName; + timer1.Enabled=false; + try + { + current = new Bitmap(loaded+"-"+frame.ToString("D5")+".bmp"); + pictureBoxArea.Image=current; + } + catch (Exception) + { + ready=false; + timer1.Enabled=false; + MessageBox.Show("Error loading animation!"); + } + } + } + + //exit menu option + private void menuItem3_Click(object sender, System.EventArgs e) + { + Application.Exit(); + } + + //stop menu option + private void menuItem4_Click(object sender, System.EventArgs e) + { + timer1.Enabled=false; + ready=false; + } + + //nothing + private void menuItem1_Click(object sender, System.EventArgs e) + { + + } + + //play menu option + private void menuItem5_Click(object sender, System.EventArgs e) + { + frame=1; + ready=true; + timer1.Enabled=true; + } + + //normal delay menu option + private void menuItem7_Click(object sender, System.EventArgs e) + { + timer1.Interval=330; + } + + //fast delay menu option + private void menuItem8_Click(object sender, System.EventArgs e) + { + timer1.Interval=110; + } + + //slow delay menu option + private void menuItem9_Click(object sender, System.EventArgs e) + { + timer1.Interval=660; + } + + //toggle looping + private void menuItemLoop_Click(object sender, System.EventArgs e) + { + loop=!loop; + menuItemLoop.Checked=loop; + } + } +} diff --git a/Form1.resx b/Form1.resx new file mode 100644 index 0000000..e9c3b07 --- /dev/null +++ b/Form1.resx @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Windows.Forms.Design.CFResXResourceReader, System.CF.Design, Version=7.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + System.Windows.Forms.Design.CFResXResourceWriter, System.CF.Design, Version=7.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Private + + + 17, 17 + + + Private + + + False + + + Private + + + Private + + + Private + + + 104, 17 + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + Private + + + False + + + (Default) + + + False + + + False + + + 8, 8 + + + Form1 + + + True + + + 80 + + + True + + + Private + + \ No newline at end of file diff --git a/ce-flipper-conv.sh b/ce-flipper-conv.sh new file mode 100644 index 0000000..453e67c --- /dev/null +++ b/ce-flipper-conv.sh @@ -0,0 +1,57 @@ +#!/bin/bash +#2022 B.M.Deeal +#this script distributed under CC0 + +#show help +#this also stops rogue arguments from being passed to ffmpeg or imagemagick +if [ $# -eq 0 ] || [[ "$1" =~ ^-.* ]] || [ "$1" == "" ] +then + echo "ce-flipper-conv.sh -- convert a video to CE-Flipper format" + echo "2022 B.M.Deeal." + echo "" + echo "This script will convert an ffmpeg compatible video file into a folder of .bmp images with a .anim file." + echo "The images will be in 'ce-flipper-output/'." + echo "Use at own risk, almost certainly contains bugs!" + echo "Requires ffmpeg and imagemagick." + echo "" + echo "usage:" + echo " ce-flipper-conv.sh video-file" + echo "" + exit 0 +fi + +#construct filenames +fn="$1" #name of file +fn_base="$(basename -- "$fn")" #name of file without path +fn_ext="${fn_base##*.}" #extension of file +fn_strip="$(basename "$fn" ".$fn_ext")" #filename without extension +fn_dir="$(dirname "$fn")" #directory of file +out_dir="$fn_dir/ce-flipper-output" #output directory for script + +#generate output folder +mkdir "$out_dir" +if [ -d "$out_dir" ] +then + #make flag file for ce-flipper + touch "$out_dir/$fn_strip.anim" + #convert video to .png + if ! ffmpeg -i "$fn" -r 3 "$out_dir/$fn_strip.anim-%5d.png" + then + echo "error: ffmpeg could not convert '$1'!" + exit 1 + fi + #convert .png to .bmp + #you can play with that convert command to your liking + #would just use normal error-diffusion dithering but imagemagick produces particularly ugly results for monochrome images (contrast doing it in GIMP, which looks quite nice) + #CE-Flipper doesn't need to use 1-bit .bmp files, but my device is grayscale (and slow) so it works better with them + cd "$out_dir" + for f in *.png + do + echo "generating $(basename "$f" ".png").bmp" + convert "$f" -resize "240x120>" +dither -ordered-dither o2x2 -monochrome -colors 2 "BMP3:$(basename "$f" ".png").bmp" + rm "$f" + done +else + echo "error: could not make '$out'!" + exit 1 +fi diff --git a/ce-flipper.csdproj b/ce-flipper.csdproj new file mode 100644 index 0000000..9924419 --- /dev/null +++ b/ce-flipper.csdproj @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ce-flipper.csdproj.user b/ce-flipper.csdproj.user new file mode 100644 index 0000000..311b619 --- /dev/null +++ b/ce-flipper.csdproj.user @@ -0,0 +1,55 @@ + + + + + + + + + + + + + diff --git a/ce-flipper.sln b/ce-flipper.sln new file mode 100644 index 0000000..44f90dd --- /dev/null +++ b/ce-flipper.sln @@ -0,0 +1,23 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{20D4826A-C6FA-45DB-90F4-C717570B9F32}") = "ce-flipper", "ce-flipper.csdproj", "{7C865EB8-72E0-4295-949C-3997636A3055}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {7C865EB8-72E0-4295-949C-3997636A3055}.Debug.ActiveCfg = Debug|Windows CE + {7C865EB8-72E0-4295-949C-3997636A3055}.Debug.Build.0 = Debug|Windows CE + {7C865EB8-72E0-4295-949C-3997636A3055}.Debug.Deploy.0 = Debug|Windows CE + {7C865EB8-72E0-4295-949C-3997636A3055}.Release.ActiveCfg = Release|Windows CE + {7C865EB8-72E0-4295-949C-3997636A3055}.Release.Build.0 = Release|Windows CE + {7C865EB8-72E0-4295-949C-3997636A3055}.Release.Deploy.0 = Release|Windows CE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/img.anim b/img.anim new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/img.anim @@ -0,0 +1 @@ +3 diff --git a/img.anim-00001.bmp b/img.anim-00001.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ad4061a985ff6879abf576112fb5315f476815c5 GIT binary patch literal 3902 zcmeH}OHSl45QZz$64}u=AX^TBI@0X94+{i2nim`-N9bi1QEL9Gq8-Qa1F4aCXpHO* z{#>u$Zm0h~o{psLgz+BzjQ)h);7=R)+pTq*u#uSwz0l}e@R8_{PEzxmP)$?ez7F{6 z*0pLcauJ`8?Alo#WA0>9_|TMi%T(rbg-==D&4}NgbG&8YhcVA5@Wv?*s>Ak+F7C+V zg-1FY@7M_+#J-2Y+AbWQ6V95||C;7Re=@vX#GdFT!y$ho{5H=Ikbv&;yk*2V<$0%^ zbbsUgN5t=izvMX!Uucfbq3R>{!Ve2Q`*Ua-DMw{uMv&ndOT#Tt&ZHR$e@OD-LwxAU z_Cv=R|CX!pQ!>7B*Oxg~4Sm60IrF@)-~6XW(I;f`CZF5mjhIe>#uTua%_us_P?AjsrQda;q1;R zaJ~N)dli{@7`=Y-#l-(b-c>lxPSGB*m*^JW#HX&pvAH>WSfb$#)}xBGdH;6xGV)ixjJKq8&rSX%&q*8_~_Bd4gDj!i{*zK z`xe{=-u8b&_uAb!bIBhUhR7~6x_{cuihm0GkrQ^t(dG6HKKLii$Gv_OojIRQMg6n= z#CPzb{~CPK`P1AVi2e-E=lWsqC!>c!A7^pJQQP3uVKCX^e$71D<}cB&Ce`b|#2xAq zhLr$Se3{1YIj#}TRaGPD5bhMjYifX#U&M0*oqR3DEAD;+pJGhGRBGVUKJ-T#KbM-P znWWvi$CS(d3l@1br(d&wdQQLp=Qwa$T3cTx|7x9;&kbk=WDC(QGU&Z|$_n>@kv-_7z zIXA{UTYoe7V(MeLzByUxe*d$$N-Pp`QN;m-Cjuy6M+qnwH4k9?`V1E>3-I&dD53EL z0Y70te!d)40NX+^Ut++DCLmm0>r4URvR45l0ew6uUWEaa%MLi%BIB5#4iYeqCWUpt zIc}l#2{@mX!oVZWrBV=h6meAG6U2N}D>wx)ryj)|O?Dn7xT*tZL4u>n)`1jP9$A4Y zt~{~}q_|WG%mQv;7sTIA*f%B3M|TE}V|Cjk;E{2Faw{8xjX=h|EHmQVOap-}F2=c8 z7#7HJT^xC?C-&L-;2nsVILE>S<{DccPt`#faE^5q1aPkJ7atJu(K9uQxPJRxP|We& zD{#7nc)q@%Ai+w#g()s2mPv5Mxbu^yby`4e9wTmiu5uiU+m#oXW&-^Wk&xheo92p0 z@li?S_3QIXlvv + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..4e37b80 --- /dev/null +++ b/readme.txt @@ -0,0 +1,92 @@ +CE-Flipper - a really, really basic animation program for Windows CE. +(C) 2022 B.M.Deeal + +=== + +CE-Flipper is distributed under the ISC License, see license.txt for details. +CE-Flipper was developed under Visual Studio .NET 2003 running on Windows 2000 and tested devices running CE2.0 and 2.11 with the .NET Compact Framework installed. + +=== +About: + +CE-Flipper plays back low framerate flipbook-style animations on a device with .NET Compact Edition. + +This program was written for a particularly slow handheld system and is a quick and dirty hack. +Faster CE devices can just use a real video player like TCPMP and real video formats. +In addition, you can convert image sequences like used in CE-Flipper to a real animation or video format with ffmpeg. + +The file format is quite simple, consisting of a set of files: +* a .anim file (eg, "my-anim.anim"). This file contains no information inside and is just used to identify an image set as an animation. +* a set of .bmp format images (eg, "my-anim.anim-00120.bmp") + +All files must be together in the same folder. The drawing area is 240x120 -- larger images will be cropped. + +=== +Installation: + +Simply copy ce-flipper.exe to your Windows CE device. +If you are using a device running CE2.x, you must rename the ce-flipper.exe to ce-flipper.net, or else it will not run. +Your system must have the .NET Compact Framework installed to run CE-Flipper. +If you are running CE 4.1 or later and do not have it, you can download it from here: + https://www.microsoft.com/en-us/download/details.aspx?id=24690 + +If you are running CE 2.0 to 4.0, you can compatible versions on HPCFactor: + https://www.hpcfactor.com/scl/search.asp?freetext=.net+compact+framework&Search=Search&title=true + + +A device with a newer version of Windows CE is highly recommended, although CE-Flipper's usefulness rapidly decreases due to a newer device being able to play back video or .gif animations. + +Do not attempt to run CE-Flipper on a desktop Windows system, as the program will freeze when attempting to load a file. +It wouldn't be too hard to provide a version of CE-Flipper for desktop Windows, but the current .exe targets only the .NET Compact Framework. + +=== +Usage: + +Go to File > Load to select a .anim file. +File > Play will begin playback from the start. +By default, animations run with about 330ms of delay between frames. This can be changed in the Options menu. You can also enable looping of the animation in Options. Timing is not precise, and on a slower device, you may want to select the 110ms fast speed. +File > Stop will stop the animation. +File > Exit will end the program. + +If CE-Flipper does not open, and you have .NET Compact Framework installed, try moving the application to a different location. In addition, try plugging in your device. + +=== +Creating files: + +A Bash shell script is provided to convert video files from (nearly) any format that ffmpeg supports. The script requires ffmpeg and imagemagick to be installed. +I wrote the script using WSL on Windows 10 running Ubuntu 20.04. +The script will generate 1-bit monochrome .bmp files. +Use at your own risk, it was very slapped together and might clobber some of your files if you're unlucky. You'll probably want to run it in a folder with nothing but your target video in it. + +You can also manually create your own animations. +Create an empty file and call it filename.anim (you can replace filename with whatever you want, just keep it consistent). +Then, create a sequence of 240x120 (or smaller) images in Paint, each named filename.anim-00001.bmp, filename.anim-00002.bmp, filename.anim-00003.bmp, etc, etc. +Some utilities save .BMP files that CE-Flipper will not be able to display. Re-saving them in MS Paint should fix this. + +Up to 99999 frames are supported -- possibly higher, but this has not been tested. + +=== +Some musings: + +I have a handful of old Windows CE systems, and I wanted to make them more useful. They're never going to be as useful as a modern system of any variety, mostly due to their extremely low speed, but one thing that stands out is the relative lack of software, especially since a lot of the shareware that was available can no longer be purchased, so there are only crippled trial versions around. + +I had the idea to maybe get some animation playing back on one of my B/W CE systems. It's slow, but it's also the most fun machine for me to use because of how clunky and limited it is. +Really, retrocomputing is like that. + +That particular system has CE2.0 on it, and .NET on CE2.0 has some major problems. In fact, if the device is not plugged in, CE-Flipper refuses to start, which is something I only found out as I was finishing up. +I have absolutely no clue as to why this is the case, and my only guess is that something on startup is timing out (the machine cuts its speed in half when on battery power). +The machine fails to run a lot of .NET CF programs, so I'm glad to say I've written one that works on it, even if only under certain conditions. + +My CE2.11 devices are quite a bit nicer (especially my Jornada 680), although I still hadn't gotten video on them. They run CE-Flipper quite well. +Still, because .NET Compact Framework on anything below CE 3 is a bit of a total hack, even that machine has a few issues with it. Namely, running it from \ce-flipper.net does not work, it has to be in a subfolder or on a memory card. +At least it has far fewer problems running .NET CF applications overall. + +If I was willing to trudge through writing WinAPI code for CE... I probably would have never written this. The standard CE development tools are deeply unpleasant, while writing a C# and WinForms program is easy and fun. +It would probably be faster and more reliable, but this went from "vague idea" to "basically working" in like two hours, most of which were spent looking up ffmpeg and imagemagick commands. +Still, I may end up writing another player entirely if the issues this one has on the intended machines grow to be too much of a problem. + +The code is a bit messy because Visual Studio 2003 lacks a bunch of features that later versions do that help a lot, like easy renaming of functions and variables. VS2003 isn't vastly different from using VS2019, but it is missing a lot of things I'm used to. + +I hope this is useful to someone other than me. At some point, I might do the less than ten minutes of work it would be to get this running on desktop .NET, saving this program from absolute obscurity, although there's really no point in animating like this vs just opening up GIMP, drawing a frame for each layer, and saving as an animated .gif when you're done there. + +--B.M.Deeal