CStampPreview.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. //
  2. // CStampPreview.m
  3. // ComPDFKit_Tools
  4. //
  5. // Copyright © 2014-2024 PDF Technologies, Inc. All Rights Reserved.
  6. //
  7. // THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
  8. // AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
  9. // UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
  10. // This notice may not be removed from this file.
  11. //
  12. #import "CStampPreview.h"
  13. #if __has_include(<ComPDFKit_Tools/ComPDFKit_Tools.h>)
  14. #import <ComPDFKit_Tools/CPDFColorUtils.h>
  15. #else
  16. #import "CPDFColorUtils.h"
  17. #endif
  18. static float c01, c02, c03, c11, c12, c13;
  19. #define kStampPreview_OnlyText_Size 48.0
  20. #define kStampPreview_Text_Size 30.0
  21. #define kStampPreview_Date_Size 20.0
  22. @implementation CStampPreview
  23. @synthesize textStampText = _textStampText;
  24. @synthesize textStampStyle = _textStampStyle;
  25. @synthesize textStampColorStyle = _textStampColorStyle;
  26. @synthesize textStampHaveDate = _textStampHaveDate;
  27. @synthesize textStampHaveTime = _textStampHaveTime;
  28. @synthesize leftMargin = _leftMargin;
  29. - (instancetype)initWithFrame:(CGRect)frame {
  30. self = [super initWithFrame:frame];
  31. if (self)
  32. {
  33. _scale = ([[UIScreen mainScreen] scale] == 2.0) ? 2.0f : 1.0f;
  34. }
  35. return self;
  36. }
  37. - (void)setTextStampColorStyle:(NSInteger)TextStampColorStyle {
  38. _textStampColorStyle = TextStampColorStyle;
  39. if (TextStampColorTypeRed == _textStampColorStyle) {
  40. color[0] = 0.57;
  41. color[1] = 0.06;
  42. color[2] = 0.02;
  43. } else if (TextStampColorTypeGreen == _textStampColorStyle) {
  44. color[0] = 0.25;
  45. color[1] = 0.42;
  46. color[2] = 0.13;
  47. } else if (TextStampColorTypeBlue == _textStampColorStyle) {
  48. color[0] = 0.09;
  49. color[1] = 0.15;
  50. color[2] = 0.39;
  51. } else if (TextStampColorTypeBlack == _textStampColorStyle) {
  52. color[0] = 0;
  53. color[1] = 0;
  54. color[2] = 0;
  55. }
  56. }
  57. - (NSString *)getDateTime {
  58. NSTimeZone* timename = [NSTimeZone systemTimeZone];
  59. NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init ];
  60. [outputFormatter setTimeZone:timename ];
  61. NSString *tDate = nil;
  62. if (_textStampHaveDate && !_textStampHaveTime)
  63. {
  64. [outputFormatter setDateFormat:@"yyyy/MM/dd"];
  65. tDate = [outputFormatter stringFromDate:[NSDate date]];
  66. }
  67. else if (_textStampHaveTime && !_textStampHaveDate)
  68. {
  69. [outputFormatter setDateFormat:@"HH:mm:ss"];
  70. tDate = [outputFormatter stringFromDate:[NSDate date]];
  71. }
  72. else if (_textStampHaveDate && _textStampHaveTime)
  73. {
  74. [outputFormatter setDateFormat:@"yyyy/MM/dd HH:mm"];
  75. tDate = [outputFormatter stringFromDate:[NSDate date]];
  76. }
  77. return tDate;
  78. }
  79. // Draw the fill effect
  80. static void MyShaderProcedure(void *info, const CGFloat *in, CGFloat *out) {
  81. CGFloat v;
  82. size_t k, components;
  83. components = (size_t)info;
  84. v = *in;
  85. for (k = 0; k < components -1; k++)
  86. {
  87. if (0 == k) {
  88. *out++ = c01 + v * (c11-c01);
  89. }
  90. else if (1 == k)
  91. {
  92. *out++ = c02 + v * (c12-c02);
  93. }
  94. else if (2 == k) {
  95. *out++ = c03 + v * (c13-c03);
  96. }
  97. }
  98. *out++ = 0.85;
  99. }
  100. // Calculate Rect based on text
  101. - (void)fitStampRect {
  102. UIFont *tTextFont = nil;
  103. UIFont *tTimeFont = nil;
  104. NSString *drawText = nil;
  105. NSString *dateText = nil;
  106. if (self.textStampText.length < 1 && !self.dateTime) {
  107. drawText = @"StampText";
  108. tTextFont = [UIFont fontWithName:@"Helvetica" size:kStampPreview_OnlyText_Size];
  109. } else if (self.textStampText.length > 0 && self.dateTime.length > 0) {
  110. tTextFont = [UIFont fontWithName:@"Helvetica" size:kStampPreview_Text_Size];
  111. tTimeFont = [UIFont fontWithName:@"Helvetica" size:kStampPreview_Date_Size];
  112. drawText = self.textStampText;
  113. dateText = self.dateTime;
  114. } else {
  115. if (self.dateTime) {
  116. drawText = self.dateTime;
  117. } else {
  118. drawText = self.textStampText;
  119. }
  120. tTextFont = [UIFont fontWithName:@"Helvetica" size:kStampPreview_OnlyText_Size];
  121. }
  122. CGSize tTextSize = [drawText sizeWithAttributes:@{ NSFontAttributeName : tTextFont }];
  123. CGSize tTimeSize = CGSizeZero;
  124. if (tTimeFont) {
  125. tTimeSize = [dateText sizeWithAttributes:@{ NSFontAttributeName : tTimeFont }];
  126. }
  127. int w = tTextSize.width > tTimeSize.width ? tTextSize.width : tTimeSize.width;
  128. int count = 0;
  129. for (int i = 0; i < drawText.length; ++i) {
  130. NSRange range = NSMakeRange(i,1);
  131. NSString *aStr = [drawText substringWithRange:range];
  132. if ([aStr isEqualToString:@" "]) {
  133. ++count;
  134. }
  135. }
  136. if (tTextSize.width < tTimeSize.width) {
  137. w += 15;
  138. } else {
  139. w += 13 + 5 * count;
  140. }
  141. int h = tTextSize.height + 5;
  142. if (dateText) {
  143. h = tTextSize.height + tTimeSize.height + 8.011;
  144. }
  145. if (_textStampStyle == TextStampTypeLeft) {
  146. w = w + h * 0.618033;
  147. } else if (_textStampStyle == TextStampTypeRight) {
  148. w = w + h * 0.618033;
  149. }
  150. float x = 0.0;
  151. float y = 0.0;
  152. _scale = 1.0;
  153. CGFloat maxW = 300 - _leftMargin;
  154. if (w > maxW ) {
  155. _scale = maxW/w;
  156. h = h*_scale;
  157. x = self.frame.size.width/2.0 - maxW/2.0;
  158. y = self.frame.size.height/2.0 - h/2.0;
  159. _stampBounds = CGRectMake(x + _leftMargin, y, maxW, h);
  160. } else {
  161. x = self.frame.size.width/2.0 - w/2.0;
  162. y = self.frame.size.height/2.0 - h/2.0;
  163. _stampBounds = CGRectMake(x + _leftMargin, y, w, h);
  164. }
  165. }
  166. // Only override drawRect: if you perform custom drawing.
  167. // An empty implementation adversely affects performance during animation.
  168. - (void)drawRect:(CGRect)rect {
  169. self.dateTime = [self getDateTime];
  170. [self fitStampRect];
  171. CGContextRef context = UIGraphicsGetCurrentContext();
  172. CGContextSetFillColorWithColor(context, [CPDFColorUtils CAnnotationSampleDrawBackgoundColor].CGColor);
  173. CGContextFillRect(context, self.bounds);
  174. // Draw border background
  175. if (TextStampTypeNone != _textStampStyle) {
  176. [self drawBounder:context];
  177. }
  178. // Draws custom text
  179. [self drawText:context];
  180. }
  181. - (void)drawBounder:(CGContextRef)context {
  182. if (!context) {
  183. return;
  184. }
  185. CGContextSaveGState(context);
  186. const CGFunctionCallbacks callbacks = {
  187. .version = 0, .evaluate = &MyShaderProcedure, .releaseInfo = NULL
  188. };
  189. c01 = c02 = c03 = c11 = c12 = c13 = 1.0;
  190. if (color[0] > color[1] && color[0] > color[2]) {
  191. c01 = 1.0;
  192. c02 = 0.78;
  193. c03 = 0.78;
  194. c11 = 0.98;
  195. c12 = 0.92;
  196. c13 = 0.91;
  197. }
  198. else if (color[1] > color[0] && color[1] > color[2]) {
  199. c01 = 0.81;
  200. c02 = 0.88;
  201. c03 = 0.78;
  202. c11 = 0.95;
  203. c12 = 0.95;
  204. c13 = 0.95;
  205. }
  206. else if (color[2] > color[0] && color[2] > color[1])
  207. {
  208. c01 = 0.79;
  209. c02 = 0.81;
  210. c03 = 0.89;
  211. c11 = 0.90;
  212. c12 = 0.95;
  213. c13 = 1.0;
  214. }
  215. size_t components = 1 + CGColorSpaceGetNumberOfComponents(CGColorSpaceCreateDeviceRGB());
  216. CGFunctionRef funcRef = CGFunctionCreate((void *) components,
  217. 1,
  218. (CGFloat[]){0.0f, 1.0f},
  219. 4,
  220. //(CGFloat[]){0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f},
  221. (CGFloat[]){c01, c11, c02, c12, c03, c13, 0.0f, 1.0f},
  222. &callbacks);
  223. CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
  224. CGShadingRef shadingRef = CGShadingCreateAxial(colorSpaceRef,
  225. CGPointMake(_stampBounds.origin.x+_stampBounds.size.width*0.75, _stampBounds.origin.y+_stampBounds.size.width*0.25),
  226. CGPointMake(_stampBounds.origin.x+_stampBounds.size.width*0.25, _stampBounds.origin.y+_stampBounds.size.width*0.75),
  227. funcRef, true, true);
  228. CGColorSpaceRelease(colorSpaceRef);
  229. CGFunctionRelease(funcRef);
  230. if (_textStampStyle == TextStampTypeCenter) {
  231. [self drawNormalRect:context];
  232. } else if (_textStampStyle == TextStampTypeLeft) {
  233. [self drawLeftBounder:context];
  234. } else if (_textStampStyle == TextStampTypeRight) {
  235. [self drawRightBounder:context];
  236. }
  237. CGContextClip (context);
  238. CGContextSaveGState(context);
  239. CGContextDrawShading(context, shadingRef);
  240. CGContextRestoreGState(context);
  241. CGShadingRelease(shadingRef);
  242. if (_textStampStyle == TextStampTypeCenter) {
  243. [self drawNormalRect:context];
  244. } else if (_textStampStyle == TextStampTypeLeft) {
  245. [self drawLeftBounder:context];
  246. } else if (_textStampStyle == TextStampTypeRight) {
  247. [self drawRightBounder:context];
  248. }
  249. CGContextStrokePath(context);
  250. }
  251. - (void)drawNormalRect:(CGContextRef)context {
  252. float tmpHeight = 11.0 * _stampBounds.size.height/50;
  253. float tmpWidth = 3.0 * _stampBounds.size.height/50;
  254. float hw1 = 5.54492 * _stampBounds.size.height/50;
  255. float hw2 = 4.40039 * _stampBounds.size.height/50;
  256. CGContextBeginPath (context);
  257. CGContextMoveToPoint(context, _stampBounds.origin.x+tmpWidth, _stampBounds.origin.y+_stampBounds.size.height-tmpHeight);
  258. CGContextAddCurveToPoint(context, _stampBounds.origin.x+tmpWidth, _stampBounds.origin.y+_stampBounds.size.height-tmpHeight+hw2, _stampBounds.origin.x+tmpHeight-hw1, _stampBounds.origin.y+_stampBounds.size.height-tmpWidth, _stampBounds.origin.x+tmpHeight, _stampBounds.origin.y+_stampBounds.size.height-tmpWidth);
  259. CGContextAddLineToPoint(context, _stampBounds.origin.x+_stampBounds.size.width-tmpHeight, _stampBounds.origin.y+_stampBounds.size.height-tmpWidth);
  260. CGContextAddCurveToPoint(context, _stampBounds.origin.x+_stampBounds.size.width-tmpHeight+hw1, _stampBounds.origin.y+_stampBounds.size.height-tmpWidth, _stampBounds.origin.x+_stampBounds.size.width-tmpWidth, _stampBounds.origin.y+_stampBounds.size.height-tmpHeight+hw2, _stampBounds.origin.x+_stampBounds.size.width-tmpWidth, _stampBounds.origin.y+_stampBounds.size.height-tmpHeight);
  261. CGContextAddLineToPoint(context, _stampBounds.origin.x+_stampBounds.size.width-tmpWidth, _stampBounds.origin.y+tmpHeight);
  262. CGContextAddCurveToPoint(context, _stampBounds.origin.x+_stampBounds.size.width-tmpWidth, _stampBounds.origin.y+tmpHeight-hw2, _stampBounds.origin.x+_stampBounds.size.width-tmpHeight+hw1, _stampBounds.origin.y+tmpWidth, _stampBounds.origin.x+_stampBounds.size.width-tmpHeight, _stampBounds.origin.y+tmpWidth);
  263. CGContextAddLineToPoint(context,_stampBounds.origin.x+tmpHeight, _stampBounds.origin.y+tmpWidth);
  264. CGContextAddCurveToPoint(context, _stampBounds.origin.x+tmpHeight-hw1, _stampBounds.origin.y+tmpWidth, _stampBounds.origin.x+tmpWidth, _stampBounds.origin.y+tmpHeight-hw2, _stampBounds.origin.x+tmpWidth, _stampBounds.origin.y+tmpHeight);
  265. CGContextAddLineToPoint(context,_stampBounds.origin.x+tmpWidth, _stampBounds.origin.y+_stampBounds.size.height-tmpHeight);
  266. CGContextClosePath (context);
  267. }
  268. - (void)drawLeftBounder:(CGContextRef)context {
  269. float tmpHeight = 11.0 * _stampBounds.size.height/50;
  270. float tmpWidth = 3.0 * _stampBounds.size.height/50;
  271. float hw1 = 5.54492 * _stampBounds.size.height/50;
  272. float hw2 = 4.40039 * _stampBounds.size.height/50;
  273. float x0 = _stampBounds.origin.x + _stampBounds.size.height * 0.618033;
  274. float y0 = _stampBounds.origin.y;
  275. float x1 = _stampBounds.origin.x + _stampBounds.size.width;
  276. float y1 = _stampBounds.origin.y + _stampBounds.size.height;
  277. float xp = _stampBounds.origin.x;
  278. float yp = _stampBounds.origin.y + _stampBounds.size.height / 2.0;
  279. CGContextBeginPath (context);
  280. CGContextMoveToPoint(context, x0 + tmpHeight, y1 - tmpWidth);
  281. CGContextAddLineToPoint(context, x1-tmpHeight, y1-tmpWidth);
  282. CGContextAddCurveToPoint(context, x1-tmpHeight+hw1, y1-tmpWidth, x1-tmpWidth, y1-tmpHeight+hw2, x1-tmpWidth, y1-tmpHeight);
  283. CGContextAddLineToPoint(context, x1-tmpWidth, y0+tmpHeight);
  284. CGContextAddCurveToPoint(context, x1-tmpWidth, y0+tmpHeight-hw2, x1-tmpHeight+hw1, y0+tmpWidth, x1-tmpHeight, y0+tmpWidth);
  285. CGContextAddLineToPoint(context, x0+tmpHeight, y0+tmpWidth);
  286. CGContextAddLineToPoint(context, xp+tmpHeight, yp);
  287. CGContextAddLineToPoint(context, x0+tmpHeight, y1-tmpWidth);
  288. CGContextClosePath (context);
  289. }
  290. - (void)drawRightBounder:(CGContextRef)context {
  291. float tmpHeight = 11.0 * _stampBounds.size.height/50;
  292. float tmpWidth = 3.0 * _stampBounds.size.height/50;
  293. float hw1 = 5.54492 * _stampBounds.size.height/50;
  294. float hw2 = 4.40039 * _stampBounds.size.height/50;
  295. float x0 = _stampBounds.origin.x;
  296. float y0 = _stampBounds.origin.y;
  297. float x1 = _stampBounds.origin.x + _stampBounds.size.width - _stampBounds.size.height * 0.618033;
  298. float y1 = _stampBounds.origin.y + _stampBounds.size.height;
  299. float xp = _stampBounds.origin.x + _stampBounds.size.width;
  300. float yp = _stampBounds.origin.y + _stampBounds.size.height / 2.0;
  301. CGContextBeginPath (context);
  302. CGContextMoveToPoint(context, x0 + tmpWidth, y1 - tmpHeight);
  303. CGContextAddCurveToPoint(context, x0+tmpWidth, y1-tmpHeight+hw2, x0+tmpHeight-hw1, y1-tmpWidth, x0+tmpHeight, y1-tmpWidth);
  304. CGContextAddLineToPoint(context, x1-tmpHeight, y1-tmpWidth);
  305. CGContextAddLineToPoint(context, xp-tmpHeight, yp);
  306. CGContextAddLineToPoint(context, x1-tmpHeight, y0+tmpWidth);
  307. CGContextAddLineToPoint(context, x0+tmpHeight, y0+tmpWidth);
  308. CGContextAddCurveToPoint(context, x0+tmpHeight-hw1, y0+tmpWidth, x0+tmpWidth, y0+tmpHeight-hw2, x0+tmpWidth, y0+tmpHeight);
  309. CGContextAddLineToPoint(context, x0+tmpWidth, y1-tmpHeight);
  310. CGContextClosePath (context);
  311. }
  312. - (void)drawText:(CGContextRef)context {
  313. if (!context) {
  314. return;
  315. }
  316. CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0, -1.0));
  317. NSString *drawText = nil;
  318. NSString *dateText = nil;
  319. if (self.textStampText.length < 1 && !self.dateTime) {
  320. drawText = @"StampText";
  321. } else if (self.textStampText.length > 0 && self.dateTime.length > 0) {
  322. drawText = self.textStampText;
  323. dateText = self.dateTime;
  324. } else {
  325. if (self.dateTime) {
  326. drawText = self.dateTime;
  327. } else {
  328. drawText = self.textStampText;
  329. }
  330. }
  331. if (!dateText) {
  332. float fontsize = kStampPreview_OnlyText_Size*_scale;
  333. UIFont* font = [UIFont fontWithName:@"Helvetica" size:fontsize];
  334. CGRect rt = CGRectInset(_stampBounds, 0, 0);
  335. rt.origin.x += 8.093 * _scale;
  336. if (_textStampStyle == TextStampTypeLeft) {
  337. rt.origin.x += rt.size.height * 0.618033;
  338. }
  339. UIGraphicsPushContext(context);
  340. [[UIColor colorWithRed:color[0] green:color[1] blue:color[2] alpha:1] set];
  341. [drawText drawInRect:rt withFont:font lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];
  342. UIGraphicsPopContext();
  343. } else {
  344. float tFontSize = kStampPreview_Text_Size*_scale;
  345. UIFont *tFont = [UIFont fontWithName:@"Helvetica" size:tFontSize];
  346. CGRect tTextRT = CGRectInset(_stampBounds, 0, 0);
  347. tTextRT.origin.x += 8.093 * _scale;
  348. if (_textStampStyle == TextStampTypeLeft) {
  349. tTextRT.origin.x += tTextRT.size.height * 0.618033;
  350. }
  351. UIGraphicsPushContext(context);
  352. [[UIColor colorWithRed:color[0] green:color[1] blue:color[2] alpha:1] set];
  353. if (drawText.length > 0) {
  354. [drawText drawInRect:tTextRT withFont:tFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];
  355. CGRect tDateRT = CGRectInset(_stampBounds, 0, 0);
  356. tDateRT.origin.x += 8.093 * _scale;
  357. if (_textStampStyle == TextStampTypeLeft) {
  358. tDateRT.origin.x += tDateRT.size.height * 0.618033;
  359. }
  360. tDateRT.origin.y = tDateRT.origin.y + tFontSize + 6.103*_scale;
  361. tFontSize = kStampPreview_Date_Size*_scale;
  362. tFont = [UIFont fontWithName:@"Helvetica" size:tFontSize];
  363. [[UIColor colorWithRed:color[0] green:color[1] blue:color[2] alpha:1] set];
  364. [dateText drawInRect:tDateRT withFont:tFont lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];
  365. } else {
  366. float fontsize = kStampPreview_Date_Size*_scale;
  367. UIFont* font = [UIFont fontWithName:@"Helvetica" size:fontsize];
  368. CGRect rt = CGRectInset(_stampBounds, 0, 0);
  369. rt.origin.x += 8.093 * _scale;
  370. if (_textStampStyle == TextStampTypeLeft) {
  371. rt.origin.x += rt.size.height * 0.618033;
  372. }
  373. [[UIColor colorWithRed:color[0] green:color[1] blue:color[2] alpha:1] set];
  374. [dateText drawInRect:rt withFont:font lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];
  375. }
  376. UIGraphicsPopContext();
  377. }
  378. }
  379. - (UIImage *)renderImage
  380. {
  381. UIImage *image = [self renderImageFromView:self];
  382. return image;
  383. }
  384. /* Convert UIView to UIImage */
  385. - (UIImage *)renderImageFromView:(UIView *)view
  386. {
  387. UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 1.0);
  388. CGContextRef context=UIGraphicsGetCurrentContext();
  389. CGContextTranslateCTM(context, 1.0, 1.0);
  390. [view.layer renderInContext:context];
  391. UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  392. UIGraphicsEndImageContext();
  393. return image;
  394. }
  395. @end