1// tImageAPNG.h 
2// 
3// This knows how to load animated PNGs (APNGs). It knows the details of the apng file format and loads the data into 
4// multiple tPixel arrays, one for each frame. These arrays may be 'stolen' by tPictures. 
5// 
6// Copyright (c) 2020 Tristan Grimmer. 
7// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
8// granted, provided that the above copyright notice and this permission notice appear in all copies. 
9// 
10// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
11// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
12// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
13// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
14// PERFORMANCE OF THIS SOFTWARE. 
15 
16#pragma once 
17#include <Foundation/tString.h> 
18#include <Math/tColour.h> 
19#include <Image/tPixelFormat.h> 
20namespace tImage 
21
22 
23 
24class tImageAPNG 
25
26public
27 // Creates an invalid tImageAPNG. You must call Load manually. 
28 tImageAPNG() { } 
29 tImageAPNG(const tString& apngFile) { Load(apngFile); } 
30 
31 virtual ~tImageAPNG() { Clear(); } 
32 
33 // Clears the current tImageAPNG before loading. If false returned object is invalid. 
34 bool Load(const tString& apngFile); 
35 
36 // After this call no memory will be consumed by the object and it will be invalid. 
37 void Clear(); 
38 bool IsValid() const { return (GetNumFrames() >= 1); } 
39 int GetNumFrames() const { return Frames.GetNumItems(); } 
40 
41 struct Frame : public tLink<Frame
42
43 int Width = 0
44 int Height = 0
45 tPixel* Pixels = nullptr
46 float Duration = 0.0f; // Frame duration in seconds. 
47 tPixelFormat SrcPixelFormat = tPixelFormat::Invalid
48 }; 
49 
50 // After this call you are the owner of the frame and must eventually delete it. The frame you stole will no 
51 // longer be a valid frame of the tImageAPNG, but the remaining ones will still be valid. 
52 Frame* StealFrame(int frameNum); 
53 Frame* GetFrame(int frameNum); 
54 tPixelFormat SrcPixelFormat = tPixelFormat::Invalid
55 
56 // Since some apng files may have a .png extension, it is hand to quickly be able to tell if a particular .png 
57 // file is an apng. Probably no one will ever read this comment, but the Mozilla apng people should probably not 
58 // have insisted that apngs be encoded in pngs. In any case, this slightly crappy code cannot guarantee that a 
59 // return value of true means it is an apng (although such a false positive is extremely unlikely). Even in these 
60 // cases, it just means the APNG reading code will be used -- it will still successfully extract the single frame. 
61 // 
62 // The preference is, however, that non-apng files be loaded by tImagePNG. It is faster and reads the src format 
63 // better than APngDis, which could be further modified but is unfamiliar code. 
64 static bool IsAnimatedPNG(const tString& pngFile); 
65 
66private
67 tList<Frame> Frames
68}; 
69 
70 
71// Implementation only below. 
72 
73 
74inline tImageAPNG::Frame* tImage::tImageAPNG::StealFrame(int frameNum
75
76 Frame* f = GetFrame(frameNum); 
77 if (!f
78 return nullptr
79 
80 return Frames.Remove(f); 
81
82 
83 
84inline tImageAPNG::Frame* tImage::tImageAPNG::GetFrame(int frameNum
85
86 if ((frameNum >= Frames.GetNumItems()) || (frameNum < 0)) 
87 return nullptr
88 
89 Frame* f = Frames.First(); 
90 while (frameNum--) 
91 f = f->Next(); 
92 
93 return f
94
95 
96 
97inline void tImageAPNG::Clear() 
98
99 while (Frame* frame = Frames.Remove()) 
100
101 delete[] frame->Pixels
102 delete frame
103
104 
105 SrcPixelFormat = tPixelFormat::Invalid
106
107 
108 
109
110