Traitement d'Images macOS Objective-C - Exemples

Exemples traitement d'images macOS Objective-C incluant lecture/écriture images, redimensionnement images et conversion format

💻 Lecture/Écriture d'Images objectivec

🟢 simple ⭐⭐

Lire images depuis fichiers URLs, sauver images divers formats via NSImage

⏱️ 20 min 🏷️ objectivec, macos, image processing
Prerequisites: Objective-C basics, AppKit framework
// macOS Objective-C Image Read/Save Examples
// Using AppKit framework

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>

// MARK: - 1. Read Image from File

@interface ImageReader : NSObject

+ (NSImage *)readImageFromFile:(NSString *)filePath;
+ (NSImage *)readImageFromURL:(NSURL *)url;
+ (NSArray<NSImage *> *)readImagesFromDirectory:(NSString *)directoryPath;

@end

@implementation ImageReader

+ (NSImage *)readImageFromFile:(NSString *)filePath {
    if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        NSLog(@"File not found: %@", filePath);
        return nil;
    }

    NSImage *image = [[NSImage alloc] initWithContentsOfFile:filePath];

    if (image) {
        NSSize size = image.size;
        NSLog(@"Loaded image from %@: %.0fx%.0f pixels", filePath, size.width, size.height);
    } else {
        NSLog(@"Failed to load image from: %@", filePath);
    }

    return image;
}

+ (NSImage *)readImageFromURL:(NSURL *)url {
    NSImage *image = [[NSImage alloc] initWithContentsOfURL:url];

    if (image) {
        NSSize size = image.size;
        NSLog(@"Loaded image from URL: %.0fx%.0f pixels", size.width, size.height);
    } else {
        NSLog(@"Failed to load image from URL: %@", url);
    }

    return image;
}

+ (NSArray<NSImage *> *)readImagesFromDirectory:(NSString *)directoryPath {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error = nil;

    NSArray *contents = [fileManager contentsOfDirectoryAtPath:directoryPath error:&error];

    if (!contents) {
        NSLog(@"Failed to read directory: %@", error.localizedDescription);
        return nil;
    }

    NSMutableArray *images = [NSMutableArray array];
    NSArray *imageExtensions = @[@"png", @"jpg", @"jpeg", @"gif", @"bmp", @"tiff", @"webp"];

    for (NSString *file in contents) {
        NSString *extension = [file pathExtension];
        NSString *filePath = [directoryPath stringByAppendingPathComponent:file];

        if ([imageExtensions containsObject:extension.lowercaseString]) {
            NSImage *image = [self readImageFromFile:filePath];
            if (image) {
                [images addObject:image];
            }
        }
    }

    NSLog(@"Loaded %lu images from directory", (unsigned long)images.count);
    return [images copy];
}

@end

// MARK: - 2. Save Image to File

@interface ImageSaver : NSObject

+ (BOOL)saveImage:(NSImage *)image
          toFile:(NSString *)filePath
       fileType:(NSBitmapImageFileType)fileType
          error:(NSError **)error;

+ (BOOL)saveImage:(NSImage *)image
          toFile:(NSString *)filePath
         asPNG:(BOOL)asPNG
          error:(NSError **)error;

+ (BOOL)saveImage:(NSImage *)image
          toFile:(NSString *)filePath
   withProperties:(NSDictionary<NSImageHintKey, id> *)properties
          error:(NSError **)error;

@end

@implementation ImageSaver

+ (BOOL)saveImage:(NSImage *)image
          toFile:(NSString *)filePath
       fileType:(NSBitmapImageFileType)fileType
          error:(NSError **)error {

    // Get bitmap representation
    NSData *imageData = [self imageDataFromImage:image fileType:fileType error:error];

    if (!imageData) {
        return NO;
    }

    // Write to file
    BOOL success = [imageData writeToFile:filePath options:NSDataWritingAtomic error:error];

    if (success) {
        NSLog(@"Saved image to: %@", filePath);
    } else {
        NSLog(@"Failed to save image: %@", (*error).localizedDescription);
    }

    return success;
}

+ (BOOL)saveImage:(NSImage *)image
          toFile:(NSString *)filePath
         asPNG:(BOOL)asPNG
          error:(NSError **)error {

    NSBitmapImageFileType fileType = asPNG ? NSPNGFileType : NSJPEGFileType;
    return [self saveImage:image toFile:filePath fileType:fileType error:error];
}

+ (BOOL)saveImage:(NSImage *)image
          toFile:(NSString *)filePath
   withProperties:(NSDictionary<NSImageHintKey, id> *)properties
          error:(NSError **)error {

    // Determine file type from extension
    NSString *extension = [[filePath pathExtension] lowercaseString];
    NSBitmapImageFileType fileType;

    if ([extension isEqualToString:@"png"]) {
        fileType = NSPNGFileType;
    } else if ([extension isEqualToString:@"jpg"] || [extension isEqualToString:@"jpeg"]) {
        fileType = NSJPEGFileType;
    } else if ([extension isEqualToString:@"gif"]) {
        fileType = NSGIFFileType;
    } else if ([extension isEqualToString:@"tiff"] || [extension isEqualToString:@"tif"]) {
        fileType = NSTIFFFileType;
    } else if ([extension isEqualToString:@"bmp"]) {
        fileType = NSBMPFileType;
    } else {
        if (error) {
            *error = [NSError errorWithDomain:@"ImageError"
                                         code:1
                                     userInfo:@{NSLocalizedDescriptionKey: @"Unsupported file type"}];
        }
        return NO;
    }

    // Get bitmap representation with properties
    NSData *imageData = [self imageDataFromImage:image fileType:fileType properties:properties error:error];

    if (!imageData) {
        return NO;
    }

    // Write to file
    BOOL success = [imageData writeToFile:filePath options:NSDataWritingAtomic error:error];

    if (success) {
        NSLog(@"Saved image to: %@", filePath);
    }

    return success;
}

+ (NSData *)imageDataFromImage:(NSImage *)image
                      fileType:(NSBitmapImageFileType)fileType
                         error:(NSError **)error {
    return [self imageDataFromImage:image fileType:fileType properties:nil error:error];
}

+ (NSData *)imageDataFromImage:(NSImage *)image
                      fileType:(NSBitmapImageFileType)fileType
                    properties:(NSDictionary *)properties
                         error:(NSError **)error {

    // Get bitmap representation
    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:image.TIFFRepresentation];

    if (!bitmapRep) {
        if (error) {
            *error = [NSError errorWithDomain:@"ImageError"
                                         code:2
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to get bitmap representation"}];
        }
        return nil;
    }

    // Create image data
    NSData *imageData = [bitmapRep representationUsingType:fileType properties:properties];

    if (!imageData) {
        if (error) {
            *error = [NSError errorWithDomain:@"ImageError"
                                         code:3
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to create image data"}];
        }
        return nil;
    }

    return imageData;
}

@end

// MARK: - 3. Image Information

@interface ImageInfo : NSObject

+ (NSDictionary *)getImageInfo:(NSImage *)image;
+ (void)printImageInfo:(NSImage *)image atPath:(NSString *)path;
+ (NSString *)getImageColorSpace:(NSImage *)image;

@end

@implementation ImageInfo

+ (NSDictionary *)getImageInfo:(NSImage *)image {
    if (!image) {
        return nil;
    }

    NSSize size = image.size;
    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:image.TIFFRepresentation];

    NSMutableDictionary *info = [NSMutableDictionary dictionary];
    info[@"width"] = @(size.width);
    info[@"height"] = @(size.height);
    info[@"pixelsWide"] = @(bitmapRep.pixelsWide);
    info[@"pixelsHigh"] = @(bitmapRep.pixelsHigh);
    info[@"bitsPerPixel"] = @(bitmapRep.bitsPerPixel);
    info[@"samplesPerPixel"] = @(bitmapRep.samplesPerPixel);
    info[@"colorSpaceName"] = bitmapRep.colorSpaceName ?: @"unknown";
    info[@"hasAlpha"] = @(bitmapRep.hasAlpha);
    info[@"isPlanar"] = @(bitmapRep.isPlanar);

    return [info copy];
}

+ (void)printImageInfo:(NSImage *)image atPath:(NSString *)path {
    NSDictionary *info = [self getImageInfo:image];

    if (!info) {
        NSLog(@"No image information available");
        return;
    }

    NSLog(@"\n--- Image Info: %@ ---", path);
    NSLog(@"Size: %.0fx%.0f pixels", [info[@"width"] doubleValue], [info[@"height"] doubleValue]);
    NSLog(@"Pixels: %lux%lu", (unsigned long)[info[@"pixelsWide"] integerValue], (unsigned long)[info[@"pixelsHigh"] integerValue]);
    NSLog(@"Bits per pixel: %@", info[@"bitsPerPixel"]);
    NSLog(@"Samples per pixel: %@", info[@"samplesPerPixel"]);
    NSLog(@"Color space: %@", info[@"colorSpaceName"]);
    NSLog(@"Has alpha: %@", info[@"hasAlpha"]);
    NSLog(@"Is planar: %@", info[@"isPlanar"]);
}

+ (NSString *)getImageColorSpace:(NSImage *)image {
    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:image.TIFFRepresentation];
    return bitmapRep.colorSpaceName;
}

@end

// MARK: - 4. Batch Image Operations

@interface BatchImageProcessor : NSObject

+ (BOOL)convertImagesInDirectory:(NSString *)inputDirectory
                    toOutputDirectory:(NSString *)outputDirectory
                           fileType:(NSBitmapImageFileType)fileType
                               error:(NSError **)error;

+ (BOOL)resizeImagesInDirectory:(NSString *)directory
                      toMaxWidth:(CGFloat)maxWidth
                     maxHeight:(CGFloat)maxHeight
                          error:(NSError **)error;

@end

@implementation BatchImageProcessor

+ (BOOL)convertImagesInDirectory:(NSString *)inputDirectory
                    toOutputDirectory:(NSString *)outputDirectory
                           fileType:(NSBitmapImageFileType)fileType
                               error:(NSError **)error {

    NSFileManager *fileManager = [NSFileManager defaultManager];

    // Create output directory
    if (![fileManager fileExistsAtPath:outputDirectory]) {
        [fileManager createDirectoryAtPath:outputDirectory
               withIntermediateDirectories:YES
                                attributes:nil
                                     error:error];
        if (*error) {
            return NO;
        }
    }

    // Read images
    NSArray *images = [ImageReader readImagesFromDirectory:inputDirectory];
    NSArray *contents = [fileManager contentsOfDirectoryAtPath:inputDirectory error:error];

    if (*error) {
        return NO;
    }

    // Filter and convert
    NSInteger successCount = 0;
    for (NSInteger i = 0; i < images.count && i < contents.count; i++) {
        NSImage *image = images[i];
        NSString *fileName = contents[i];
        NSString *outputPath = [outputDirectory stringByAppendingPathComponent:fileName];

        if ([ImageSaver saveImage:image toFile:outputPath fileType:fileType error:error]) {
            successCount++;
        }
    }

    NSLog(@"Converted %ld images", (long)successCount);
    return YES;
}

+ (BOOL)resizeImagesInDirectory:(NSString *)directory
                      toMaxWidth:(CGFloat)maxWidth
                     maxHeight:(CGFloat)maxHeight
                          error:(NSError **)error {

    NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directory error:error];

    if (*error) {
        return NO;
    }

    NSInteger processedCount = 0;

    for (NSString *fileName in contents) {
        NSString *filePath = [directory stringByAppendingPathComponent:fileName];

        NSImage *image = [ImageReader readImageFromFile:filePath];
        if (!image) continue;

        NSSize originalSize = image.size;
        NSSize newSize;

        if (originalSize.width > maxWidth || originalSize.height > maxHeight) {
            CGFloat widthRatio = maxWidth / originalSize.width;
            CGFloat heightRatio = maxHeight / originalSize.height;
            CGFloat ratio = MIN(widthRatio, heightRatio);

            newSize = NSMakeSize(originalSize.width * ratio, originalSize.height * ratio);

            // Resize (implementation would go here)
            processedCount++;
        }
    }

    NSLog(@"Processed %ld images", (long)processedCount);
    return YES;
}

@end

// MARK: - Main Demonstration

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"=== macOS Objective-C Image Read/Save Examples ===\n");

        // 1. Read image from file
        NSLog(@"--- 1. Read Image from File ---");

        NSString *testImagePath = @"/tmp/test_image.png";

        // Create a simple test image
        NSImage *testImage = [[NSImage alloc] initWithSize:NSMakeSize(200, 200)];
        [testImage lockFocus];
        [[NSColor blueColor] set];
        [NSBezierPath fillRect:NSMakeRect(0, 0, 200, 200)];
        [[NSColor whiteColor] set];
        NSString *text = @"Test Image";
        NSPoint textPoint = NSMakePoint(50, 90);
        [text drawAtPoint:textPoint withAttributes:nil];
        [testImage unlockFocus];

        // Save test image
        NSError *error = nil;
        [ImageSaver saveImage:testImage
                       toFile:testImagePath
                        asPNG:YES
                         error:&error];

        // Read it back
        NSImage *readImage = [ImageReader readImageFromFile:testImagePath];

        // 2. Display image info
        NSLog(@"\n--- 2. Image Information ---");
        if (readImage) {
            [ImageInfo printImageInfo:readImage atPath:testImagePath];
        }

        // 3. Save in different formats
        NSLog(@"\n--- 3. Save in Different Formats ---");

        NSString *pngPath = @"/tmp/test_output.png";
        NSString *jpgPath = @"/tmp/test_output.jpg";
        NSString *tiffPath = @"/tmp/test_output.tiff";

        [ImageSaver saveImage:testImage toFile:pngPath asPNG:YES error:&error];

        // Save JPEG with compression
        [ImageSaver saveImage:testImage
                       toFile:jpgPath
                withProperties:@{NSImageCompressionFactor: @(0.8)}
                         error:&error];

        [ImageSaver saveImage:testImage toFile:tiffPath asPNG:NO error:&error];

        // 4. Read from URL (simulated with file URL)
        NSLog(@"\n--- 4. Read from URL ---");
        NSURL *fileURL = [NSURL fileURLWithPath:testImagePath];
        NSImage *urlImage = [ImageReader readImageFromURL:fileURL];

        // 5. Batch processing
        NSLog(@"\n--- 5. Batch Processing ---");

        NSString *batchDir = @"/tmp/batch_images";
        NSString *outputDir = @"/tmp/batch_output";

        [[NSFileManager defaultManager] createDirectoryAtPath:batchDir
                                 withIntermediateDirectories:YES
                                                  attributes:nil
                                                       error:nil];

        // Copy test image to batch directory
        [[NSFileManager defaultManager] copyItemAtPath:testImagePath
                                                toPath:[batchDir stringByAppendingPathComponent:@"image1.png"]
                                                 error:nil];

        [BatchImageProcessor convertImagesInDirectory:batchDir
                                     toOutputDirectory:outputDir
                                            fileType:NSJPEGFileType
                                                error:&error];

        // Cleanup
        NSArray *filesToClean = @[
            testImagePath, pngPath, jpgPath, tiffPath
        ];

        for (NSString *file in filesToClean) {
            [[NSFileManager defaultManager] removeItemAtPath:file error:nil];
        }

        [[NSFileManager defaultManager] removeItemAtPath:batchDir error:nil];
        [[NSFileManager defaultManager] removeItemAtPath:outputDir error:nil];

        NSLog(@"\nCleanup completed");
        NSLog(@"\n=== Image Read/Save Examples Completed ===");
    }

    return 0;
}

💻 Redimensionnement d'Images objectivec

🟡 intermediate ⭐⭐⭐

Redimensionner images, mettre à l'échelle dimensions spécifiques, maintenir ratio aspect via CoreGraphics

⏱️ 30 min 🏷️ objectivec, macos, image processing, scaling
Prerequisites: Objective-C basics, AppKit framework, CoreGraphics
// macOS Objective-C Image Scaling Examples
// Using CoreGraphics and AppKit frameworks

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <CoreGraphics/CoreGraphics.h>

// MARK: - 1. Basic Image Scaling

@interface ImageScaler : NSObject

+ (NSImage *)scaleImage:(NSImage *)image
                 toSize:(NSSize)newSize;

+ (NSImage *)scaleImage:(NSImage *)image
              toWidth:(CGFloat)newWidth
               height:(CGFloat)newHeight;

+ (NSImage *)scaleImageByFactor:(NSImage *)image
                          factor:(CGFloat)factor;

@end

@implementation ImageScaler

+ (NSImage *)scaleImage:(NSImage *)image
                 toSize:(NSSize)newSize {

    if (!image) {
        NSLog(@"Cannot scale nil image");
        return nil;
    }

    NSSize originalSize = image.size;
    NSLog(@"Scaling from %.0fx%.0f to %.0fx%.0f",
          originalSize.width, originalSize.height, newSize.width, newSize.height);

    // Create new image with scaled size
    NSImage *scaledImage = [[NSImage alloc] initWithSize:newSize];

    [scaledImage lockFocus];
    [image drawInRect:NSMakeRect(0, 0, newSize.width, newSize.height)
             fromRect:NSMakeRect(0, 0, originalSize.width, originalSize.height)
            operation:NSCompositingOperationCopy
             fraction:1.0];
    [scaledImage unlockFocus];

    return scaledImage;
}

+ (NSImage *)scaleImage:(NSImage *)image
              toWidth:(CGFloat)newWidth
               height:(CGFloat)newHeight {

    NSSize newSize = NSMakeSize(newWidth, newHeight);
    return [self scaleImage:image toSize:newSize];
}

+ (NSImage *)scaleImageByFactor:(NSImage *)image
                          factor:(CGFloat)factor {

    NSSize originalSize = image.size;
    NSSize newSize = NSMakeSize(originalSize.width * factor, originalSize.height * factor);

    NSLog(@"Scaling by factor %.2f: %.0fx%.0f -> %.0fx%.0f",
          factor, originalSize.width, originalSize.height, newSize.width, newSize.height);

    return [self scaleImage:image toSize:newSize];
}

@end

// MARK: - 2. Aspect Ratio Preserving Scaling

@interface AspectRatioScaler : NSObject

+ (NSImage *)fitImage:(NSImage *)image
              inSize:(NSSize)containerSize;

+ (NSImage *)fillSize:(NSSize)containerSize
           withImage:(NSImage *)image;

+ (NSImage *)scaleImage:(NSImage *)image
          toFitInWidth:(CGFloat)maxWidth
                 height:(CGFloat)maxHeight;

@end

@implementation AspectRatioScaler

+ (NSImage *)fitImage:(NSImage *)image
              inSize:(NSSize)containerSize {

    NSSize originalSize = image.size;
    CGFloat widthRatio = containerSize.width / originalSize.width;
    CGFloat heightRatio = containerSize.height / originalSize.height;
    CGFloat ratio = MIN(widthRatio, heightRatio);

    NSSize newSize = NSMakeSize(originalSize.width * ratio, originalSize.height * ratio);

    NSLog(@"Fitting %.0fx%.0f into %.0fx%.0f (ratio: %.2f)",
          originalSize.width, originalSize.height,
          containerSize.width, containerSize.height, ratio);

    return [ImageScaler scaleImage:image toSize:newSize];
}

+ (NSImage *)fillSize:(NSSize)containerSize
           withImage:(NSImage *)image {

    NSSize originalSize = image.size;
    CGFloat widthRatio = containerSize.width / originalSize.width;
    CGFloat heightRatio = containerSize.height / originalSize.height;
    CGFloat ratio = MAX(widthRatio, heightRatio);

    NSSize newSize = NSMakeSize(originalSize.width * ratio, originalSize.height * ratio);

    NSLog(@"Filling %.0fx%.0f with %.0fx%.0f (ratio: %.2f)",
          containerSize.width, containerSize.height,
          originalSize.width, originalSize.height, ratio);

    return [ImageScaler scaleImage:image toSize:newSize];
}

+ (NSImage *)scaleImage:(NSImage *)image
          toFitInWidth:(CGFloat)maxWidth
                 height:(CGFloat)maxHeight {

    NSSize containerSize = NSMakeSize(maxWidth, maxHeight);
    return [self fitImage:image inSize:containerSize];
}

@end

// MARK: - 3. High-Quality Scaling with CoreGraphics

@interface HighQualityImageScaler : NSObject

+ (NSImage *)scaleImageHighQuality:(NSImage *)image
                            toSize:(NSSize)newSize;

+ (NSImage *)scaleImageWithInterpolation:(NSImage *)image
                                  toSize:(NSSize)newSize
                           interpolation:(CGInterpolationQuality)quality;

@end

@implementation HighQualityImageScaler

+ (NSImage *)scaleImageHighQuality:(NSImage *)image
                            toSize:(NSSize)newSize {

    return [self scaleImageWithInterpolation:image
                                      toSize:newSize
                               interpolation:kCGInterpolationHigh];
}

+ (NSImage *)scaleImageWithInterpolation:(NSImage *)image
                                  toSize:(NSSize)newSize
                           interpolation:(CGInterpolationQuality)quality {

    if (!image) {
        return nil;
    }

    NSSize originalSize = image.size;

    // Create bitmap context
    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:image.TIFFRepresentation];

    NSInteger pixelsWide = (NSInteger)newSize.width;
    NSInteger pixelsHigh = (NSInteger)newSize.height;

    NSBitmapImageRep *newBitmapRep = [[NSBitmapImageRep alloc]
        initWithBitmapDataPlanes:NULL
                      pixelsWide:pixelsWide
                      pixelsHigh:pixelsHigh
                   bitsPerSample:8
                 samplesPerPixel:4
                        hasAlpha:YES
                        isPlanar:NO
                  colorSpaceName:NSCalibratedRGBColorSpace
                     bytesPerRow:0
                    bitsPerPixel:0];

    // Create graphics context
    NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithBitmapImageRep:newBitmapRep];
    [NSGraphicsContext saveGraphicsState];
    [NSGraphicsContext setCurrentContext:context];

    // Set interpolation quality
    [context setImageInterpolation:quality];

    // Draw image scaled
    [image drawInRect:NSMakeRect(0, 0, newSize.width, newSize.height)
             fromRect:NSMakeRect(0, 0, originalSize.width, originalSize.height)
            operation:NSCompositingOperationCopy
             fraction:1.0];

    [NSGraphicsContext restoreGraphicsState];

    // Create NSImage from bitmap
    NSImage *scaledImage = [[NSImage alloc] initWithSize:newSize];
    [scaledImage addRepresentation:newBitmapRep];

    NSLog(@"High-quality scaling: %.0fx%.0f -> %.0fx%.0f",
          originalSize.width, originalSize.height, newSize.width, newSize.height);

    return scaledImage;
}

@end

// MARK: - 4. Thumbnail Generation

@interface ThumbnailGenerator : NSObject

+ (NSImage *)createThumbnail:(NSImage *)image
                    ofSize:(NSSize)size;

+ (NSImage *)createSquareThumbnail:(NSImage *)image
                         sideLength:(CGFloat)sideLength;

+ (BOOL)generateThumbnailForFile:(NSString *)inputPath
                          toFile:(NSString *)outputPath
                          ofSize:(NSSize)size
                           error:(NSError **)error;

@end

@implementation ThumbnailGenerator

+ (NSImage *)createThumbnail:(NSImage *)image
                    ofSize:(NSSize)size {

    NSLog(@"Creating thumbnail: %.0fx%.0f", size.width, size.height);
    return [AspectRatioScaler fitImage:image inSize:size];
}

+ (NSImage *)createSquareThumbnail:(NSImage *)image
                         sideLength:(CGFloat)sideLength {

    NSSize size = NSMakeSize(sideLength, sideLength);
    NSSize originalSize = image.size;

    // Calculate crop rectangle to center crop
    CGFloat minDimension = MIN(originalSize.width, originalSize.height);
    CGFloat x = (originalSize.width - minDimension) / 2.0;
    CGFloat y = (originalSize.height - minDimension) / 2.0;

    // Crop to square
    NSRect cropRect = NSMakeRect(x, y, minDimension, minDimension);
    NSImage *croppedImage = [[NSImage alloc] initWithSize:cropRect.size];

    [croppedImage lockFocus];
    [image drawInRect:NSMakeRect(0, 0, cropRect.size.width, cropRect.size.height)
             fromRect:cropRect
            operation:NSCompositingOperationCopy
             fraction:1.0];
    [croppedImage unlockFocus];

    // Scale to thumbnail size
    NSImage *thumbnail = [ImageScaler scaleImage:croppedImage toSize:size];

    NSLog(@"Created square thumbnail: %.0fx%.0f", sideLength, sideLength);
    return thumbnail;
}

+ (BOOL)generateThumbnailForFile:(NSString *)inputPath
                          toFile:(NSString *)outputPath
                          ofSize:(NSSize)size
                           error:(NSError **)error {

    // Load image
    NSImage *image = [[NSImage alloc] initWithContentsOfFile:inputPath];

    if (!image) {
        if (error) {
            *error = [NSError errorWithDomain:@"ThumbnailError"
                                         code:1
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to load image"}];
        }
        return NO;
    }

    // Create thumbnail
    NSImage *thumbnail = [self createThumbnail:image ofSize:size];

    if (!thumbnail) {
        if (error) {
            *error = [NSError errorWithDomain:@"ThumbnailError"
                                         code:2
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to create thumbnail"}];
        }
        return NO;
    }

    // Save thumbnail
    NSData *tiffData = thumbnail.TIFFRepresentation;
    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:tiffData];
    NSData *pngData = [bitmapRep representationUsingType:NSPNGFileType properties:@{}];

    BOOL success = [pngData writeToFile:outputPath options:NSDataWritingAtomic error:error];

    if (success) {
        NSLog(@"Saved thumbnail to: %@", outputPath);
    }

    return success;
}

@end

// MARK: - 5. Multi-Scale Image Generation

@interface MultiScaleGenerator : NSObject

+ (NSDictionary<NSString *, NSImage *> *)generateScalesForImage:(NSImage *)image
                                                    sizes:(NSArray<NSValue *> *)sizes;

@end

@implementation MultiScaleGenerator

+ (NSDictionary<NSString *, NSImage *> *)generateScalesForImage:(NSImage *)image
                                                    sizes:(NSArray<NSValue *> *)sizes {

    NSMutableDictionary *scaledImages = [NSMutableDictionary dictionary];

    for (NSValue *sizeValue in sizes) {
        NSSize size;
        [sizeValue getValue:&size];

        NSString *key = [NSString stringWithFormat:@"%.0fx%.0f", size.width, size.height];
        NSImage *scaled = [ImageScaler scaleImage:image toSize:size];

        if (scaled) {
            scaledImages[key] = scaled;
            NSLog(@"Generated scale: %@", key);
        }
    }

    return [scaledImages copy];
}

@end

// MARK: - Main Demonstration

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"=== macOS Objective-C Image Scaling Examples ===\n");

        // Create test image
        NSImage *testImage = [[NSImage alloc] initWithSize:NSMakeSize(400, 300)];
        [testImage lockFocus];

        // Draw gradient background
        NSGradient *gradient = [[NSGradient alloc] initWithColors:@[
            [NSColor colorWithCalibratedRed:0.2 green:0.4 blue:0.8 alpha:1.0],
            [NSColor colorWithCalibratedRed:0.8 green:0.4 blue:0.2 alpha:1.0]
        ]];
        [gradient drawInRect:NSMakeRect(0, 0, 400, 300) angle:45];

        // Draw some shapes
        [[NSColor whiteColor] set];
        [NSBezierPath fillRect:NSMakeRect(50, 50, 100, 100)];
        [[NSColor blackColor] set];
        [NSBezierPath strokeRect:NSMakeRect(200, 100, 150, 100)];

        // Draw text
        NSString *text = @"Scaling Test";
        NSPoint textPoint = NSMakePoint(120, 150);
        NSDictionary *attrs = @{NSFontAttributeName: [NSFont boldSystemFontOfSize:24]};
        [text drawAtPoint:textPoint withAttributes:attrs];

        [testImage unlockFocus];

        // 1. Basic scaling
        NSLog(@"--- 1. Basic Scaling ---");

        NSImage *scaled2x = [ImageScaler scaleImageByFactor:testImage factor:2.0];
        NSImage *scaled05x = [ImageScaler scaleImageByFactor:testImage factor:0.5];

        NSLog(@"Original size: %.0fx%.0f", testImage.size.width, testImage.size.height);
        NSLog(@"2x size: %.0fx%.0f", scaled2x.size.width, scaled2x.size.height);
        NSLog(@"0.5x size: %.0fx%.0f", scaled05x.size.width, scaled05x.size.height);

        // 2. Scale to specific dimensions
        NSLog(@"\n--- 2. Scale to Dimensions ---");

        NSImage *exactSize = [ImageScaler scaleImage:testImage
                                           toWidth:200
                                            height:200];
        NSLog(@"Exact 200x200: %.0fx%.0f", exactSize.size.width, exactSize.size.height);

        // 3. Aspect ratio preserving
        NSLog(@"\n--- 3. Aspect Ratio Preserving ---");

        NSImage *fitted = [AspectRatioScaler fitImage:testImage
                                               inSize:NSMakeSize(150, 150)];
        NSLog(@"Fitted to 150x150: %.0fx%.0f", fitted.size.width, fitted.size.height);

        NSImage *filled = [AspectRatioScaler fillSize:NSMakeSize(500, 200)
                                            withImage:testImage];
        NSLog(@"Filled to 500x200: %.0fx%.0f", filled.size.width, filled.size.height);

        // 4. High-quality scaling
        NSLog(@"\n--- 4. High-Quality Scaling ---");

        NSImage *hqScaled = [HighQualityImageScaler scaleImageHighQuality:testImage
                                                                    toSize:NSMakeSize(800, 600)];
        NSLog(@"High-quality scaled: %.0fx%.0f", hqScaled.size.width, hqScaled.size.height);

        NSImage *lowQuality = [HighQualityImageScaler scaleImageWithInterpolation:testImage
                                                                         toSize:NSMakeSize(800, 600)
                                                                  interpolation:kCGInterpolationNone];
        NSLog(@"Low-quality scaled: %.0fx%.0f", lowQuality.size.width, lowQuality.size.height);

        // 5. Thumbnails
        NSLog(@"\n--- 5. Thumbnails ---");

        NSImage *thumbnail = [ThumbnailGenerator createThumbnail:testImage
                                                          ofSize:NSMakeSize(80, 80)];
        NSLog(@"Thumbnail: %.0fx%.0f", thumbnail.size.width, thumbnail.size.height);

        NSImage *squareThumb = [ThumbnailGenerator createSquareThumbnail:testImage
                                                              sideLength:100];
        NSLog(@"Square thumbnail: %.0fx%.0f", squareThumb.size.width, squareThumb.size.height);

        // Save test images
        NSLog(@"\n--- Saving Test Images ---");

        NSString *basePath = @"/tmp/scale_test";

        NSData *originalTIFF = testImage.TIFFRepresentation;
        NSBitmapImageRep *originalRep = [NSBitmapImageRep imageRepWithData:originalTIFF];
        NSData *originalPNG = [originalRep representationUsingType:NSPNGFileType properties:@{}];
        [originalPNG writeToFile:[basePath stringByAppendingString:@"_original.png"] atomically:YES];

        NSData *thumbTIFF = thumbnail.TIFFRepresentation;
        NSBitmapImageRep *thumbRep = [NSBitmapImageRep imageRepWithData:thumbTIFF];
        NSData *thumbPNG = [thumbRep representationUsingType:NSPNGFileType properties:@{}];
        [thumbPNG writeToFile:[basePath stringByAppendingString:@"_thumb.png"] atomically:YES];

        NSLog(@"Test images saved to /tmp/scale_test_*");

        // Cleanup
        [[NSFileManager defaultManager] removeItemAtPath:[basePath stringByAppendingString:@"_original.png"] error:nil];
        [[NSFileManager defaultManager] removeItemAtPath:[basePath stringByAppendingString:@"_thumb.png"] error:nil];

        NSLog(@"\nCleanup completed");
        NSLog(@"\n=== Image Scaling Examples Completed ===");
    }

    return 0;
}

💻 Conversion Format Image objectivec

🟡 intermediate ⭐⭐⭐

Convertir entre formats images incluant PNG, JPEG, GIF, TIFF BMP avec paramètres qualité

⏱️ 25 min 🏷️ objectivec, macos, image processing, conversion
Prerequisites: Objective-C basics, AppKit framework
// macOS Objective-C Image Format Conversion Examples
// Using AppKit framework

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>

// MARK: - 1. Format Converter

@interface ImageFormatConverter : NSObject

+ (BOOL)convertImage:(NSString *)inputPath
             toFile:(NSString *)outputPath
           fileType:(NSBitmapImageFileType)fileType
              error:(NSError **)error;

+ (BOOL)convertToPNG:(NSString *)inputPath
              toFile:(NSString *)outputPath
               error:(NSError **)error;

+ (BOOL)convertToJPEG:(NSString *)inputPath
               toFile:(NSString *)outputPath
                error:(NSError **)error;

+ (BOOL)convertToGIF:(NSString *)inputPath
              toFile:(NSString *)outputPath
               error:(NSError **)error;

+ (BOOL)convertToTIFF:(NSString *)inputPath
               toFile:(NSString *)outputPath
                error:(NSError **)error;

+ (BOOL)convertToBMP:(NSString *)inputPath
              toFile:(NSString *)outputPath
               error:(NSError **)error;

@end

@implementation ImageFormatConverter

+ (BOOL)convertImage:(NSString *)inputPath
             toFile:(NSString *)outputPath
           fileType:(NSBitmapImageFileType)fileType
              error:(NSError **)error {

    // Load input image
    NSImage *image = [[NSImage alloc] initWithContentsOfFile:inputPath];

    if (!image) {
        if (error) {
            *error = [NSError errorWithDomain:@"ConversionError"
                                         code:1
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to load input image"}];
        }
        return NO;
    }

    // Get bitmap representation
    NSData *tiffData = image.TIFFRepresentation;
    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:tiffData];

    if (!bitmapRep) {
        if (error) {
            *error = [NSError errorWithDomain:@"ConversionError"
                                         code:2
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to get bitmap representation"}];
        }
        return NO;
    }

    // Convert to target format
    NSData *outputData = [bitmapRep representationUsingType:fileType properties:@{}];

    if (!outputData) {
        if (error) {
            *error = [NSError errorWithDomain:@"ConversionError"
                                         code:3
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to convert image format"}];
        }
        return NO;
    }

    // Save to file
    BOOL success = [outputData writeToFile:outputPath options:NSDataWritingAtomic error:error];

    if (success) {
        NSLog(@"Converted %@ to %@", [self formatNameForType:fileType], outputPath);
    }

    return success;
}

+ (BOOL)convertToPNG:(NSString *)inputPath
              toFile:(NSString *)outputPath
               error:(NSError **)error {

    return [self convertImage:inputPath toFile:outputPath fileType:NSPNGFileType error:error];
}

+ (BOOL)convertToJPEG:(NSString *)inputPath
               toFile:(NSString *)outputPath
                error:(NSError **)error {

    return [self convertImage:inputPath toFile:outputPath fileType:NSJPEGFileType error:error];
}

+ (BOOL)convertToGIF:(NSString *)inputPath
              toFile:(NSString *)outputPath
               error:(NSError **)error {

    return [self convertImage:inputPath toFile:outputPath fileType:NSGIFFileType error:error];
}

+ (BOOL)convertToTIFF:(NSString *)inputPath
               toFile:(NSString *)outputPath
                error:(NSError **)error {

    return [self convertImage:inputPath toFile:outputPath fileType:NSTIFFFileType error:error];
}

+ (BOOL)convertToBMP:(NSString *)inputPath
              toFile:(NSString *)outputPath
               error:(NSError **)error {

    return [self convertImage:inputPath toFile:outputPath fileType:NSBMPFileType error:error];
}

+ (NSString *)formatNameForType:(NSBitmapImageFileType)fileType {
    switch (fileType) {
        case NSPNGFileType:
            return @"PNG";
        case NSJPEGFileType:
            return @"JPEG";
        case NSGIFFileType:
            return @"GIF";
        case NSTIFFFileType:
            return @"TIFF";
        case NSBMPFileType:
            return @"BMP";
        default:
            return @"Unknown";
    }
}

@end

// MARK: - 2. JPEG Quality Settings

@interface JPEGConverter : NSObject

+ (BOOL)convertToJPEG:(NSString *)inputPath
               toFile:(NSString *)outputPath
              quality:(CGFloat)quality
                error:(NSError **)error;

+ (NSArray<NSData *> *)createJPEGProgressive:(NSString *)inputPath
                               qualityLevels:(NSArray<NSNumber *> *)qualities;

@end

@implementation JPEGConverter

+ (BOOL)convertToJPEG:(NSString *)inputPath
               toFile:(NSString *)outputPath
              quality:(CGFloat)quality
                error:(NSError **)error {

    // Load image
    NSImage *image = [[NSImage alloc] initWithContentsOfFile:inputPath];

    if (!image) {
        if (error) {
            *error = [NSError errorWithDomain:@"JPEGError"
                                         code:1
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to load image"}];
        }
        return NO;
    }

    // Get bitmap representation
    NSData *tiffData = image.TIFFRepresentation;
    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:tiffData];

    // Set compression quality
    NSDictionary *properties = @{
        NSImageCompressionFactor: @(quality)
    };

    // Convert to JPEG
    NSData *jpegData = [bitmapRep representationUsingType:NSJPEGFileType properties:properties];

    if (!jpegData) {
        if (error) {
            *error = [NSError errorWithDomain:@"JPEGError"
                                         code:2
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to create JPEG"}];
        }
        return NO;
    }

    // Save
    BOOL success = [jpegData writeToFile:outputPath options:NSDataWritingAtomic error:error];

    if (success) {
        NSLog(@"Created JPEG with quality %.2f: %@", quality, outputPath);
        NSLog(@"File size: %lu bytes", (unsigned long)jpegData.length);
    }

    return success;
}

+ (NSArray<NSData *> *)createJPEGProgressive:(NSString *)inputPath
                               qualityLevels:(NSArray<NSNumber *> *)qualities {

    NSImage *image = [[NSImage alloc] initWithContentsOfFile:inputPath];
    NSData *tiffData = image.TIFFRepresentation;
    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:tiffData];

    NSMutableArray *jpegArray = [NSMutableArray array];

    for (NSNumber *qualityNum in qualities) {
        CGFloat quality = [qualityNum floatValue];
        NSDictionary *properties = @{NSImageCompressionFactor: @(quality)};

        NSData *jpegData = [bitmapRep representationUsingType:NSJPEGFileType properties:properties];

        if (jpegData) {
            [jpegArray addObject:jpegData];
            NSLog(@"JPEG quality %.2f: %lu bytes", quality, (unsigned long)jpegData.length);
        }
    }

    return [jpegArray copy];
}

@end

// MARK: - 3. PNG Compression Settings

@interface PNGConverter : NSObject

+ (BOOL)convertToPNG:(NSString *)inputPath
             toFile:(NSString *)outputPath
           interlaced:(BOOL)interlaced
              error:(NSError **)error;

@end

@implementation PNGConverter

+ (BOOL)convertToPNG:(NSString *)inputPath
             toFile:(NSString *)outputPath
           interlaced:(BOOL)interlaced
              error:(NSError **)error {

    NSImage *image = [[NSImage alloc] initWithContentsOfFile:inputPath];

    if (!image) {
        if (error) {
            *error = [NSError errorWithDomain:@"PNGError"
                                         code:1
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to load image"}];
        }
        return NO;
    }

    NSData *tiffData = image.TIFFRepresentation;
    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:tiffData];

    // PNG doesn't use compression factor, but we can set other properties
    NSDictionary *properties = @{};

    NSData *pngData = [bitmapRep representationUsingType:NSPNGFileType properties:properties];

    if (!pngData) {
        if (error) {
            *error = [NSError errorWithDomain:@"PNGError"
                                         code:2
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to create PNG"}];
        }
        return NO;
    }

    BOOL success = [pngData writeToFile:outputPath options:NSDataWritingAtomic error:error];

    if (success) {
        NSLog(@"Created PNG: %@ (%lu bytes)", outputPath, (unsigned long)pngData.length);
    }

    return success;
}

@end

// MARK: - 4. Batch Format Conversion

@interface BatchFormatConverter : NSObject

+ (NSInteger)convertDirectory:(NSString *)inputDirectory
              toOutputDirectory:(NSString *)outputDirectory
                      fileType:(NSBitmapImageFileType)fileType
                          error:(NSError **)error;

+ (BOOL)convertMultipleFormats:(NSString *)inputPath
                   outputFiles:(NSDictionary<NSString *, NSNumber *> *)outputPaths
                        error:(NSError **)error;

@end

@implementation BatchFormatConverter

+ (NSInteger)convertDirectory:(NSString *)inputDirectory
              toOutputDirectory:(NSString *)outputDirectory
                      fileType:(NSBitmapImageFileType)fileType
                          error:(NSError **)error {

    NSFileManager *fileManager = [NSFileManager defaultManager];

    // Create output directory
    if (![fileManager fileExistsAtPath:outputDirectory]) {
        [fileManager createDirectoryAtPath:outputDirectory
               withIntermediateDirectories:YES
                                attributes:nil
                                     error:error];
        if (*error) {
            return 0;
        }
    }

    // Get all files
    NSArray *files = [fileManager contentsOfDirectoryAtPath:inputDirectory error:error];

    if (*error) {
        return 0;
    }

    NSArray *imageExtensions = @[@"png", @"jpg", @"jpeg", @"gif", @"bmp", @"tiff"];
    NSInteger successCount = 0;

    for (NSString *file in files) {
        NSString *extension = [file pathExtension];

        if ([imageExtensions containsObject:extension.lowercaseString]) {
            NSString *inputPath = [inputDirectory stringByAppendingPathComponent:file];

            // Create output filename with new extension
            NSString *newExtension = [self extensionForFileType:fileType];
            NSString *outputFile = [[file stringByDeletingPathExtension]
                                    stringByAppendingPathExtension:newExtension];
            NSString *outputPath = [outputDirectory stringByAppendingPathComponent:outputFile];

            NSError *localError = nil;
            if ([ImageFormatConverter convertImage:inputPath
                                            toFile:outputPath
                                          fileType:fileType
                                             error:&localError]) {
                successCount++;
            } else {
                NSLog(@"Failed to convert %@: %@", file, localError.localizedDescription);
            }
        }
    }

    NSLog(@"Batch conversion completed: %ld files", (long)successCount);
    return successCount;
}

+ (BOOL)convertMultipleFormats:(NSString *)inputPath
                   outputFiles:(NSDictionary<NSString *, NSNumber *> *)outputPaths
                        error:(NSError **)error {

    NSImage *image = [[NSImage alloc] initWithContentsOfFile:inputPath];

    if (!image) {
        if (error) {
            *error = [NSError errorWithDomain:@"BatchConversionError"
                                         code:1
                                     userInfo:@{NSLocalizedDescriptionKey: @"Failed to load image"}];
        }
        return NO;
    }

    NSData *tiffData = image.TIFFRepresentation;
    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:tiffData];

    NSInteger successCount = 0;

    for (NSString *outputPath in outputPaths) {
        NSNumber *fileTypeNum = outputPaths[outputPath];
        NSBitmapImageFileType fileType = (NSBitmapImageFileType)[fileTypeNum integerValue];

        NSData *outputData = [bitmapRep representationUsingType:fileType properties:@{}];

        if ([outputData writeToFile:outputPath options:NSDataWritingAtomic error:error]) {
            successCount++;
            NSLog(@"Created: %@", outputPath);
        }
    }

    return successCount > 0;
}

+ (NSString *)extensionForFileType:(NSBitmapImageFileType)fileType {
    switch (fileType) {
        case NSPNGFileType:
            return @"png";
        case NSJPEGFileType:
            return @"jpg";
        case NSGIFFileType:
            return @"gif";
        case NSTIFFFileType:
            return @"tiff";
        case NSBMPFileType:
            return @"bmp";
        default:
            return @"img";
    }
}

@end

// MARK: - 5. Format Detection and Info

@interface FormatDetector : NSObject

+ (NSString *)detectImageFormat:(NSString *)filePath;
+ (NSDictionary *)getImageFormatInfo:(NSData *)imageData;

@end

@implementation FormatDetector

+ (NSString *)detectImageFormat:(NSString *)filePath {

    NSData *data = [NSData dataWithContentsOfFile:filePath];
    if (!data || data.length < 8) {
        return @"unknown";
    }

    // Check magic bytes
    const uint8_t *bytes = data.bytes;

    // PNG: 89 50 4E 47 0D 0A 1A 0A
    if (data.length >= 8 && bytes[0] == 0x89 && bytes[1] == 0x50 &&
        bytes[2] == 0x4E && bytes[3] == 0x47 && bytes[4] == 0x0D &&
        bytes[5] == 0x0A && bytes[6] == 0x1A && bytes[7] == 0x0A) {
        return @"png";
    }

    // JPEG: FF D8 FF
    if (data.length >= 3 && bytes[0] == 0xFF && bytes[1] == 0xD8 && bytes[2] == 0xFF) {
        return @"jpeg";
    }

    // GIF: GIF87a or GIF89a
    if (data.length >= 6 && bytes[0] == 0x47 && bytes[1] == 0x49 && bytes[2] == 0x46 &&
        bytes[3] == 0x38 && (bytes[4] == 0x37 || bytes[4] == 0x39) && bytes[5] == 0x61) {
        return @"gif";
    }

    // BMP: BM
    if (data.length >= 2 && bytes[0] == 0x42 && bytes[1] == 0x4D) {
        return @"bmp";
    }

    // TIFF: II (little-endian) or MM (big-endian)
    if (data.length >= 4) {
        if ((bytes[0] == 0x49 && bytes[1] == 0x49 && bytes[2] == 0x2A && bytes[3] == 0x00) ||
            (bytes[0] == 0x4D && bytes[1] == 0x4D && bytes[2] == 0x00 && bytes[3] == 0x2A)) {
            return @"tiff";
        }
    }

    return @"unknown";
}

+ (NSDictionary *)getImageFormatInfo:(NSData *)imageData {

    NSImage *image = [[NSImage alloc] initWithData:imageData];

    if (!image) {
        return nil;
    }

    NSBitmapImageRep *bitmapRep = [NSBitmapImageRep imageRepWithData:imageData];

    NSMutableDictionary *info = [NSMutableDictionary dictionary];
    info[@"size"] = NSStringFromSize(image.size);
    info[@"pixelsWide"] = @(bitmapRep.pixelsWide);
    info[@"pixelsHigh"] = @(bitmapRep.pixelsHigh);
    info[@"bitsPerPixel"] = @(bitmapRep.bitsPerPixel);
    info[@"colorSpace"] = bitmapRep.colorSpaceName;
    info[@"hasAlpha"] = @(bitmapRep.hasAlpha);
    info[@"dataSize"] = @(imageData.length);

    return [info copy];
}

@end

// MARK: - Main Demonstration

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"=== macOS Objective-C Image Format Conversion Examples ===\n");

        // Create test image
        NSImage *testImage = [[NSImage alloc] initWithSize:NSMakeSize(300, 200)];
        [testImage lockFocus];

        NSGradient *gradient = [[NSGradient alloc] initWithStartingColor:[NSColor blueColor]
                                                             endingColor:[NSColor greenColor]];
        [gradient drawInRect:NSMakeRect(0, 0, 300, 200) angle:0];

        [[NSColor whiteColor] set];
        NSString *text = @"Format Test";
        [text drawAtPoint:NSMakePoint(100, 90) withAttributes:@{NSFontAttributeName: [NSFont boldSystemFontOfSize:20]}];

        [testImage unlockFocus];

        // Save test image as PNG
        NSString *testPNG = @"/tmp/test_convert.png";
        NSData *tiffData = testImage.TIFFRepresentation;
        NSBitmapImageRep *testRep = [NSBitmapImageRep imageRepWithData:tiffData];
        NSData *pngData = [testRep representationUsingType:NSPNGFileType properties:@{}];
        [pngData writeToFile:testPNG atomically:YES];

        // 1. Convert to different formats
        NSLog(@"--- 1. Convert to Different Formats ---");

        NSError *error = nil;

        [ImageFormatConverter convertToJPEG:testPNG
                                      toFile:@"/tmp/test_output.jpg"
                                       error:&error];

        [ImageFormatConverter convertToGIF:testPNG
                                     toFile:@"/tmp/test_output.gif"
                                      error:&error];

        [ImageFormatConverter convertToTIFF:testPNG
                                       toFile:@"/tmp/test_output.tiff"
                                        error:&error];

        [ImageFormatConverter convertToBMP:testPNG
                                     toFile:@"/tmp/test_output.bmp"
                                      error:&error];

        // 2. JPEG quality settings
        NSLog(@"\n--- 2. JPEG Quality Settings ---");

        [JPEGConverter convertToJPEG:testPNG
                               toFile:@"/tmp/test_high.jpg"
                              quality:1.0
                                error:&error];

        [JPEGConverter convertToJPEG:testPNG
                               toFile:@"/tmp/test_low.jpg"
                              quality:0.3
                                error:&error];

        // 3. Progressive JPEG
        NSLog(@"\n--- 3. Progressive JPEG ---");

        NSArray *qualities = @[@(1.0), @(0.8), @(0.5), @(0.3)];
        [JPEGConverter createJPEGProgressive:testPNG qualityLevels:qualities];

        // 4. Format detection
        NSLog(@"\n--- 4. Format Detection ---");

        NSString *detectedFormat = [FormatDetector detectImageFormat:testPNG];
        NSLog(@"Detected format: %@", detectedFormat);

        NSDictionary *formatInfo = [FormatDetector getImageFormatInfo:pngData];
        NSLog(@"Format info: %@", formatInfo);

        // 5. Batch conversion
        NSLog(@"\n--- 5. Batch Conversion ---");

        NSString *inputDir = @"/tmp/batch_convert_input";
        NSString *outputDir = @"/tmp/batch_convert_output";

        [[NSFileManager defaultManager] createDirectoryAtPath:inputDir
                                 withIntermediateDirectories:YES
                                                  attributes:nil
                                                       error:nil];

        // Copy test image to input directory
        [[NSFileManager defaultManager] copyItemAtPath:testPNG
                                                toPath:[inputDir stringByAppendingPathComponent:@"image.png"]
                                                 error:nil];

        [BatchFormatConverter convertDirectory:inputDir
                           toOutputDirectory:outputDir
                                   fileType:NSJPEGFileType
                                       error:&error];

        // Cleanup
        NSArray *filesToClean = @[
            testPNG,
            @"/tmp/test_output.jpg",
            @"/tmp/test_output.gif",
            @"/tmp/test_output.tiff",
            @"/tmp/test_output.bmp",
            @"/tmp/test_high.jpg",
            @"/tmp/test_low.jpg"
        ];

        for (NSString *file in filesToClean) {
            [[NSFileManager defaultManager] removeItemAtPath:file error:nil];
        }

        [[NSFileManager defaultManager] removeItemAtPath:inputDir error:nil];
        [[NSFileManager defaultManager] removeItemAtPath:outputDir error:nil];

        NSLog(@"\nCleanup completed");
        NSLog(@"\n=== Image Format Conversion Examples Completed ===");
    }

    return 0;
}