IccMAX 2.1.27
Color Profile Tools
Loading...
Searching...
No Matches
iccJpegDump.cpp File Reference
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <fstream>
#include <arpa/inet.h>
+ Include dependency graph for iccJpegDump.cpp:

Go to the source code of this file.

Macros

#define LOG_ERROR(msg)   fprintf(stderr, "[ERROR] %s\n", msg)
 
#define safe_exit(reason)   do { LOG_ERROR(reason); exit(EXIT_FAILURE); } while (0)
 
#define TRAP()   abort()
 Core and external libraries necessary for the fuzzer functionality.
 

Typedefs

typedef unsigned char * jpeg_icc_profilep
 

Functions

bool ExtractIccFromJpeg (const char *jpegPath, const char *iccOutPath)
 
bool InjectIccIntoJpeg (const char *inputPath, const char *iccPath, const char *outputPath)
 
int main (int argc, char *argv[])
 
void Usage ()
 

Macro Definition Documentation

◆ LOG_ERROR

#define LOG_ERROR (   msg)    fprintf(stderr, "[ERROR] %s\n", msg)

◆ safe_exit

#define safe_exit (   reason)    do { LOG_ERROR(reason); exit(EXIT_FAILURE); } while (0)

◆ TRAP

#define TRAP ( )    abort()

Core and external libraries necessary for the fuzzer functionality.

This section includes the necessary headers for the Foundation framework, UIKit, Core Graphics, standard input/output, standard library, memory management, mathematical functions, Boolean type, floating-point limits, and string functions. These libraries support image processing, UI interaction, and basic C operations essential for the application.

Typedef Documentation

◆ jpeg_icc_profilep

typedef unsigned char* jpeg_icc_profilep

Function Documentation

◆ ExtractIccFromJpeg()

bool ExtractIccFromJpeg ( const char *  jpegPath,
const char *  iccOutPath 
)
159 {
160 FILE* fp = fopen(jpegPath, "rb");
161 if (!fp) safe_exit("Cannot open input JPEG file.");
162
163 std::vector<unsigned char> iccData;
164 unsigned char marker[2];
165 bool found = false;
166
167 // ------------------------------------------------------------
168 // Iterate JPEG markers and scan for APPx segments
169 // ------------------------------------------------------------
170 while (fread(marker, 1, 2, fp) == 2) {
171 if (marker[0] != 0xFF) break;
172 if (marker[1] == 0xD9) break; // EOI
173
174 unsigned short len = 0;
175 if (fread(&len, 2, 1, fp) != 1) break;
176 len = ntohs(len);
177
178 if (len < 2) break;
179 std::vector<unsigned char> segment(len - 2);
180 if (fread(segment.data(), 1, segment.size(), fp) != segment.size())
181 break;
182
183 printf("[INFO] Scanning segment 0x%02X, length: %u bytes\n", marker[1], len);
184
185 // --------------------------------------------------------
186 // Check for APP2 ICC_PROFILE header (spec-compliant)
187 // --------------------------------------------------------
188 if (marker[1] == 0xE2 && len > 16) {
189 if (memcmp(segment.data(), "ICC_PROFILE\0", 12) == 0) {
190 unsigned char* dataStart = segment.data() + 14;
191 size_t dataLen = segment.size() - 14;
192 iccData.insert(iccData.end(), dataStart, dataStart + dataLen);
193 printf("[INFO] Found ICC_PROFILE in APP2 segment.\n");
194 found = true;
195 break;
196 }
197 }
198
199 // --------------------------------------------------------
200 // Fallback: Search all APPx for "acsp" ICC signature
201 // --------------------------------------------------------
202 if (marker[1] >= 0xE0 && marker[1] <= 0xEF) {
203 for (size_t i = 0; i + 4 < segment.size(); ++i) {
204 if (memcmp(&segment[i], "acsp", 4) == 0) {
205 iccData.insert(iccData.end(), segment.begin() + i, segment.end());
206 printf("[INFO] Found 'acsp' ICC magic in APP segment 0x%02X at offset %zu.\n", marker[1], i);
207 found = true;
208 goto done;
209 }
210 }
211 }
212 }
213
214 // ------------------------------------------------------------
215 // Raw Fallback: Scan entire file for "acsp"
216 // ------------------------------------------------------------
217 if (!found) {
218 std::ifstream file(jpegPath, std::ios::binary);
219 if (!file) {
220 LOG_ERROR("Fallback open failed.");
221 return false;
222 }
223
224 std::vector<unsigned char> raw((std::istreambuf_iterator<char>(file)),
225 std::istreambuf_iterator<char>());
226
227 for (size_t i = 0; i + 4 < raw.size(); ++i) {
228 if (memcmp(&raw[i], "acsp", 4) == 0) {
229 iccData.insert(iccData.end(), raw.begin() + i, raw.end());
230 printf("[INFO] Fallback: Found 'acsp' in raw file at offset %zu.\n", i);
231 found = true;
232 break;
233 }
234 }
235 }
236
237done:
238 fclose(fp);
239
240 if (iccData.empty()) {
241 LOG_ERROR("No ICC profile found.");
242 return false;
243 }
244
245 FILE* out = fopen(iccOutPath, "wb");
246 if (!out) safe_exit("Failed to open output ICC file.");
247 fwrite(iccData.data(), 1, iccData.size(), out);
248 fclose(out);
249
250 printf("[INFO] ICC profile extracted to: %s\n", iccOutPath);
251 return true;
252}
#define LOG_ERROR(msg)
Definition iccJpegDump.cpp:125
#define safe_exit(reason)
Definition iccJpegDump.cpp:126

Referenced by main().

+ Here is the caller graph for this function:

◆ InjectIccIntoJpeg()

bool InjectIccIntoJpeg ( const char *  inputPath,
const char *  iccPath,
const char *  outputPath 
)
276 {
277 FILE* in = fopen(inputPath, "rb");
278 FILE* out = fopen(outputPath, "wb");
279 std::ifstream icc(iccPath, std::ios::binary);
280
281 if (!in || !out || !icc.is_open())
282 safe_exit("Cannot open input/output/ICC file.");
283
284 // ------------------------------------------------------------------------
285 // Read ICC profile into memory
286 // ------------------------------------------------------------------------
287 std::vector<unsigned char> iccData((std::istreambuf_iterator<char>(icc)),
288 std::istreambuf_iterator<char>());
289
290 // ------------------------------------------------------------------------
291 // Verify and copy SOI marker (0xFFD8)
292 // ------------------------------------------------------------------------
293 unsigned char soi[2];
294 // Line 294: Original Code
295 // fread(soi, 1, 2, in);
296
297 // Updated Code
298 size_t bytesRead = fread(soi, 1, 2, in);
299 if (bytesRead != 2) {
300 fprintf(stderr, "Error: Failed to read 2 bytes from the input file.\n");
301 fclose(in);
302 return false; // or handle the error as required
303 }
304 if (soi[0] != 0xFF || soi[1] != 0xD8)
305 safe_exit("Not a valid JPEG file.");
306 fwrite(soi, 1, 2, out);
307
308 // ------------------------------------------------------------------------
309 // Write APP2 segment with ICC header and payload
310 // Format:
311 // - Marker : 0xFFE2
312 // - Length : 2-byte big endian (header + payload)
313 // - Signature : "ICC_PROFILE" + '\0'
314 // - Sequence No : 1 (single-segment)
315 // - Total Segs : 1
316 // - ICC Data : full profile binary
317 // ------------------------------------------------------------------------
318 std::string sig = "ICC_PROFILE";
319 unsigned short markerLen = 2 + sig.size() + 1 + 2 + iccData.size(); // length includes itself
320 unsigned short markerBE = htons(markerLen);
321
322 fputc(0xFF, out); fputc(0xE2, out); // APP2
323 fwrite(&markerBE, 2, 1, out); // segment length
324 fwrite(sig.c_str(), 1, sig.size(), out); // "ICC_PROFILE"
325 fputc(0x00, out); // null terminator
326 fputc(1, out); fputc(1, out); // sequence 1 of 1
327 fwrite(iccData.data(), 1, iccData.size(), out); // profile payload
328
329 // ------------------------------------------------------------------------
330 // Append remainder of JPEG file unmodified
331 // ------------------------------------------------------------------------
332 unsigned char buf[4096];
333 size_t n;
334 while ((n = fread(buf, 1, sizeof(buf), in)) > 0)
335 fwrite(buf, 1, n, out);
336
337 fclose(in); fclose(out); icc.close();
338 return true;
339}

Referenced by main().

+ Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char *  argv[] 
)
357 {
358 if (argc < 2) {
359 Usage();
360 safe_exit("Missing arguments.");
361 }
362
363 // ------------------------------------------------------------------------
364 // Parse Command-Line Arguments
365 // ------------------------------------------------------------------------
366 const char* inputFile = nullptr;
367 const char* extractIccOut = nullptr;
368 const char* injectIccFile = nullptr;
369 const char* outputJpegFile = nullptr;
370
371 inputFile = argv[1];
372
373 for (int i = 2; i < argc; ++i) {
374 if (strcmp(argv[i], "--write-icc") == 0 && i + 1 < argc) {
375 injectIccFile = argv[++i];
376 } else if (strcmp(argv[i], "--output") == 0 && i + 1 < argc) {
377 outputJpegFile = argv[++i];
378 } else {
379 extractIccOut = argv[i];
380 }
381 }
382
383 // ------------------------------------------------------------------------
384 // ICC Injection Mode: Embed ICC profile into a JPEG
385 // ------------------------------------------------------------------------
386 if (injectIccFile && outputJpegFile) {
387 if (!InjectIccIntoJpeg(inputFile, injectIccFile, outputJpegFile)) {
388 safe_exit("Failed to inject ICC profile.");
389 }
390 printf("[INFO] ICC profile successfully injected into: %s\n", outputJpegFile);
391
392 // ------------------------------------------------------------------------
393 // ICC Extraction Mode: Extract ICC profile from a JPEG
394 // ------------------------------------------------------------------------
395 } else if (extractIccOut) {
396 if (!ExtractIccFromJpeg(inputFile, extractIccOut)) {
397 safe_exit("Failed to extract ICC profile.");
398 }
399
400 // ------------------------------------------------------------------------
401 // Invalid Argument Combinations
402 // ------------------------------------------------------------------------
403 } else {
404 Usage();
405 safe_exit("Invalid argument combination.");
406 }
407
408 return 0;
409}
void Usage()
Definition iccJpegDump.cpp:133
bool ExtractIccFromJpeg(const char *jpegPath, const char *iccOutPath)
Definition iccJpegDump.cpp:159
bool InjectIccIntoJpeg(const char *inputPath, const char *iccPath, const char *outputPath)
Definition iccJpegDump.cpp:276

References ExtractIccFromJpeg(), InjectIccIntoJpeg(), and Usage().

+ Here is the call graph for this function:

◆ Usage()

void Usage ( )
133 {
134 printf("Usage:\n");
135 printf(" iccJpegDump <input.jpg> [output.icc]\n");
136 printf(" - Extract ICC profile from JPEG (APP2 or EXIF-based) if present.\n");
137 printf(" iccJpegDump <input.jpg> --write-icc <profile.icc> --output <output.jpg>\n");
138 printf(" - Inject ICC profile into JPEG image.\n");
139}