1// tImageJPG.cpp 
2// 
3// This class knows how to load and save a JPeg (.jpg and .jpeg) file. It does zero processing of image data. It knows 
4// the details of the jpg file format and loads the data into a tPixel array. These tPixels may be 'stolen' by the 
5// tPicture's constructor if a jpg file is specified. After the array is stolen the tImageJPG is invalid. This is 
6// purely for performance. The loading and saving uses libjpeg-turbo. See Licence_LibJpegTurbo.txt for more info. 
7// 
8// Copyright (c) 2020 Tristan Grimmer. 
9// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
10// granted, provided that the above copyright notice and this permission notice appear in all copies. 
11// 
12// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
13// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
14// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
15// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
16// PERFORMANCE OF THIS SOFTWARE. 
17 
18#include <System/tFile.h> 
19#include "Image/tImageJPG.h" 
20#if defined(PLATFORM_LINUX) 
21#include "TurboJpeg/Linux/turbojpeg.h" 
22#elif defined(PLATFORM_WINDOWS) 
23#include "TurboJpeg/Windows/turbojpeg.h" 
24#endif 
25 
26 
27using namespace tSystem
28namespace tImage 
29
30 
31 
32bool tImageJPG::Load(const tString& jpgFile, bool strict
33
34 Clear(); 
35 
36 if (tSystem::tGetFileType(jpgFile) != tSystem::tFileType::JPG
37 return false
38 
39 if (!tFileExists(jpgFile)) 
40 return false
41 
42 int numBytes = 0
43 uint8* jpgFileInMemory = tLoadFile(jpgFile, nullptr, &numBytes); 
44 bool success = Set(jpgFileInMemory, numBytes, strict); 
45 delete[] jpgFileInMemory
46 
47 return success
48
49 
50 
51bool tImageJPG::Set(const uint8* jpgFileInMemory, int numBytes, bool strict
52
53 Clear(); 
54 if ((numBytes <= 0) || !jpgFileInMemory
55 return false
56 
57 tjhandle tjInstance = tjInitDecompress(); 
58 if (!tjInstance
59 return false
60 
61 int subSamp = 0
62 int colourSpace = 0
63 int headerResult = tjDecompressHeader3(tjInstance, jpgFileInMemory, numBytes, &Width, &Height, &subSamp, &colourSpace); 
64 if (headerResult < 0
65 return false
66 
67 int numPixels = Width * Height
68 Pixels = new tPixel[numPixels]; 
69 
70 int jpgPixelFormat = TJPF_RGBA
71 int flags = 0
72 flags |= TJFLAG_BOTTOMUP
73 //flags |= TJFLAG_FASTUPSAMPLE; 
74 //flags |= TJFLAG_FASTDCT; 
75 flags |= TJFLAG_ACCURATEDCT
76 
77 int decomResult = tjDecompress2 
78
79 tjInstance, jpgFileInMemory, numBytes, (uint8*)Pixels
80 Width, 0, Height, jpgPixelFormat, flags 
81 ); 
82 
83 bool abortLoad = false
84 if (decomResult < 0
85
86 int errorSeverity = tjGetErrorCode(tjInstance); 
87 char* errorMsg = tjGetErrorStr2(tjInstance); 
88 switch (errorSeverity
89
90 case TJERR_WARNING
91 tPrintf("Warning: JPG ill-formed: %s\n", errorMsg); 
92 if (strict
93 abortLoad = true
94 break
95 
96 case TJERR_FATAL
97 tPrintf("Error: JPG fatally ill-formed: %s\n", errorMsg); 
98 abortLoad = true
99 break
100
101
102 
103 tjDestroy(tjInstance); 
104 if (abortLoad
105
106 Clear(); 
107 return false
108
109 
110 SrcPixelFormat = tPixelFormat::R8G8B8
111 return true
112
113 
114 
115bool tImageJPG::Set(tPixel* pixels, int width, int height, bool steal
116
117 Clear(); 
118 if (!pixels || (width <= 0) || (height <= 0)) 
119 return false
120 
121 Width = width
122 Height = height
123 if (steal
124
125 Pixels = pixels
126
127 else 
128
129 Pixels = new tPixel[Width*Height]; 
130 tStd::tMemcpy(Pixels, pixels, Width*Height*sizeof(tPixel)); 
131
132 
133 SrcPixelFormat = tPixelFormat::R8G8B8A8
134 return true
135
136 
137 
138bool tImageJPG::Save(const tString& jpgFile, int quality) const 
139
140 if (!IsValid()) 
141 return false
142 
143 if (tSystem::tGetFileType(jpgFile) != tSystem::tFileType::JPG
144 return false
145 
146 tjhandle tjInstance = tjInitCompress(); 
147 if (!tjInstance
148 return false
149 
150 uint8* jpegBuf = nullptr
151 ulong jpegSize = 0
152 
153 int flags = 0
154 flags |= TJFLAG_BOTTOMUP
155 //flags |= TJFLAG_FASTUPSAMPLE; 
156 //flags |= TJFLAG_FASTDCT; 
157 flags |= TJFLAG_ACCURATEDCT
158 
159 int compResult = tjCompress2(tjInstance, (uint8*)Pixels, Width, 0, Height, TJPF_RGBA
160 &jpegBuf, &jpegSize, TJSAMP_444, quality, flags); 
161 
162 tjDestroy(tjInstance); 
163 if (compResult < 0
164
165 tjFree(jpegBuf); 
166 return false
167
168 
169 tFileHandle fileHandle = tOpenFile(jpgFile.Chars(), "wb"); 
170 if (!fileHandle
171
172 tjFree(jpegBuf); 
173 return false
174
175 bool success = tWriteFile(fileHandle, jpegBuf, jpegSize); 
176 tCloseFile(fileHandle); 
177 tjFree(jpegBuf); 
178 
179 return success
180
181 
182 
183tPixel* tImageJPG::StealPixels() 
184
185 tPixel* pixels = Pixels
186 Pixels = nullptr
187 Width = 0
188 Height = 0
189 return pixels
190
191 
192 
193
194