iOS-盲水印、数字水印

// 嵌入信息
- (UIImage *)embedMessage:(NSString *)message inImage:(UIImage *)image {
    // 将图片转换为位图数据
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    NSUInteger bytesPerPixel = 4; // 每个像素占 4 个字节(RGBA)
    NSUInteger bitsPerComponent = 8; // 每个颜色分量占 8 位
    NSUInteger bytesPerRow = bytesPerPixel * width; // 每行的字节数
    unsigned char *rawData = (unsigned char *)calloc(height * width * bytesPerPixel, sizeof(unsigned char));
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);


    // 将消息转换为二进制数据,并在末尾添加终止符 '\0'
    NSString *messageWithTerminator = [message stringByAppendingString:@"\0"];
    NSData *messageData = [messageWithTerminator dataUsingEncoding:NSUTF8StringEncoding];
    const char *messageBytes = [messageData bytes];
    NSUInteger messageLength = [messageData length];


    // 使用 LSB 嵌入消息
    NSUInteger byteIndex = 0;
    NSUInteger bitIndex = 0;
    for (NSUInteger y = 0; y < height; y++) {
        for (NSUInteger x = 0; x < width; x++) {
            NSUInteger pixelIndex = (width * y + x) * bytesPerPixel;
            for (NSUInteger i = 0; i < 3; i++) { // 修改 RGB 通道的最低有效位
                if (byteIndex < messageLength) {
                    unsigned char bit = (messageBytes[byteIndex] >> bitIndex) & 1;
                    rawData[pixelIndex + i] = (rawData[pixelIndex + i] & 0xFE) | bit;
                    bitIndex++;
                    if (bitIndex == 8) {
                        byteIndex++;
                        bitIndex = 0;
                    }
                }
            }
        }
    }


    // 生成新的图片
    CGImageRef newImageRef = CGBitmapContextCreateImage(context);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(newImageRef);
    free(rawData);


    return newImage;
}
// 提取
- (NSString *)extractMessageFromImage:(UIImage *)image {
    // 将图片转换为位图数据
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    NSUInteger bytesPerPixel = 4; // 每个像素占 4 个字节(RGBA)
    NSUInteger bitsPerComponent = 8; // 每个颜色分量占 8 位
    NSUInteger bytesPerRow = bytesPerPixel * width; // 每行的字节数
    unsigned char *rawData = (unsigned char *)calloc(height * width * bytesPerPixel, sizeof(unsigned char));
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);


    // 从 LSB 中提取消息
    NSMutableData *messageData = [NSMutableData data];
    unsigned char byte = 0;
    NSUInteger bitIndex = 0;
    BOOL endOfMessage = NO;


    for (NSUInteger y = 0; y < height && !endOfMessage; y++) {
        for (NSUInteger x = 0; x < width && !endOfMessage; x++) {
            NSUInteger pixelIndex = (width * y + x) * bytesPerPixel;
            for (NSUInteger i = 0; i < 3 && !endOfMessage; i++) { // 读取 RGB 通道的最低有效位
                unsigned char bit = rawData[pixelIndex + i] & 1;
                byte |= (bit << bitIndex);
                bitIndex++;
                if (bitIndex == 8) {
                    [messageData appendBytes:&byte length:1];
                    if (byte == '\0') { // 遇到终止符,结束提取
                        endOfMessage = YES;
                        break;
                    }
                    byte = 0;
                    bitIndex = 0;
                }
            }
        }
    }


    // 转换为字符串
    NSString *message = [[NSString alloc] initWithData:messageData encoding:NSUTF8StringEncoding];
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    free(rawData);


    return message;
}

-(void)saveWithImage:(UIImage *)image{
    // 将 UIImage 转换为 PNG 数据
    NSData *pngData = UIImagePNGRepresentation(image);


    // 保存 PNG 数据到相册
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        [PHAssetCreationRequest creationRequestForAssetFromImage:[UIImage imageWithData:pngData]];
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        if (success) {
            NSLog(@"保存成功");
        } else {
            NSLog(@"保存失败: %@", error.localizedDescription);
        }
    }];
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容