KMPDFSignatureImageView.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. //
  2. // KMPDFSignatureImageView.m
  3. // PDF Reader
  4. //
  5. // Created by 丁林圭 on 2018/6/8.
  6. // Copyright © 2018年 Kdan Mobile. All rights reserved.
  7. //
  8. #import "KMPDFSignatureImageView.h"
  9. #import <Quartz/Quartz.h>
  10. #import "KMImageAccessoryController.h"
  11. #import "NSButton+TitleColor.h"
  12. #define KMSignatureMaxWidth 400
  13. #define KMSignatureMaxHeight 300
  14. @interface KMPDFSignatureImageView()
  15. @property (nonatomic, retain) NSImage * picImage;
  16. @property (nonatomic) IBOutlet NSView *pictureView;
  17. @property (nonatomic) IBOutlet NSTextField *emptyTipLbl;
  18. @property (nonatomic) IBOutlet NSButton *dragButton;
  19. @property (nonatomic) IBOutlet NSImageView *emptyImg;
  20. @property (nonatomic, copy) NSTrackingArea *trackingArea;
  21. @property (nonatomic, strong) NSURL *imageURL;
  22. @end
  23. @implementation KMPDFSignatureImageView
  24. - (void)dealloc {
  25. [self removeTrackingArea:self.trackingArea];
  26. }
  27. - (id)initWithFrame:(NSRect)frameRect
  28. {
  29. if (self = [super initWithFrame:frameRect])
  30. {
  31. self.wantsLayer = YES;
  32. self.layer.borderWidth = 1.0;
  33. self.layer.borderColor = [NSColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.05].CGColor;
  34. self.layer.backgroundColor = [NSColor colorWithRed:1 green:1 blue:1 alpha:0.9].CGColor;;
  35. [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
  36. }
  37. return self;
  38. }
  39. - (void)awakeFromNib
  40. {
  41. [super awakeFromNib];
  42. self.emptyTipLbl.stringValue = NSLocalizedString(@"Select image file", nil);
  43. self.emptyTipLbl.textColor = [NSColor labelColor];
  44. self.dragButton.wantsLayer = YES;
  45. [self.dragButton setTitleColor:[NSColor labelColor]];
  46. self.pictureView.wantsLayer = YES;
  47. self.emptyImg.image = [NSImage imageNamed:@"signPicture_nor"];
  48. self.trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
  49. options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways
  50. owner:self
  51. userInfo:nil];
  52. [self addTrackingArea:self.trackingArea];
  53. }
  54. - (NSArray *)supportedImageTypes
  55. {
  56. return [NSArray arrayWithObjects:@"jpg",@"cur",@"bmp",@"jpeg",@"gif",@"png",@"tiff",@"tif",@"ico",@"icns",@"tga",@"psd",@"eps",@"hdr",@"jp2",@"jpc",@"pict",@"sgi",@"pdf", nil];
  57. }
  58. - (void)drawRect:(NSRect)dirtyRect
  59. {
  60. [super drawRect:dirtyRect];
  61. if (self.pictureView) {
  62. CGRect rect = NSZeroRect;
  63. CIImage *imageCIImage = [CIImage imageWithData:self.picImage.TIFFRepresentation];
  64. NSSize size = [imageCIImage extent].size;
  65. CGFloat scale = MIN((dirtyRect.size.width - 30)/size.width, (dirtyRect.size.height - 30)/size.height);
  66. if (scale > 1) {
  67. rect = CGRectMake(0, 0, size.width, size.height);
  68. } else {
  69. rect = CGRectMake(0, 0, size.width * scale, size.height *scale);
  70. }
  71. [self.picImage drawInRect:CGRectMake((dirtyRect.size.width - rect.size.width)/2,
  72. (dirtyRect.size.height - rect.size.height)/2,
  73. rect.size.width,rect.size.height)
  74. fromRect:NSZeroRect
  75. operation:NSCompositingOperationSourceOver
  76. fraction:1.0];
  77. }
  78. }
  79. - (void)setClearBackground:(BOOL)clearBackground {
  80. _clearBackground = clearBackground;
  81. if (self.imageURL && self.imageURL.path.length > 0) {
  82. [self loadImageViewPath:self.imageURL isRemoveBGColor:self.clearBackground];
  83. }
  84. }
  85. #pragma mark Public
  86. - (void)clearImage
  87. {
  88. self.picImage = nil;
  89. self.imageURL = nil;
  90. self.pictureView.hidden = self.emptyTipLbl.hidden = NO;
  91. [self setNeedsDisplay:YES];
  92. if (self.changeSignatureImageCallback) {
  93. self.changeSignatureImageCallback(YES);
  94. }
  95. }
  96. - (void)reSelectImage {
  97. [self buttonItemClick_SelectPhoto:nil];
  98. }
  99. - (NSImage *)signatureImage
  100. {
  101. CGRect rect = CGRectZero;
  102. if (!self.picImage) {
  103. return nil;
  104. } else {
  105. CIImage *imageCIImage = [CIImage imageWithData:self.picImage.TIFFRepresentation];
  106. NSSize size = [imageCIImage extent].size;
  107. CGFloat scale = MIN(KMSignatureMaxWidth/size.width, KMSignatureMaxHeight/size.height);
  108. if (scale > 1) {
  109. rect = CGRectMake(0, 0, size.width, size.height);
  110. } else {
  111. rect = CGRectMake(0, 0, size.width * scale, size.height *scale);
  112. }
  113. }
  114. NSImage *image = [[NSImage alloc] initWithSize:rect.size];
  115. [image lockFocus];
  116. [self.picImage drawInRect:rect
  117. fromRect:NSZeroRect
  118. operation:NSCompositingOperationSourceOver
  119. fraction:1.0];
  120. [image unlockFocus];
  121. return image;
  122. }
  123. - (void)loadImageViewPath:(NSURL *)url isRemoveBGColor:(BOOL)isRemove
  124. {
  125. self.imageURL = url;
  126. NSString * filePath = url.path;
  127. if ([filePath.pathExtension.lowercaseString isEqualToString:@"pdf"]) {
  128. PDFDocument *pdf = [[PDFDocument alloc] initWithURL:url];
  129. if (pdf.isEncrypted) {
  130. return;
  131. }
  132. }
  133. NSImage *image = [[NSImage alloc] initWithContentsOfFile:filePath];
  134. if (isRemove) {
  135. NSData *imageData = [image TIFFRepresentation];
  136. CGImageRef imageRef;
  137. if (imageData) {
  138. CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageData, NULL);
  139. imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
  140. }
  141. const int imageWidth = image.size.width;
  142. const int imageHeight = image.size.height;
  143. size_t bytesPerRow = imageWidth * 4;
  144. uint32_t* rgbImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight);
  145. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  146. CGContextRef context = CGBitmapContextCreate(rgbImageBuf,
  147. imageWidth,
  148. imageHeight,
  149. 8,
  150. bytesPerRow,
  151. colorSpace,
  152. kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
  153. CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), imageRef);
  154. int pixelNum = imageWidth * imageHeight;
  155. uint32_t* pCurPtr = rgbImageBuf;
  156. for (int i = 0; i < pixelNum; i++, pCurPtr++) {
  157. uint8_t* ptr = (uint8_t*)pCurPtr;
  158. if (ptr[1] > 240 && ptr[2] > 240 && ptr[3] > 240) {
  159. ptr[0] = 0;
  160. }
  161. }
  162. CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight, nil);
  163. imageRef = CGImageCreate(imageWidth,
  164. imageHeight,
  165. 8,
  166. 32,
  167. bytesPerRow,
  168. colorSpace,
  169. kCGImageAlphaLast |kCGBitmapByteOrder32Little,
  170. dataProvider,
  171. NULL,
  172. true,
  173. kCGRenderingIntentDefault);
  174. CGDataProviderRelease(dataProvider);
  175. NSImage *newImage = nil;
  176. if (imageRef) {
  177. NSRect imageRect = NSMakeRect(0.0, 0.0, 0.0, 0.0);
  178. CGContextRef imageContext = nil;
  179. // Get the image dimensions.
  180. imageRect.size.height = CGImageGetHeight(imageRef);
  181. imageRect.size.width = CGImageGetWidth(imageRef);
  182. // Create a new image to receive the Quartz image data.
  183. newImage = [[NSImage alloc] initWithSize:imageRect.size];
  184. [newImage lockFocus];
  185. // Get the Quartz context and draw.
  186. imageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
  187. CGContextDrawImage(imageContext, *(CGRect*)&imageRect, imageRef);
  188. [newImage unlockFocus];
  189. CGImageRelease(imageRef);
  190. }
  191. if (newImage) {
  192. image = newImage;
  193. }
  194. }
  195. if (image) {
  196. self.picImage = image;
  197. self.pictureView.hidden = self.emptyTipLbl.hidden = YES;
  198. [self setNeedsDisplay:YES];
  199. }
  200. }
  201. - (CAGradientLayer *)setGradualChanging {
  202. CAGradientLayer *gradientLayer = [CAGradientLayer layer];
  203. gradientLayer.frame = _dragButton.bounds;
  204. gradientLayer.colors = @[(__bridge id)[NSColor lightGrayColor].CGColor,(__bridge id)[NSColor whiteColor].CGColor];
  205. gradientLayer.startPoint = CGPointMake(0, 0);
  206. gradientLayer.endPoint = CGPointMake(1, 1);
  207. gradientLayer.locations = @[@0,@1];
  208. return gradientLayer;
  209. }
  210. - (BOOL)isDamageImage:(NSImage *)image imagePath:(NSString *)path {
  211. NSString *addImageAnnotation = [[[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier] stringByAppendingPathComponent:@"addImageAnnotation"];
  212. if (![[NSFileManager defaultManager] fileExistsAtPath:addImageAnnotation]) {
  213. [[NSFileManager defaultManager] createDirectoryAtPath:addImageAnnotation withIntermediateDirectories:NO attributes:nil error:nil];
  214. }
  215. NSData *data = [image TIFFRepresentation];
  216. NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:data];
  217. [imageRep setSize:[image size]];
  218. NSData *imageData = nil;
  219. if ([path.lowercaseString isEqualToString:@"png"]) {
  220. imageData = [imageRep representationUsingType:NSBitmapImageFileTypePNG properties:@{}];
  221. } else {
  222. imageData = [imageRep representationUsingType:NSJPEGFileType properties:@{}];
  223. }
  224. NSString *rPath = [addImageAnnotation stringByAppendingPathComponent:[[self tagString] stringByAppendingPathExtension:@"png"]];
  225. if (![imageData writeToFile:rPath atomically:YES]) {
  226. return YES;
  227. } else {
  228. return NO;
  229. }
  230. }
  231. - (NSString *)tagString {
  232. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  233. dateFormatter.dateFormat = @"yyMMddHHmmss";
  234. return [NSString stringWithFormat:@"%@%04d", [dateFormatter stringFromDate:[NSDate date]], rand()%10000];
  235. }
  236. #pragma mark - Button Action
  237. - (IBAction)buttonItemClick_SelectPhoto:(id)sender
  238. {
  239. NSOpenPanel *openPanel = [NSOpenPanel openPanel];
  240. [openPanel setAllowedFileTypes:[self supportedImageTypes]];
  241. [openPanel setAllowedFileTypes:[KMImageAccessoryController supportedImageTypes]];
  242. if ([openPanel respondsToSelector:@selector(setAccessoryViewDisclosed:)]) {
  243. [openPanel setAccessoryViewDisclosed:YES];
  244. }
  245. [openPanel setAllowsMultipleSelection:NO];
  246. [openPanel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {
  247. if (result == NSModalResponseOK) {
  248. NSURL *url = [openPanel URL];
  249. //判断PDF文件是否已损坏
  250. NSString * filePath = url.path;
  251. if ([filePath.pathExtension.lowercaseString isEqualToString:@"pdf"]) {
  252. PDFDocument *pdf = [[PDFDocument alloc] initWithURL:url];
  253. if (!pdf) {
  254. NSAlert *alert = [[NSAlert alloc] init];
  255. [alert setAlertStyle:NSAlertStyleCritical];
  256. [alert setMessageText:[NSString stringWithFormat:@"%@",NSLocalizedString(@"An error occurred while opening this document. The file is damaged and could not be repaired.", nil)]];
  257. [alert runModal];
  258. return;
  259. }
  260. }
  261. NSImage *image = [[NSImage alloc] initWithContentsOfFile:url.path];
  262. if ([self isDamageImage:image imagePath:url.path]) {
  263. NSAlert *alert = [[NSAlert alloc] init];
  264. [alert setAlertStyle:NSAlertStyleCritical];
  265. [alert setMessageText: [NSString stringWithFormat:NSLocalizedString(@"The file \"%@\" could not be opened.", nil), url.path.lastPathComponent]];
  266. [alert setInformativeText:NSLocalizedString(@"It may be damaged or use a file format that PDF Reader Pro doesn’t recognize.", nil)];
  267. [alert addButtonWithTitle:NSLocalizedString(@"Cancel", nil)];
  268. [alert beginSheetModalForWindow:[NSApp mainWindow] completionHandler:^(NSModalResponse returnCode) {
  269. if (returnCode == NSAlertFirstButtonReturn) {
  270. }
  271. }];
  272. return;
  273. }
  274. [self loadImageViewPath:url isRemoveBGColor:self.clearBackground];
  275. if (self.changeSignatureImageCallback) {
  276. self.changeSignatureImageCallback(YES);
  277. }
  278. }
  279. }];
  280. }
  281. - (void)mouseEntered:(NSEvent *)event {
  282. [super mouseEntered:event];
  283. self.emptyImg.image = [NSImage imageNamed:@"signPicture_hover"];
  284. }
  285. - (void)mouseMoved:(NSEvent *)event {
  286. [super mouseMoved:event];
  287. CGPoint point = [event locationInWindow];
  288. CGPoint convertPoint = [self.pictureView convertPoint:point fromView:self.window.contentView];
  289. if (CGRectContainsPoint(self.pictureView.bounds, convertPoint)) {
  290. self.emptyImg.image = [NSImage imageNamed:@"signPicture_hover"];
  291. } else {
  292. self.emptyImg.image = [NSImage imageNamed:@"signPicture_nor"];
  293. }
  294. }
  295. - (void)mouseExited:(NSEvent *)event {
  296. [super mouseExited:event];
  297. self.emptyImg.image = [NSImage imageNamed:@"signPicture_nor"];
  298. }
  299. #pragma mark - Drag
  300. - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
  301. {
  302. NSPasteboard *pboard = [sender draggingPasteboard];
  303. if ([pboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]]) {
  304. NSArray *fileNames = [pboard propertyListForType:NSFilenamesPboardType];
  305. if (fileNames.count == 1) {
  306. NSArray *supportArray= [self supportedImageTypes];
  307. NSString* path = fileNames.firstObject;
  308. if ([supportArray containsObject:[path.pathExtension lowercaseString]]) {
  309. return NSDragOperationEvery;
  310. }
  311. }
  312. }
  313. return NSDragOperationNone;
  314. }
  315. - (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)sender
  316. {
  317. NSPasteboard *pboard = [sender draggingPasteboard];
  318. if ([pboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]]) {
  319. NSMutableArray *fileNames = [pboard propertyListForType:NSFilenamesPboardType];
  320. if (fileNames.count == 1) {
  321. NSArray *supportArray= [self supportedImageTypes];
  322. NSString* path = fileNames.firstObject;
  323. //判断PDF文件是否已损坏
  324. NSString * filePath = path;
  325. if ([filePath.pathExtension.lowercaseString isEqualToString:@"pdf"]) {
  326. PDFDocument *pdf = [[PDFDocument alloc] initWithURL:[NSURL fileURLWithPath:path]];
  327. if (!pdf) {
  328. NSAlert *alert = [[NSAlert alloc] init];
  329. [alert setAlertStyle:NSAlertStyleCritical];
  330. [alert setMessageText:[NSString stringWithFormat:@"%@",NSLocalizedString(@"An error occurred while opening this document. The file is damaged and could not be repaired.", nil)]];
  331. [alert runModal];
  332. return NO;
  333. }
  334. }
  335. if ([supportArray containsObject:[path.pathExtension lowercaseString]]) {
  336. [self loadImageViewPath:[NSURL fileURLWithPath:path] isRemoveBGColor:self.clearBackground];
  337. if (self.changeSignatureImageCallback) {
  338. self.changeSignatureImageCallback(YES);
  339. }
  340. }
  341. }
  342. }
  343. return YES;
  344. }
  345. @end