1// tImageTIFF.h 
2// 
3// This knows how to load/save TIFFs. It knows the details of the tiff file format and loads the data into multiple 
4// tPixel arrays, one for each frame (in a TIFF thay are called pages). These arrays may be 'stolen' by tPictures. 
5// 
6// Copyright (c) 2020-2024 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> 
20#include <Image/tFrame.h> 
21#include <LibTIFF/include/tiffio.h> 
22#include <Image/tBaseImage.h> 
23namespace tImage 
24
25 
26 
27class tImageTIFF : public tBaseImage 
28
29public
30 // Creates an invalid tImageTIFF. You must call Load manually. 
31 tImageTIFF() { } 
32 tImageTIFF(const tString& tiffFile) { Load(tiffFile); } 
33 
34 // Creates a tImageAPNG from a bunch of frames. If steal is true, the srcFrames will be empty after. 
35 tImageTIFF(tList<tFrame>& srcFrames, bool stealFrames) { Set(srcFrames, stealFrames); } 
36 
37 // This one sets from a supplied pixel array. If steal is true it takes ownership of the pixels pointer. Otherwise 
38 // it just copies the data out. 
39 tImageTIFF(tPixel4b* pixels, int width, int height, bool steal = false) { Set(pixels, width, height, steal); } 
40 
41 // Sets from a single frame. 
42 tImageTIFF(tFrame* frame, bool steal = true) { Set(frame, steal); } 
43 
44 // Constructs from a tPicture. Single-frame. 
45 tImageTIFF(tPicture& picture, bool steal = true) { Set(picture, steal); } 
46 
47 virtual ~tImageTIFF() { Clear(); } 
48 
49 // Clears the current tImageTIFF before loading. If false returned object is invalid. 
50 bool Load(const tString& tiffFile); 
51 
52 // @todo No current in-memory loader. 
53 // bool Load(const uint8* tiffFileInMemory, int numBytes); 
54 
55 bool Set(tList<tFrame>& srcFrames, bool stealFrames); 
56 
57 // This one sets from a supplied pixel array. If steal is true it takes ownership of the pixels pointer. Otherwise 
58 // it just copies the data out. 
59 bool Set(tPixel4b* pixels, int width, int height, bool steal = false) override; 
60 
61 // Sets from a single frame. 
62 bool Set(tFrame*, bool steal = true) override; 
63 
64 // Sets from a tPicture. 
65 bool Set(tPicture& picture, bool steal = true) override; 
66 
67 enum class tFormat 
68
69 Invalid, // Invalid must be 0. 
70 BPP24, // RGB. 24 bit colour. 
71 BPP32, // RGBA. 24 bit colour and 8 bits opacity in the alpha channel. 
72 Auto // Save function will decide format. BPP24 if all image pixels are opaque and BPP32 otherwise. 
73 }; 
74 
75 struct SaveParams 
76
77 SaveParams() { Reset(); } 
78 SaveParams(const SaveParams& src) : Format(src.Format), UseZLibCompression(src.UseZLibCompression), OverrideFrameDuration(src.OverrideFrameDuration) { } 
79 void Reset() { Format = tFormat::Auto; UseZLibCompression = true; OverrideFrameDuration = -1; } 
80 SaveParams& operator=(const SaveParams& src) { Format = src.Format; UseZLibCompression = src.UseZLibCompression; OverrideFrameDuration = src.OverrideFrameDuration; return *this; } 
81 
82 tFormat Format
83 bool UseZLibCompression
84 int OverrideFrameDuration
85 }; 
86 
87 // Saves the tImageTIFF to the TIFF file specified. The type of filename must be TIFF (tif or tiff extension). 
88 // If tFormat is Auto, this function will decide the format. BPP24 if all image pixels are opaque and BPP32 
89 // otherwise. Since each frame (page in tiff parlance) may be stored in a different pixel format, we cannot return 
90 // the chosen pixel format as they mey be different between frames. Returns true on success. OverrideframeDuration 
91 // is in milliseconds. Set to >= 0 to override all frames. 
92 bool Save(const tString& tiffFile, tFormat, bool useZLibComp = true, int overrideFrameDuration = -1) const
93 bool Save(const tString& tiffFile, const SaveParams& = SaveParams()) const
94 
95 // After this call no memory will be consumed by the object and it will be invalid. 
96 void Clear() override; 
97 bool IsValid() const override { return (GetNumFrames() >= 1); } 
98 int GetNumFrames() const { return Frames.GetNumItems(); } 
99 
100 // Returns true if ALL frames are opaque. Slow. Checks all pixels. 
101 bool IsOpaque() const
102 
103 // After this call you are the owner of the frame and must eventually delete it. The frame you stole will no longer 
104 // be part of the tImageTIFF, but the remaining ones will still be there. GetNumFrames will be one fewer. 
105 tFrame* StealFrame(int frameNum); 
106 tFrame* GetFrame(bool steal = true) override; 
107 
108 // Similar to above but takes all the frames from the tImageTIFF and appends them to the supplied frame list. The 
109 // object will be invalid after since it will have no frames. 
110 void StealFrames(tList<tFrame>&); 
111 
112 // Returns a pointer to the frame, but it's not yours to delete. This object still owns it. 
113 tFrame* GetFrame(int frameNum); 
114 
115private
116 int ReadSoftwarePageDuration(TIFF*) const
117 bool WriteSoftwarePageDuration(TIFF*, int milliseconds) const
118 
119 tList<tFrame> Frames
120}; 
121 
122 
123// Implementation only below. 
124 
125 
126inline tFrame* tImage::tImageTIFF::StealFrame(int frameNum
127
128 tFrame* f = GetFrame(frameNum); 
129 if (!f
130 return nullptr
131 
132 return Frames.Remove(item: f); 
133
134 
135 
136inline void tImage::tImageTIFF::StealFrames(tList<tFrame>& frames
137
138 while (tFrame* frame = Frames.Remove()) 
139 frames.Append(item: frame); 
140
141 
142 
143inline tFrame* tImage::tImageTIFF::GetFrame(int frameNum
144
145 if ((frameNum >= Frames.GetNumItems()) || (frameNum < 0)) 
146 return nullptr
147 
148 tFrame* f = Frames.First(); 
149 while (frameNum--) 
150 f = f->Next(); 
151 
152 return f
153
154 
155 
156inline void tImageTIFF::Clear() 
157
158 while (tFrame* frame = Frames.Remove()) 
159 delete frame
160 
161 tBaseImage::Clear(); 
162
163 
164 
165
166