TextDrawable.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. //
  2. // TextDrawable.m
  3. // pdftest
  4. //
  5. // Created by Ray on 10/12/16.
  6. // Copyright © 2016 United Software Applications, Inc. All rights reserved.
  7. //
  8. #import "TextDrawable.h"
  9. #import <CoreText/CoreText.h>
  10. #import "RAUtils.h"
  11. @implementation TextDrawable
  12. -(void) setDrawableTemplate:(NSMutableDictionary *)drawableTemplate
  13. {
  14. [super setDrawableTemplate:drawableTemplate];
  15. NSString* align= drawableTemplate[@"textAlignment"];
  16. if(align.length==0 || [align.lowercaseString isEqualToString:@"left"])
  17. {
  18. self.textalignment= kCTTextAlignmentLeft;
  19. }
  20. else if([align.lowercaseString isEqualToString:@"right"])
  21. {
  22. self.textalignment= kCTTextAlignmentRight;
  23. }
  24. else if([align.lowercaseString isEqualToString:@"center"])
  25. {
  26. self.textalignment= kCTTextAlignmentCenter;
  27. }
  28. else
  29. {
  30. self.textalignment= kCTTextAlignmentLeft;
  31. }
  32. NSString* colorvalue=drawableTemplate[@"color"];
  33. if(colorvalue.length>0 )
  34. {
  35. unsigned long color = strtoul([colorvalue UTF8String],0,16);
  36. self.textColor= UIColorFromRGB(color);
  37. }
  38. else
  39. {
  40. self.textColor= [UIColor blackColor];
  41. }
  42. // kCTTextAlignmentJustified CT_ENUM_AVAILABLE(10_8, 6_0) = 3,
  43. // kCTTextAlignmentNatural CT_ENUM_AVAILABLE(10_8, 6_0) = 4,
  44. // _drawableTemplate = drawableTemplate;
  45. // self.margin_left=[self.drawableTemplate[@"margin_left"] doubleValue];
  46. // self.margin_right=[self.drawableTemplate[@"margin_right"] doubleValue];
  47. // self.margin_top=[self.drawableTemplate[@"margin_top"] doubleValue];
  48. // self.margin_bottom=[self.drawableTemplate[@"margin_bottom"] doubleValue];
  49. // self.rect = CGRectMake(0, 0, [self.drawableTemplate[@"width"] doubleValue], [self.drawableTemplate[@"height"] doubleValue]);
  50. }
  51. -(CGRect) Query_Rect:(CGContextRef) context dataSource:(NSMutableDictionary*)data ParentRect:(CGRect)p_rect startX:(double) x startY:(double) y flipHeight:(double)flip_height range:(NSRange)between_header_and_footer
  52. {
  53. CGRect parentrect = [self to_parent_rect:p_rect pos:self.rect offsetX:0 offsetY:0];
  54. return parentrect;
  55. }
  56. -(CTFontRef)CreateFont:(NSString*)name size:(double)size bold:(bool)bold
  57. {
  58. if(name==nil)
  59. {
  60. name=@"Helvetica";
  61. // name=@"DejaVu Sans";
  62. }
  63. if(size==0)
  64. {
  65. size=10;
  66. }
  67. NSString* style = @"Regular";
  68. if(bold)
  69. style=@"Bold";
  70. //name=@"Courier";
  71. NSDictionary *fontAttributes =
  72. [NSDictionary dictionaryWithObjectsAndKeys:
  73. name, (NSString *)kCTFontFamilyNameAttribute,
  74. style, (NSString *)kCTFontStyleNameAttribute,
  75. [NSNumber numberWithFloat:size],
  76. (NSString *)kCTFontSizeAttribute,
  77. nil];
  78. // Create a descriptor.
  79. CTFontDescriptorRef descriptor =
  80. CTFontDescriptorCreateWithAttributes((CFDictionaryRef)fontAttributes);
  81. // Create a font using the descriptor.
  82. CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, 0.0, NULL);
  83. CFRelease(descriptor);
  84. return font;
  85. // if(bold)
  86. // {
  87. // CTFontRef font=CTFontCreateWithName((__bridge CFStringRef)name, size, NULL);
  88. // CTFontRef font_bold =CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, kCTFontBoldTrait, kCTFontBoldTrait);
  89. // CFBridgingRelease(font);
  90. // return font_bold;
  91. // }
  92. // return CTFontCreateWithName((__bridge CFStringRef)name, size, NULL);
  93. }
  94. //-(NSString*) QueryFontName:(NSString*)font
  95. //{
  96. // if(font==nil)
  97. // {
  98. // return @"Helvetica";
  99. // }
  100. // else if([font.lowercaseString isEqualToString:@"kalinga"])
  101. // {
  102. // return @"kalinga";
  103. // }
  104. // return @"Helvetica";
  105. //}
  106. -(NSMutableAttributedString*) richtext2attributedstring:(NSMutableAttributedString*)string font:(NSString*)font size:(double)size bold:(bool)bold
  107. {
  108. // UILabel* uilabel=[[UILabel alloc]init];
  109. // uilabel.font=[UIFont fontWithName:font size:size];
  110. // NSAttributedString * attrStr = [[NSAttributedString alloc] initWithData:[self.text dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
  111. // uilabel.attributedText = attrStr;
  112. // NSLog(@"%@", attrStr);
  113. // NSLog(@"%@", uilabel.attributedText);
  114. CTFontRef ctfont = [self CreateFont:font size:size bold:bold];//CTFontCreateWithName(CFSTR("Helvetica"), fontsize, NULL);b
  115. CTFontRef ctfont_bold = [self CreateFont:font size:size bold:true];//CTFontCreateWithName(CFSTR("Helvetica"), fontsize, NULL);
  116. // CTFontRef helveticaBold = CTFontCreateWithName(CFSTR("Helvetica"), fontsize, NULL);
  117. //字体,把helvetica 样式加到整个,string上
  118. [string addAttribute:(id)kCTFontAttributeName
  119. value:CFBridgingRelease(ctfont)
  120. range:NSMakeRange(0, [string length])];
  121. //颜色,此处为黑色,你可以自己改颜色,[UIColor redColor]
  122. [string addAttribute:(id)kCTForegroundColorAttributeName
  123. value:(id)self.textColor.CGColor
  124. range:NSMakeRange(0, [string length])];
  125. if(!bold)
  126. {
  127. NSString* newstring= nil;
  128. // NSString *content = string.string ;
  129. NSString *pattern = @"\\<b\\>([\\s\\S]*?)\\<\\/b\\>";
  130. // NSArray* matches=[RAUtils expression_varable:content regex:pattern];
  131. // if (matches) {
  132. // for (NSTextCheckingResult *match in matches) {
  133. // for (int i = 0; i < match.numberOfRanges; ++i) {
  134. // NSLog(@"%d-> %@",i, [content substringWithRange:[match rangeAtIndex:i]]);
  135. // }
  136. // }
  137. // }
  138. NSTextCheckingResult * match=[RAUtils expression_findfistMatch:string.string regex:pattern];
  139. while(match)
  140. {
  141. //for (int i = 0; i < match.numberOfRanges/2; ++i)
  142. {
  143. int i=0;
  144. NSLog(@"%d->range with richtext label: %d,%d",i, [match rangeAtIndex:i].location,[match rangeAtIndex:i].length);
  145. NSLog(@"%d-> range of text: %d,%d ",i+1, [match rangeAtIndex:i+1].location,[match rangeAtIndex:i+1].length);
  146. NSLog(@"string length: %d",string.string.length);
  147. [string addAttribute:(id)kCTFontAttributeName
  148. value:(__bridge id _Nonnull)(ctfont_bold)
  149. range:[match rangeAtIndex:i+1]];
  150. [string replaceCharactersInRange:NSMakeRange([match rangeAtIndex:i+1].location+[match rangeAtIndex:i+1].length, [match rangeAtIndex:i].location+[match rangeAtIndex:i].length-([match rangeAtIndex:i+1].location+[match rangeAtIndex:i+1].length)) withString:@""];
  151. [string replaceCharactersInRange:NSMakeRange([match rangeAtIndex:i].location, [match rangeAtIndex:i+1].location-[match rangeAtIndex:i].location) withString:@""];
  152. NSLog(@"string after replace: %@",string.string);
  153. //newstring=[newstring stringByReplacingOccurrencesOfString:[content substringWithRange:[match rangeAtIndex:i]] withString:[content substringWithRange:[match rangeAtIndex:i+1]]];
  154. match=[RAUtils expression_findfistMatch:string.string regex:pattern];
  155. }
  156. }
  157. // if (matches)
  158. // {
  159. // newstring=content;
  160. // for (NSTextCheckingResult *match in matches)
  161. // {
  162. //
  163. // for (int i = 0; i < match.numberOfRanges/2; ++i)
  164. // {
  165. // NSLog(@"%d-> %@",i, [content substringWithRange:[match rangeAtIndex:i]]);
  166. // NSLog(@"%d-> %@",i+1, [content substringWithRange:[match rangeAtIndex:i+1]]);
  167. //
  168. // [string addAttribute:(id)kCTFontAttributeName
  169. // value:CFBridgingRelease(ctfont_bold)
  170. // range:[match rangeAtIndex:i+1]];
  171. //
  172. // newstring=[newstring stringByReplacingOccurrencesOfString:[content substringWithRange:[match rangeAtIndex:i]] withString:[content substringWithRange:[match rangeAtIndex:i+1]]];
  173. //
  174. // }
  175. // }
  176. // }
  177. CFBridgingRelease(ctfont_bold);
  178. }
  179. return string;
  180. }
  181. -(CGRect) Draw:(CGContextRef) context dataSource:(NSMutableDictionary*)data ParentRect:(CGRect)p_rect startX:(double) x startY:(double) y flipHeight:(double)flip_height range:(NSRange)between_header_and_footer
  182. {
  183. NSString * source=self.drawableTemplate[@"source_type"];
  184. if(source==nil)
  185. source=@"const";
  186. if([source isEqualToString:@"const"])
  187. {
  188. self.text=self.drawableTemplate[@"text"];
  189. }
  190. else if([source isEqualToString:@"data"])
  191. {
  192. if([self.drawableTemplate[@"source_isexpression"] boolValue])
  193. {
  194. NSString *content = data[self.drawableTemplate[@"source"]];
  195. NSString *pattern = @"\\$\\.\\{([\\s\\S]*?)\\}\\.\\$";
  196. NSArray* matches=[RAUtils expression_varable:content regex:pattern];
  197. // if (matches) {
  198. // for (NSTextCheckingResult *match in matches) {
  199. // for (int i = 0; i < match.numberOfRanges; ++i) {
  200. // NSLog(@"%d-> %@",i, [content substringWithRange:[match rangeAtIndex:i]]);
  201. // }
  202. // }
  203. // }
  204. if (matches)
  205. {
  206. self.text=content;
  207. for (NSTextCheckingResult *match in matches)
  208. {
  209. for (int i = 0; i < match.numberOfRanges/2; ++i) {
  210. NSLog(@"%d-> %@",i, [content substringWithRange:[match rangeAtIndex:i]]);
  211. NSLog(@"%d-> %@",i+1, [content substringWithRange:[match rangeAtIndex:i+1]]);
  212. self.text=[self.text stringByReplacingOccurrencesOfString:[content substringWithRange:[match rangeAtIndex:i]] withString:[NSString stringWithFormat:@"%@",data[[content substringWithRange:[match rangeAtIndex:i+1]]]]];
  213. }
  214. }
  215. }
  216. //self.text=content;
  217. }
  218. else
  219. {
  220. self.text=data[self.drawableTemplate[@"source"]];
  221. }
  222. }
  223. if(self.text==nil)
  224. self.text=@"";
  225. // if([self.text isEqualToString:@"Special: $ 185.00"])
  226. // {
  227. // int debug=0;
  228. // }
  229. bool bold = [self.drawableTemplate[@"bold"] boolValue];
  230. bool italic = [self.drawableTemplate[@"italic"] boolValue];
  231. NSString* font=self.drawableTemplate[@"font"];
  232. // [super flipContext:context ContextHeight:flip_height];
  233. // super flipContext:context ContextHeight:<#(double)#>
  234. CGFloat fontsize = [self.drawableTemplate[@"size"] doubleValue];
  235. //NSAttributedString * attrStr = [[NSAttributedString alloc] initWithData:[title dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
  236. //创建AttributeStringfdsa
  237. NSMutableAttributedString *string = nil;
  238. // if([self.drawableTemplate[@"ishtml"] boolValue])
  239. // {
  240. // string=[[[NSAttributedString alloc] initWithData:[self.text dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil] mutableCopy];
  241. //
  242. // }
  243. // else
  244. {
  245. string=[[NSMutableAttributedString alloc] initWithString:self.text];
  246. //创建字体以及字体大小
  247. // CTFontRef ctfont = [self CreateFont:font size:fontsize bold:bold];//CTFontCreateWithName(CFSTR("Helvetica"), fontsize, NULL);
  248. // // CTFontRef helveticaBold = CTFontCreateWithName(CFSTR("Helvetica"), fontsize, NULL);
  249. // //字体,把helvetica 样式加到整个,string上
  250. // [string addAttribute:(id)kCTFontAttributeName
  251. // value:CFBridgingRelease(ctfont)
  252. // range:NSMakeRange(0, [string length])];
  253. //
  254. // //字体样式 ,把helveticaBold 样式加到整个,string上
  255. // // [string addAttribute:(id)kCTFontAttributeName
  256. // // value:CFBridgingRelease(helveticaBold)
  257. // // range:NSMakeRange(0, [string length])];
  258. //
  259. // //颜色,此处为黑色,你可以自己改颜色,[UIColor redColor]
  260. // [string addAttribute:(id)kCTForegroundColorAttributeName
  261. // value:(id)self.textColor.CGColor
  262. // range:NSMakeRange(0, [string length])];
  263. string = [self richtext2attributedstring:string font:font size:fontsize bold:bold];
  264. //设置字体间距
  265. long number = self.characterSpace;
  266. CFNumberRef num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type, &number);
  267. [string addAttribute:(id)kCTKernAttributeName value:CFBridgingRelease(num) range:NSMakeRange(0, [string length])];
  268. CFRelease(num);
  269. //创建文本对齐方式
  270. CTTextAlignment alignment = self.textalignment;//对齐方
  271. CTParagraphStyleSetting alignmentStyle;
  272. alignmentStyle.spec=kCTParagraphStyleSpecifierAlignment;
  273. alignmentStyle.valueSize=sizeof(alignment);
  274. alignmentStyle.value=&alignment;
  275. //创建文本, 行间距
  276. CGFloat lineSpace=self.lineSpace;//间距数据
  277. CTParagraphStyleSetting lineSpaceStyle;
  278. lineSpaceStyle.spec=kCTParagraphStyleSpecifierLineSpacing;
  279. lineSpaceStyle.valueSize=sizeof(lineSpace);
  280. lineSpaceStyle.value=&lineSpace;
  281. //设置 line break;
  282. CTLineBreakMode linebreakmode = kCTLineBreakByTruncatingTail;
  283. CTParagraphStyleSetting linebreakStyle;
  284. linebreakStyle.spec = kCTParagraphStyleSpecifierLineBreakMode;
  285. linebreakStyle.valueSize = sizeof(CGFloat);
  286. linebreakStyle.value = &linebreakmode;
  287. //设置 段落间距
  288. CGFloat paragraph = self.paragraphSpace;
  289. CTParagraphStyleSetting paragraphStyle;
  290. paragraphStyle.spec = kCTParagraphStyleSpecifierParagraphSpacing;
  291. paragraphStyle.valueSize = sizeof(CGFloat);
  292. paragraphStyle.value = &paragraph;
  293. //创建样式数组
  294. CTParagraphStyleSetting settings[]={
  295. alignmentStyle,lineSpaceStyle,paragraphStyle,linebreakStyle
  296. };
  297. //设置样式
  298. CTParagraphStyleRef paragraphStyle1 = CTParagraphStyleCreate(settings, sizeof(settings));
  299. //给字符串添加样式attribute
  300. [string addAttribute:(id)kCTParagraphStyleAttributeName
  301. value:(id)paragraphStyle1
  302. range:NSMakeRange(0, [string length])];
  303. }
  304. // CGRect pdfrect=[self to_parent_rect:p_rect pos:self.rect offsetX:0 offsetY:0];
  305. // [string drawInRect:pdfrect];
  306. // [self.text drawInRect:pdfrect withAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:40],NSForegroundColorAttributeName : [UIColor redColor]}];
  307. // layout master
  308. CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
  309. //计算文本绘制size ,这里300是文字宽度,你可以自己更改为247,但是要记得,在height 方法里的这个位置,也改为247
  310. CGSize tmpSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0,0), NULL, CGSizeMake(self.rect.size.width-self.margin_left-self.margin_right, MAXFLOAT), NULL);
  311. //创建textBoxSize以设置view的frame
  312. CGSize textBoxSize = CGSizeMake((int)tmpSize.width + 1, (int)tmpSize.height + 1);
  313. // NSLog(@"textBoxSize0 == %f,%f,%f",textBoxSize.width,textBoxSize.height,textBoxSize.width / textBoxSize.height);
  314. // self.frame = CGRectMake(0, 0, textBoxSize.width , textBoxSize.height);
  315. // [string release];
  316. //- (void)drawRect:(CGRect)rect;代码
  317. CGMutablePathRef leftColumnPath = CGPathCreateMutable();
  318. CGRect parentrect = [self to_parent_rect:p_rect pos:self.rect offsetX:0 offsetY:0];
  319. CGRect rect=CGRectMake(parentrect.origin.x, parentrect.origin.y, parentrect.size.width, /*tmpSize.height*/parentrect.size.height);
  320. // CGRect rect=[RAUtils rectAlign:parentrect rect:scalerect hAlign:self.hAlign vAlign:self.vAlign];
  321. rect=[RAUtils rectVAlign:parentrect rect:rect vAlign:self.vAlign];
  322. // CGRect pdfrect = [self to_pdf_rect:p_rect pos:self.rect contextHeight:flip_height];
  323. rect= [self parent_to_pdf_rect:rect contextHeight:flip_height];
  324. // pdfrect=CGRectMake(pdfrect.origin.x, flip_height-pdfrect.origin.y, pdfrect.size.width, pdfrect.size.height);
  325. CGPathAddRect(leftColumnPath, NULL,
  326. rect);
  327. CTFrameRef leftFrame = CTFramesetterCreateFrame(framesetter,
  328. CFRangeMake(0, 0),
  329. leftColumnPath, NULL);
  330. // NSLog(@"textBoxSize1 == %f,%f",self.frame.size.width,self.frame.size.height);
  331. // flip the coordinate system
  332. // CGContextRef context = UIGraphicsGetCurrentContext();
  333. // CGContextClearRect(context, self.rect);
  334. // CGContextSetFillColorWithColor(context, [[UIColor whiteColor]CGColor]);
  335. // CGContextFillRect(context, CGRectMake(0, 0, self.rect.size.width, self.rect.size.height));
  336. CGContextSetTextMatrix(context, CGAffineTransformIdentity);
  337. // CGContextTranslateCTM(context, 0, self.rect.size.height);
  338. // CGContextScaleCTM(context, 1.0, -1.0);
  339. // draw
  340. CTFrameDraw(leftFrame, context);
  341. // cleanup
  342. CGPathRelease(leftColumnPath);
  343. CFRelease(framesetter);
  344. [self DrawBound:context dataSource:data ParentRect:p_rect startX:x startY:y flipHeight:flip_height range:between_header_and_footer];
  345. return parentrect;
  346. // return CGPointMake(parentrect.origin.x+parentrect.size.width, parentrect.origin.y+parentrect.size.height);
  347. // [super restoreFlip:context ContextHeight:flip_height];
  348. }
  349. @end