TextDrawable.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  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. // self.text=[self.text stringByReplacingOccurrencesOfString:@"\r\n" withString:@"<br>"];
  190. }
  191. else if([source isEqualToString:@"data"])
  192. {
  193. if([self.drawableTemplate[@"source_isexpression"] boolValue])
  194. {
  195. NSString *content = data[self.drawableTemplate[@"source"]];
  196. NSString *pattern = @"\\$\\.\\{([\\s\\S]*?)\\}\\.\\$";
  197. NSArray* matches=[RAUtils expression_varable:content regex:pattern];
  198. // if (matches) {
  199. // for (NSTextCheckingResult *match in matches) {
  200. // for (int i = 0; i < match.numberOfRanges; ++i) {
  201. // NSLog(@"%d-> %@",i, [content substringWithRange:[match rangeAtIndex:i]]);
  202. // }
  203. // }
  204. // }
  205. if (matches)
  206. {
  207. self.text=content;
  208. for (NSTextCheckingResult *match in matches)
  209. {
  210. for (int i = 0; i < match.numberOfRanges/2; ++i) {
  211. NSLog(@"%d-> %@",i, [content substringWithRange:[match rangeAtIndex:i]]);
  212. NSLog(@"%d-> %@",i+1, [content substringWithRange:[match rangeAtIndex:i+1]]);
  213. self.text=[self.text stringByReplacingOccurrencesOfString:[content substringWithRange:[match rangeAtIndex:i]] withString:[NSString stringWithFormat:@"%@",data[[content substringWithRange:[match rangeAtIndex:i+1]]]]];
  214. }
  215. }
  216. }
  217. //self.text=content;
  218. }
  219. else
  220. {
  221. self.text=data[self.drawableTemplate[@"source"]];
  222. }
  223. }
  224. if(self.text==nil)
  225. self.text=@"";
  226. if([self.text isEqualToString:@"www.newpacificdirect.com"])
  227. {
  228. int debug=0;
  229. }
  230. bool bold = [self.drawableTemplate[@"bold"] boolValue];
  231. bool italic = [self.drawableTemplate[@"italic"] boolValue];
  232. NSString* font=self.drawableTemplate[@"font"];
  233. // [super flipContext:context ContextHeight:flip_height];
  234. // super flipContext:context ContextHeight:<#(double)#>
  235. CGFloat fontsize = [self.drawableTemplate[@"size"] doubleValue];
  236. //NSAttributedString * attrStr = [[NSAttributedString alloc] initWithData:[title dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
  237. //创建AttributeStringfdsa
  238. NSMutableAttributedString *string = nil;
  239. // if([self.drawableTemplate[@"ishtml"] boolValue])
  240. // {
  241. // string=[[[NSAttributedString alloc] initWithData:[self.text dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil] mutableCopy];
  242. //
  243. // }
  244. // else
  245. {
  246. string=[[NSMutableAttributedString alloc] initWithString:self.text];
  247. //创建字体以及字体大小
  248. // CTFontRef ctfont = [self CreateFont:font size:fontsize bold:bold];//CTFontCreateWithName(CFSTR("Helvetica"), fontsize, NULL);
  249. // // CTFontRef helveticaBold = CTFontCreateWithName(CFSTR("Helvetica"), fontsize, NULL);
  250. // //字体,把helvetica 样式加到整个,string上
  251. // [string addAttribute:(id)kCTFontAttributeName
  252. // value:CFBridgingRelease(ctfont)
  253. // range:NSMakeRange(0, [string length])];
  254. //
  255. // //字体样式 ,把helveticaBold 样式加到整个,string上
  256. // // [string addAttribute:(id)kCTFontAttributeName
  257. // // value:CFBridgingRelease(helveticaBold)
  258. // // range:NSMakeRange(0, [string length])];
  259. //
  260. // //颜色,此处为黑色,你可以自己改颜色,[UIColor redColor]
  261. // [string addAttribute:(id)kCTForegroundColorAttributeName
  262. // value:(id)self.textColor.CGColor
  263. // range:NSMakeRange(0, [string length])];
  264. string = [self richtext2attributedstring:string font:font size:fontsize bold:bold];
  265. //设置字体间距
  266. long number = self.characterSpace;
  267. CFNumberRef num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type, &number);
  268. [string addAttribute:(id)kCTKernAttributeName value:CFBridgingRelease(num) range:NSMakeRange(0, [string length])];
  269. CFRelease(num);
  270. //创建文本对齐方式
  271. CTTextAlignment alignment = self.textalignment;//对齐方
  272. CTParagraphStyleSetting alignmentStyle;
  273. alignmentStyle.spec=kCTParagraphStyleSpecifierAlignment;
  274. alignmentStyle.valueSize=sizeof(alignment);
  275. alignmentStyle.value=&alignment;
  276. //创建文本, 行间距
  277. CGFloat lineSpace=self.lineSpace;//间距数据
  278. CTParagraphStyleSetting lineSpaceStyle;
  279. lineSpaceStyle.spec=kCTParagraphStyleSpecifierLineSpacing;
  280. lineSpaceStyle.valueSize=sizeof(lineSpace);
  281. lineSpaceStyle.value=&lineSpace;
  282. //设置 line break;
  283. CTLineBreakMode linebreakmode = kCTLineBreakByTruncatingTail;
  284. CTParagraphStyleSetting linebreakStyle;
  285. linebreakStyle.spec = kCTParagraphStyleSpecifierLineBreakMode;
  286. linebreakStyle.valueSize = sizeof(CGFloat);
  287. linebreakStyle.value = &linebreakmode;
  288. //设置 段落间距
  289. CGFloat paragraph = self.paragraphSpace;
  290. CTParagraphStyleSetting paragraphStyle;
  291. paragraphStyle.spec = kCTParagraphStyleSpecifierParagraphSpacing;
  292. paragraphStyle.valueSize = sizeof(CGFloat);
  293. paragraphStyle.value = &paragraph;
  294. //创建样式数组
  295. CTParagraphStyleSetting settings[]={
  296. alignmentStyle,lineSpaceStyle,paragraphStyle,linebreakStyle
  297. };
  298. //设置样式
  299. CTParagraphStyleRef paragraphStyle1 = CTParagraphStyleCreate(settings, sizeof(settings));
  300. //给字符串添加样式attribute
  301. [string addAttribute:(id)kCTParagraphStyleAttributeName
  302. value:(id)paragraphStyle1
  303. range:NSMakeRange(0, [string length])];
  304. }
  305. // CGRect pdfrect=[self to_parent_rect:p_rect pos:self.rect offsetX:0 offsetY:0];
  306. // [string drawInRect:pdfrect];
  307. // [self.text drawInRect:pdfrect withAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:40],NSForegroundColorAttributeName : [UIColor redColor]}];
  308. // layout master
  309. CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
  310. //计算文本绘制size ,这里300是文字宽度,你可以自己更改为247,但是要记得,在height 方法里的这个位置,也改为247
  311. CGSize tmpSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0,0), NULL, CGSizeMake(self.rect.size.width-self.margin_left-self.margin_right, MAXFLOAT), NULL);
  312. //创建textBoxSize以设置view的frame
  313. CGSize textBoxSize = CGSizeMake((int)tmpSize.width + 1, (int)tmpSize.height + 1);
  314. // NSLog(@"textBoxSize0 == %f,%f,%f",textBoxSize.width,textBoxSize.height,textBoxSize.width / textBoxSize.height);
  315. // self.frame = CGRectMake(0, 0, textBoxSize.width , textBoxSize.height);
  316. // [string release];
  317. //- (void)drawRect:(CGRect)rect;代码
  318. CGMutablePathRef leftColumnPath = CGPathCreateMutable();
  319. CGRect parentrect = [self to_parent_rect:p_rect pos:self.rect offsetX:0 offsetY:0];
  320. double height =0;
  321. if(tmpSize.height<parentrect.size.height)
  322. height=tmpSize.height;
  323. else
  324. height=parentrect.size.height;
  325. CGRect rect=CGRectMake(parentrect.origin.x, parentrect.origin.y, parentrect.size.width, height);
  326. // CGRect rect=[RAUtils rectAlign:parentrect rect:scalerect hAlign:self.hAlign vAlign:self.vAlign];
  327. rect=[RAUtils rectVAlign:parentrect rect:rect vAlign:self.vAlign];
  328. // CGRect pdfrect = [self to_pdf_rect:p_rect pos:self.rect contextHeight:flip_height];
  329. rect= [self parent_to_pdf_rect:rect contextHeight:flip_height];
  330. // pdfrect=CGRectMake(pdfrect.origin.x, flip_height-pdfrect.origin.y, pdfrect.size.width, pdfrect.size.height);
  331. CGPathAddRect(leftColumnPath, NULL,
  332. rect);
  333. CTFrameRef leftFrame = CTFramesetterCreateFrame(framesetter,
  334. CFRangeMake(0, 0),
  335. leftColumnPath, NULL);
  336. // NSLog(@"textBoxSize1 == %f,%f",self.frame.size.width,self.frame.size.height);
  337. // flip the coordinate system
  338. // CGContextRef context = UIGraphicsGetCurrentContext();
  339. // CGContextClearRect(context, self.rect);
  340. // CGContextSetFillColorWithColor(context, [[UIColor whiteColor]CGColor]);
  341. // CGContextFillRect(context, CGRectMake(0, 0, self.rect.size.width, self.rect.size.height));
  342. CGContextSetTextMatrix(context, CGAffineTransformIdentity);
  343. // CGContextTranslateCTM(context, 0, self.rect.size.height);
  344. // CGContextScaleCTM(context, 1.0, -1.0);
  345. // draw
  346. CTFrameDraw(leftFrame, context);
  347. // cleanup
  348. CGPathRelease(leftColumnPath);
  349. CFRelease(framesetter);
  350. [self DrawBound:context dataSource:data ParentRect:p_rect startX:x startY:y flipHeight:flip_height range:between_header_and_footer];
  351. return parentrect;
  352. // return CGPointMake(parentrect.origin.x+parentrect.size.width, parentrect.origin.y+parentrect.size.height);
  353. // [super restoreFlip:context ContextHeight:flip_height];
  354. }
  355. @end