“AI 技术+人才”如何成为企业增长新引擎?戳此了解>>> 了解详情
写点什么

贝塞尔曲线在 iOS 端的绘图实践

  • 2020-09-15
  • 本文字数:9102 字

    阅读完需:约 30 分钟

贝塞尔曲线在iOS端的绘图实践

1 前言

在这个大数据的时代,很多信息只有通过图形才能更好的展示给用户。例如:房屋的历史价格、基金股票的历史增长、数据占比分析图等。如何做图形?需要用到什么知识?本文将从 建模、显示 两方面来展开介绍。


2 建模

建模是一切图形的基础,其他内容的前提,要用代码展示一个图形,首先要有它的几何模型表达。目前在客户端二维图形建模上,Bézier curve(贝塞尔曲线)可以称为 经典 和 主流 并重的数学曲线。


对于贝塞尔曲线来说,最重要的是 起始点、终止点(也称锚点)、控制点。控制点决定了一条路径的弯曲轨迹,根据控制点的个数,贝塞尔曲线被分为:一阶贝塞尔曲线(0 个控制点)、二阶贝塞尔曲线(1 个控制点)、三阶贝塞尔曲线(2 个控制点)、N 阶贝塞尔曲线(n - 1 个控制点)。

2.1 贝塞尔曲线原理

以二阶贝塞尔曲线为例 解释说明:


起始点:P0 ; 控制点:P1 ; 终止点:P2



  1. 连接 P0P1 线 和 P1P2 线。

  2. 在 P0P1 线上找到点 A,在 P1P2 线上找到点 B,使得 P0A/AP1 = P1B/BP2

  3. 连接 AB,在 AB 上找到点 X,X 点满足:AX/XB = P0A/AP1 = P1B/BP2

  4. 找出所有满足公式:AX/XB = P0A/AP1 = P1B/BP2 的 X 点。(从 P0 到 P2 的红色曲线点为所有 X 点的连线)这条由所有 X 点组成的连线 即为 贝塞尔曲线。


二阶贝塞尔曲线 起始点:P0 ; 控制点:P1 ; 终止点:P2



三阶贝塞尔曲线 起始点:P0 ; 控制点:P1、P2; 终止点:P3



四阶贝塞尔曲线 起始点:P0 ; 控制点:P1、P2、P3 ; 终止点:P4


2.2 UIBezierPath 类

系统给我们提供了一个叫做 UIBezierPath 类,用它可以画简单的圆形,椭圆,矩形,圆角矩形,也可以通过添加点去生成任意的图形,还可以简单的创建一条二阶贝塞尔曲线和三阶贝塞尔曲线。我们来了解一下它的常用方法:

2.2.1 初始化方法

// 创建UIBezierPath对象+ (instancetype)bezierPath;// 创建在rect内的矩形+ (instancetype)bezierPathWithRect:(CGRect)rect;// 设定特定的角为圆角的矩形,corners:指定的角为圆角,其他角不变,cornerRadii:圆角的大小+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;// 创建圆弧+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;// 通过已有路径创建路径+ (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;// 创建三次贝塞尔曲线 endPoint:终点 controlPoint1:控制点1 controlPoint2:控制点2- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;- // 创建二次贝塞尔曲线 endPoint:终点 controlPoint:控制点- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
复制代码

2.2.2 使用方法

// 移动到某一点- (void)moveToPoint:(CGPoint)point;// 绘制一条线- (void)addLineToPoint:(CGPoint)point;// 闭合路径,即在终点和起点连一根线- (void)closePath;// 清空路径- (void)removeAllPoints;// 填充- (void)fill;// 描边,路径创建需要描边才能显示出来- (void)stroke;
复制代码

2.2.3 常用属性

// 将UIBezierPath类转换成CGPath,类似于UIColor的CGColor@property(nonatomic) CGPathRef CGPath;// path线的宽度@property(nonatomic) CGFloat lineWidth;// path端点样式@property(nonatomic) CGLineCap lineCapStyle;// 拐角样式@property(nonatomic) CGLineJoin lineJoinStyle;
复制代码

2.2.4 举个栗子🌰

先看效果👇:



代码如下:


- (void)drawRect:(CGRect)rect {
[[UIColor redColor] set];
// 右边第一个图 UIBezierPath* maskPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 100, 100) byRoundingCorners:UIRectCornerTopLeft cornerRadii:CGSizeMake(30, 30)]; maskPath.lineWidth = 20.f; maskPath.lineJoinStyle = kCGLineJoinBevel; [maskPath stroke]; // 中间第二个图 UIBezierPath* maskFillPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(200, 50, 100, 100) byRoundingCorners:UIRectCornerTopLeft cornerRadii:CGSizeMake(30, 30)]; maskFillPath.lineWidth = 20.f; maskFillPath.lineJoinStyle = kCGLineJoinBevel; [maskFillPath fill]; [maskFillPath stroke]; // 右边第三个图 UIBezierPath *maskLinePath = [UIBezierPath bezierPath]; maskLinePath.lineWidth = 20.f; maskLinePath.lineCapStyle = kCGLineCapRound; [maskLinePath moveToPoint:CGPointMake(250.0, 50)]; [maskLinePath addLineToPoint:CGPointMake(300.0, 100.0)]; [maskLinePath stroke];}
复制代码


上图中:


1)图一和图二 唯一的不同是[maskFillPath fill]方法,fill 方法要在封闭的曲线调用。


2)图一和图二 为设定特定的角为圆角的矩形,corners 为 UIRectCornerTopLeft 左上角,cornerRadii 圆角大小为 30,绿色的箭头 表示的设定的这个角。


corners 为下面五种类型typedef NS_OPTIONS(NSUInteger, UIRectCorner) {    UIRectCornerTopLeft     = 1 << 0,    // 左上角    UIRectCornerTopRight    = 1 << 1,    // 右上角    UIRectCornerBottomLeft  = 1 << 2,    // 左下角    UIRectCornerBottomRight = 1 << 3,    // 右下角    UIRectCornerAllCorners  = ~0UL        // 全部};
复制代码


3)图一和图二 黄色的箭头 设置的属性 拐角样式:lineJoinStyle kCGLineJoinBevel(缺角)


lineJoinStyle 为下面三种类型typedef CF_ENUM(int32_t, CGLineJoin) {    kCGLineJoinMiter,    // 尖角    kCGLineJoinRound,    // 圆角    kCGLineJoinBevel    // 缺角};
复制代码


4)图三 白色的箭头 设置的属性 path 端点样式:lineCapStyle kCGLineCapRound(圆形端点)


lineCapStyle 为下面三种类型typedef CF_ENUM(int32_t, CGLineCap) {    kCGLineCapButt,        // 无端点    kCGLineCapRound,    // 圆形端点    kCGLineCapSquare    // 方形端点};
复制代码


有兴趣的 可以试试别的方法属性~

2.3 波浪曲线实现

如何实现 N 阶 波浪式曲线?如何找到 N-1 个对应的控制点?


有两个方法,下图为同数据,方案一 和 方案二 分别所得曲线图。


方案一 为左边(三阶贝塞尔)图 其中 第二条的红点 为数据的位置


方案二 为右边(CatmullRom)图 其中 第二条的红点 为数据的位置



方案一:根据 创建三次贝塞尔曲线 方法 实现波浪曲线


控制点的选取方案不唯一,以下为我选择控制点的方案:


控制点 P1:CGPointMake((PrePonit.x+NowPoint.x)/2, PrePonit.y)


控制点 P2:CGPointMake((PrePonit.x+NowPoint.x)/2, NowPoint.y)


可以根据前一个点 PrePonit 和 现在的点 NowPoint 进行计算 控制点。


主要代码如下:


UIBezierPath *path = [UIBezierPath bezierPath];[path moveToPoint:[self pointAtIndex:0]];NSInteger count = self.points.count;CGPoint PrePonit;
for (NSInteger i = 0; i < count; i++) {
CGPoint NowPoint = [self pointAtIndex:i]; if(i == 0) { PrePonit = NowPoint; } else { // 利用三次曲线 形成波浪曲线 [path addCurveToPoint:point controlPoint1:CGPointMake((PrePonit.x+NowPoint.x)/2, PrePonit.y) controlPoint2:CGPointMake((PrePonit.x+NowPoint.x)/2, NowPoint.y)]; PrePonit = NowPoint; }}return path;
复制代码


方案二:使用 CatmullRom 插值样条。(有兴趣的可以百度一下~这里只简单介绍)


要点分析:


1)给定一组控制点而得到一条曲线,曲线经过给定所有数据点。


2)Catmull-Rom 公式:P(t) = 0.5 * (2*p1 + (p2 - p0) *t + (2*p0 - 5*p1 + 4*p2 - p3)* t * t + (3*p1 - p0 - 3*p2 + p3) * t * t * t);


注:t 为分割的最小粒尺寸,根据 P0 P1 P2 P3 顺序的四个点 求得 P1P2 曲线公式。


主要代码如下:


void getPointsFromBezier(void *info, const CGPathElement *element) {    NSMutableArray *bezierPoints = (__bridge NSMutableArray *)info;    CGPathElementType type = element->type;    CGPoint *points = element->points;
if (type != kCGPathElementCloseSubpath) { [bezierPoints addObject:VALUE(0)]; if ((type != kCGPathElementAddLineToPoint) && (type != kCGPathElementMoveToPoint)) [bezierPoints addObject:VALUE(1)]; } if (type == kCGPathElementAddCurveToPoint) [bezierPoints addObject:VALUE(2)];}
NSArray *pointsFromBezierPath(UIBezierPath *bpath) { NSMutableArray *points = [NSMutableArray array]; // 获取贝塞尔曲线上所有的点 CGPathApply(bpath.CGPath, (__bridge void *)points, getPointsFromBezier); return points;}
- (UIBezierPath*)smoothedPathWithGranularity:(NSInteger)granularity path:(UIBezierPath *)path { NSMutableArray *points = [pointsFromBezierPath(path) mutableCopy];
if (points.count < 4) return [path copy]; [points insertObject:[points objectAtIndex:0] atIndex:0]; [points addObject:[points lastObject]];
UIBezierPath *smoothedPath = [path copy]; [smoothedPath removeAllPoints]; [smoothedPath moveToPoint:POINT(0)];
for (NSUInteger index = 1; index < points.count - 2; index++) { CGPoint p0 = POINT(index - 1); CGPoint p1 = POINT(index); CGPoint p2 = POINT(index + 1); CGPoint p3 = POINT(index + 2);
for (int i = 1; i < granularity; i++) { // granularity 这里按照 20 粒度划分的 float t = (float) i * (1.0f / (float) granularity); float tt = t * t; float ttt = tt * t;
CGPoint pi; // 根据 CatmullRom 公式 根据 P0 P1 P2 P3 获取点的坐标 pi.x = 0.5 * (2*p1.x+(p2.x-p0.x)*t + (2*p0.x-5*p1.x+4*p2.x-p3.x)*tt + (3*p1.x-p0.x-3*p2.x+p3.x)*ttt); pi.y = 0.5 * (2*p1.y+(p2.y-p0.y)*t + (2*p0.y-5*p1.y+4*p2.y-p3.y)*tt + (3*p1.y-p0.y-3*p2.y+p3.y)*ttt); if (pi.x <= self.width) { [smoothedPath addLineToPoint:pi]; } }
if (p2.x <= self.width) { [smoothedPath addLineToPoint:p2]; } }
return smoothedPath;}
复制代码


对比总结:


方案一 控制点的选取比较难,曲线的弯度 也取决于控制点,操作简单,易理解。


方案二 曲线更顺滑,但实现更复杂,不易理解。


这里推荐两个好用的网站:


a 这个网站提供了丰富的曲线类型可供选择,非常直观。


http://easings.net


b 这个网站提供了可视化的修改两个控制点,来生成一条三阶贝塞尔曲线,并切右边还可以看到这条曲线产生的动画会做怎样的速度改变。


http://www.roblaplaca.com/examples/bezierBuilder/#

3 显示

当 layer 与贝塞尔曲线相遇,会发生什么样的神奇反应?

3.1 CALayer

苹果官网注释:“An object that manages image-based content and allows you to perform animations on that content.” 管理基于图像的内容并允许您对该内容执行动画的对象。


CALayer 主要就两方面作用:


1) 管理展示内容


2)内容可执行动画


CALayer 自身有很多情况下自带隐式动画,但是 UIView 的根 Layer 是没有隐式动画的。

3.1.1 常用属性

// 图层大小 支持隐式动画@property CGRect bounds;// 图层位置 支持隐式动画@property CGPoint position;// 在z轴上的位置 支持隐式动画@property CGFloat zPosition;// 沿z轴位置的锚点 支持隐式动画@property CGFloat anchorPointZ;// 锚点 默认在layer的中心点 取值范围(0~1) 支持隐式动画@property CGPoint anchorPoint;// 图层变换 支持隐式动画@property CATransform3D transform;// 图层大小和位置 不支持隐式动画@property CGRect frame;// 是否隐藏 支持隐式动画@property(getter=isHidden) BOOL hidden;// 图层背景是否显示 支持隐式动画@property(getter=isDoubleSided) BOOL doubleSided;// 父图层 支持隐式动画@property(nullable, readonly) CALayer *superlayer;// 子图层 支持隐式动画@property(nullable, copy) NSArray<__kindof CALayer *> *sublayers;// 子图层变换 支持隐式动画@property CATransform3D sublayerTransform;// 图层蒙版 支持隐式动画@property(nullable, strong) __kindof CALayer *mask;// 子图层是否裁切超出父图层的部分,默认为NO@property BOOL masksToBounds;// 图层显示内容 设置layer的contents可以为layer添加显示内容 支持隐式动画@property(nullable, strong) id contents;// 图层显示内容的大小和位置 支持隐式动画@property CGRect contentsRect;// 用于指定层的内容如何在其范围内定位或缩放@property(copy) CALayerContentsGravity contentsGravity;// 是否包含完全不透明内容的布尔值@property(getter=isOpaque) BOOL opaque;// 背景色 支持隐式动画@property(nullable) CGColorRef backgroundColor;// 圆角半径 支持隐式动画@property CGFloat cornerRadius;// 边框宽度 支持隐式动画@property CGFloat borderWidth;// 边框颜色 支持隐式动画@property(nullable) CGColorRef borderColor;// 透明度 支持隐式动画@property float opacity;// 阴影颜色 支持隐式动画@property(nullable) CGColorRef shadowColor;// 阴影透明度 默认为0 需要显示阴影 必须设置值 支持隐式动画@property float shadowOpacity;// 阴影偏移量 支持隐式动画@property CGSize shadowOffset;// 阴影半径 支持隐式动画@property CGFloat shadowRadius;// 阴影形状 支持隐式动画@property(nullable) CGPathRef shadowPath;
复制代码

3.1.2 子类


CALayer 的子类有很多,下面说几个比较常用的。

3.2 CAShapeLayer

苹果官网注释:“A layer that draws a cubic Bezier spline in its coordinate space.” 专门用于绘制贝塞尔曲线的 layer。

3.2.1 看一下它独特的属性:

// path属性是曲线的路径,也是它和贝塞尔曲线紧密连接一个入口,决定了图层上画的是什么形状。@property(nullable) CGPathRef path;// 填充颜色@property(nullable) CGColorRef fillColor;// 曲线 指定哪块区域为内部,内部会被填充颜色@property(copy) CAShapeLayerFillRule fillRule;// 线的颜色@property(nullable) CGColorRef strokeColor;// strokeStart 和 strokeEnd 两者的取值都是0~1,决定贝塞尔曲线的划线百分比@property CGFloat strokeStart;@property CGFloat strokeEnd;// 虚线开始的位置@property CGFloat lineDashPhase;// 虚线设置,数组中奇数位实线长度,偶数位带遍空白长度@property(nullable, copy) NSArray<NSNumber *> *lineDashPattern;// 线的宽度@property CGFloat lineWidth;// 最大斜接长度 只有lineJoin属性为kCALineJoinMiter时miterLimit才有效@property CGFloat miterLimit;// 线端点样式(样式与 贝塞尔曲线的CGLineCap 属性一致)@property(copy) CAShapeLayerLineCap lineCap;// 拐角样式(样式与 贝塞尔曲线的CGLineJoin 属性一致)@property(copy) CAShapeLayerLineJoin lineJoin;
复制代码

3.2.2 举个栗子🌰

使用上面的一些属性,再结合贝塞尔曲线,我们实现了如下一些效果:



其中图五的效果,代码实现如下:


UIBezierPath *maskPath = [UIBezierPath bezierPath];for (NSInteger i = 1; i < 9; i++) {    UIBezierPath *tempPath = [UIBezierPath bezierPathWithRect:CGRectMake(190 - 20 * i, 550 - 10 * i, 40 * i, 20 * i)];    [maskPath appendPath:tempPath];}[maskPath stroke];
// CAShapeLayerCAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];maskLayer.frame = self.view.bounds;maskLayer.path = maskPath.CGPath;maskLayer.lineWidth = 5;maskLayer.strokeColor = [UIColor purpleColor].CGColor;maskLayer.fillRule = kCAFillRuleEvenOdd;maskLayer.fillColor = [UIColor cyanColor].CGColor;maskLayer.strokeStart = 0.2;maskLayer.strokeEnd = 0.5;maskLayer.lineDashPattern = @[@(10), @(10), @(30), @(30)];maskLayer.lineDashPhase = 0;[self.view.layer addSublayer:maskLayer];
复制代码

3.3 CAGradientLayer

苹果官网注释:“A layer that draws a color gradient over its background color, filling the shape of the layer (including rounded corners)” 专门用于在背景色上绘制颜色渐变的图层,填充图层的形状。

3.3.1 看一下它独特的属性:

// colors属性是CAGradientLayer的特殊属性,完美实现几种颜色的过渡。@property(nullable, copy) NSArray *colors;// 定义每个梯度停止的位置。取值范围为0~1递增@property(nullable, copy) NSArray<NSNumber *> *locations;// 决定了变色范围的起始点@property CGPoint startPoint;// 决定了变色范围的结束点@property CGPoint endPoint;// startPoint 和 endPoint两者的连线决定变色的趋势
复制代码

3.3.2 举个栗子🌰

使用上面的一些属性我们实现了如下一些效果:



其中图五的效果,代码实现如下:


CAGradientLayer *gradientLayer = [CAGradientLayer layer];gradientLayer.frame = CGRectMake(20, 450, 150, 150);gradientLayer.locations = @[@(0.2), @(0.5), @(0.6), @(0.8)];gradientLayer.startPoint = CGPointMake(0, 0);gradientLayer.endPoint = CGPointMake(1, 1);gradientLayer.colors = @[(id)[UIColor purpleColor].CGColor, (id)[UIColor greenColor].CGColor, (id)[UIColor orangeColor].CGColor, (id)[UIColor blackColor].CGColor];[self.view.layer addSublayer:gradientLayer];
复制代码

3.4 再举个栗子🌰🌰

当 CAGradientLayer + CAShapeLayer + 贝塞尔曲线 会有什么效果?上代码~


- (void)setupUI {    // 贝塞尔曲线    UIBezierPath *maskPath = [UIBezierPath bezierPath];    [maskPath moveToPoint:CGPointMake(100, 220)];    [maskPath addLineToPoint:CGPointMake(200, 150)];    [maskPath addLineToPoint:CGPointMake(300, 220)];    [maskPath stroke];
UIBezierPath *maskBottomPath = [UIBezierPath bezierPath]; [maskBottomPath moveToPoint:CGPointMake(280, 250)]; [maskBottomPath addCurveToPoint:CGPointMake(120, 250) controlPoint1:CGPointMake(250, 320) controlPoint2:CGPointMake(150, 320)]; [maskBottomPath stroke];
[maskPath appendPath:maskBottomPath];
// CAShapeLayer CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; maskLayer.frame = self.view.bounds; maskLayer.path = maskPath.CGPath; maskLayer.lineWidth = 20; maskLayer.strokeColor = UIColorFromRGB(0xF0F5FF).CGColor; maskLayer.lineCap = kCALineCapRound; maskLayer.lineJoin = kCALineJoinRound; maskLayer.fillColor = [UIColor clearColor].CGColor; maskLayer.strokeStart = 0; maskLayer.strokeEnd = 0; [self.view.layer addSublayer:maskLayer];
// CAGradientLayer NSMutableArray *colorArray = [NSMutableArray new]; for (NSInteger i = 0; i < 6; i++) { [colorArray addObject:[self arc4randomColor]]; }
CAGradientLayer *gradientLayer = [CAGradientLayer layer]; gradientLayer.frame = self.view.bounds; gradientLayer.colors = colorArray; gradientLayer.startPoint = CGPointMake(0, 0.5); gradientLayer.endPoint = CGPointMake(1, 0.5); gradientLayer.mask = maskLayer; [self.view.layer addSublayer:gradientLayer];
// 创建全局并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 创建定时器 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); // 设置定时器,每N秒触发 int64_t intervalInNanoseconds = (int64_t)(0.3 * NSEC_PER_SEC); dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), (uint64_t)intervalInNanoseconds, 0); // 设置定时器处理事件 dispatch_source_set_event_handler(timer, ^{ dispatch_async(dispatch_get_main_queue(), ^{
if (maskLayer.strokeEnd < 0.6) { maskLayer.strokeEnd += 0.4; } else if (maskLayer.strokeEnd < 0.8){ maskLayer.strokeEnd += 0.2; } else if (maskLayer.strokeEnd < 1){ maskLayer.strokeEnd += 0.1; } else { maskLayer.strokeEnd = 1; if (maskLayer.strokeStart < 0.6) { maskLayer.strokeStart += 0.4; } else if (maskLayer.strokeStart < 0.8){ maskLayer.strokeStart += 0.2; } else if (maskLayer.strokeStart < 1){ maskLayer.strokeStart += 0.1; } else { [colorArray removeObjectAtIndex:0]; [colorArray addObject:[self arc4randomColor]]; gradientLayer.colors = colorArray;
maskLayer.strokeStart = 0; maskLayer.strokeEnd = 0; } } }); });
_timer = timer;
// 开启定时器 dispatch_resume(_timer);}
- (id)arc4randomColor { return (id)[UIColor colorWithRed:arc4random()%255/255.f green:arc4random()%255/255.f blue:arc4random()%255/255.f alpha:1].CGColor;}
复制代码


运行结果👇


<https://v.qq.com/x/page/l3146iykm06.html


其他 layer 怎么使用?贝塞尔曲线 + Layer 还可以组合出更多神奇的反应!感兴趣的可以去试试哦~本文仅为抛砖引玉~~


本文转载自公众号贝壳产品技术(ID:beikeTC)。


原文链接


贝塞尔曲线在iOS端的绘图实践


2020-09-15 10:083244

评论

发布
暂无评论
发现更多内容

介绍SDK(C++版)使用方法

矩视智能

深度学习 机器视觉

英特尔以创新边缘AI技术赋能未来智慧城市建设

E科讯

实况窗功能上线,即时掌握活动最新进展

HMS Core

HarmonyOS

用友BIP,为打造世界一流光伏数智灯塔工厂聚势蓄能

用友BIP

光伏产业

生成式 AI 如何释放开发者的生产力?

LigaAI

人工智能 程序员 技术管理 AIGC 研发效能管理

第10期 | GPTSecurity周报

云起无垠

ConceptDraw MINDMAP for mac(思维导图软件) 15.0.0.296中文激活版

mac

苹果mac Windows软件 ConceptDraw MINDMAP 思维导图绘制软件

ConceptDraw PROJECT for Mac(项目管理软件) 14.0.0.302完整激活版

mac

项目管理工具 苹果mac Windows软件 ConceptDraw PROJECT

Mac电脑图像处理AI软件 Topaz Photo AI最新激活版

mac大玩家j

Mac软件 图像处理软件 图像编辑处理

LLM在text2sql上的应用 | 京东云技术团队

京东科技开发者

人工智能 LLM 企业号10月PK榜 text2sql

1024 特别企划|揭秘 StarRocks 社区背后的神秘力量(内涵福利)

StarRocks

开源社区 StarRocks

万能音视频转换器Permute 3最新中文版

胖墩儿不胖y

Mac软件 音频处理工具 音频格式转换器

语音识别技术在医疗健康领域的应用与挑战

来自四九城儿

数智化浪潮中,广电行业收入管理流程该如何重构?

用友BIP

广电行业

装备修理行业数智化转型之道

用友BIP

装备修理行业

SpringBoot自动配置原理解析 | 京东物流技术团队

京东科技开发者

spring-boot 自动配置 企业号10月PK榜

开放原子开源基金会理事长孙文龙一行赴拓维信息参观交流

开放原子开源基金会

开源

语雀服务宕机带来的稳定性思考

老张

高可用 SRE 稳定性保障

支付宝权限问题大全|一文搞定,持续更新

盐焗代码虾

支付宝 经验分享 支付宝权限

用友全球司库十问(五)| 企业如何主动管理资金流动性?

用友BIP

全球司库 流动性管理

利用观测云的 RUM 追踪和分析一个 VIP 用户的旅程

观测云

可观测性 用户体验分析

Java类加载机制详解 | 京东云技术团队

京东科技开发者

Java spi 类加载机制 企业号10月PK榜

ETL工具与数据处理的关系

RestCloud

数据处理 ETL

用友BIP智能分析资产包正式发布,助力企业智能化决策!

用友BIP

智能分析

零代码开发、可视化界面!飞桨AI Studio星河社区带你玩转Prompt应用

飞桨PaddlePaddle

程序员 开发者 插件开发 Prompt

开放原子开源基金会联合主办的2023 CCF中国开源大会正式开幕

开放原子开源基金会

开源 CCF

实测亚马逊 AI 编程助手 Amazon CodeWhisperer

全栈若城

去中心化应用程序(DAPPS)开发

西安链酷科技

区块链 源码 dapp 去中心化 交易所搭建

Ready to go: IPQ4029/IPQ4019 with IPQ8072- Connect more and enjoy faster

wifi6-yiyi

wifi IPQ4019 IPQ8072 ipq4029

HarmonyOS SDK,赋能开发者实现更具象、个性化开发诉求

HMS Core

鸿蒙 HarmonyOS

2023 CCF中国开源大会「开放科学——引领未来科学研究发展的新范式分论坛」成功举办

开放原子开源基金会

贝塞尔曲线在iOS端的绘图实践_大数据_孙齐_InfoQ精选文章