// 嵌入信息
- (UIImage *)embedMessage:(NSString *)message inImage:(UIImage *)image {
// 將圖片轉(zhuǎn)換為位圖數(shù)據(jù)
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSUInteger bytesPerPixel = 4; // 每個(gè)像素占 4 個(gè)字節(jié)(RGBA)
NSUInteger bitsPerComponent = 8; // 每個(gè)顏色分量占 8 位
NSUInteger bytesPerRow = bytesPerPixel * width; // 每行的字節(jié)數(shù)
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);
// 將消息轉(zhuǎn)換為二進(jìn)制數(shù)據(jù),并在末尾添加終止符 '\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 {
// 將圖片轉(zhuǎn)換為位圖數(shù)據(jù)
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSUInteger bytesPerPixel = 4; // 每個(gè)像素占 4 個(gè)字節(jié)(RGBA)
NSUInteger bitsPerComponent = 8; // 每個(gè)顏色分量占 8 位
NSUInteger bytesPerRow = bytesPerPixel * width; // 每行的字節(jié)數(shù)
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') { // 遇到終止符,結(jié)束提取
endOfMessage = YES;
break;
}
byte = 0;
bitIndex = 0;
}
}
}
}
// 轉(zhuǎn)換為字符串
NSString *message = [[NSString alloc] initWithData:messageData encoding:NSUTF8StringEncoding];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
free(rawData);
return message;
}
-(void)saveWithImage:(UIImage *)image{
// 將 UIImage 轉(zhuǎn)換為 PNG 數(shù)據(jù)
NSData *pngData = UIImagePNGRepresentation(image);
// 保存 PNG 數(shù)據(jù)到相冊(cè)
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetCreationRequest creationRequestForAssetFromImage:[UIImage imageWithData:pngData]];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (success) {
NSLog(@"保存成功");
} else {
NSLog(@"保存失敗: %@", error.localizedDescription);
}
}];
}
iOS-盲水印、數(shù)字水印
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- 在使用知乎,微博的時(shí)候,我們經(jīng)??梢钥吹阶约荷蟼鞯膱D片被加上了文字水印,在實(shí)際的應(yīng)用開(kāi)發(fā)過(guò)程中,很多客戶端都需要開(kāi)...
- 前言 在前面博文講解位平面分解的時(shí)候,我們就提到過(guò)可以通過(guò)位平面分解的方式給圖像添加水印。而數(shù)值水印是圖片版權(quán)用到...
- Date: 2019.3.24 前言 ? ? 數(shù)字水印技術(shù)一般用于版權(quán)認(rèn)證。在實(shí)際使用中,嵌入水印的魯棒性就顯...
- 最近要實(shí)現(xiàn)一個(gè)手寫簽名功能,要求是,在一定區(qū)域繪制文字簽名,簽名完成后,添加新的水印,并且將圖片僅保留簽字區(qū)域剪切...
- 散列函數(shù)是一種公開(kāi)的數(shù)學(xué)函數(shù)。散列函數(shù)運(yùn)算的輸入信息也可叫作報(bào)文。散列函數(shù)運(yùn)算后所得到的結(jié)果叫作散列碼或者叫作消息...