當前位置:首頁 » 操作系統 » canvas演算法

canvas演算法

發布時間: 2022-11-21 08:54:05

Ⅰ canvas的drawimage方法沒法繪制動態gif圖

1.用img標簽,然後浮在canvas上面,canvas和html結合作圖才是王道。
2.讀取gif的二進制數據,然後用一些演算法解析出來,然後一楨一幀畫出來,這個的確是有的,你可以在google搜一下,有一個框架,不過這種方法不太靠譜。就是玩的。

Ⅱ gif 怎麼用Canvas 繪制 GIF 動畫圖

想讓gif可控,就必須進行拆幀,比較好的軟體推薦texturepack,固然也有在線的
gif
to
animation
目前還是只是個demo,還沒寫完。效果是這樣的:
auto
play
分別為偏移背景,img浮動偏移,canvas渲染。

Ⅲ 怎麼通過演算法大量生成圖片

首先需要製作一個nodejs小程序,然後通過該程序開始運行演算法,通過小程序的建模生成圖片,這樣就可以通過演算法生成大量的圖片。首先,先介紹廣告創意圖片的整體生成流程:用戶先提供必要的信息,如廣告標題、促銷信息、廣告商品圖等,然後通過介面發送做圖程序。

做圖程序是一個nodejs服務,nodejs會啟動一個後端的headless模式的chrome,我們使用的是puppeteer,然後puppeteer啟動真正的做圖程序。

做圖主程序使用js和canvas進行編寫,js根據傳入的參數,計算出最合適的模板,然後進行配色、配置背景圖、裝飾文本、裝飾商品圖等各種繁瑣細節的操作,最終在HTML里通過canvas渲染出所有的創意圖片。

最後再通過nodejs,做圖完成,nodejs再調用puppeteer計算位置關系等進行截圖,生成最終的圖片。

Ⅳ 如何用Canvas繪制多種圖形

HTML5 的標准已經出來好久了,但是似乎其中的 Canvas 現在並沒有在太多的地方用到。一個很重要的原因是,Canvas 的標准還沒有完全確定,不適合大規模用在生產環境。但是,Canvas 的優點也是很明顯的,例如在繪制含有大量元素的圖表的時候,SVG 往往因為性能問題而無法勝任,例如我見過的一次技術分享會的抽獎環節,雖然效果比較炫,但因為每個頭像都是 DOM,利用 CSS3 控制的動畫,導致了性能非常低下。此外,隨著硬體性能的提高,視頻截圖、圖像處理等功能也逐漸可以在網頁上實現了,大多數網站用的是 Flash,但是 Flash 在 Mac 電腦上性能不高,還需要學一些額外的知識。Canvas 則是直接使用 javaScript 來進行繪圖,對 Mac 友好,所以不失為 Flash 的一個繼承者。

使用 Canvas
說了這么多,Canvas 究竟是個啥?
英文中 Canvas 的意思是「畫布」,不過這里說的 Canvas 是 HTML5 中新出的一個元素,開發者可以在上面繪制一系列圖形。Canvas 在 HTML 文件中的寫法很簡單:
<canvas id="canvas" width="寬度" height="高度"></canvas>

其中 id 屬性是所有 HTML 元素都可以用的,Canvas 自帶的屬性只有後面兩個(分別控制寬度、高度),沒有其它的了。至於兼容性,CanIUse 上面寫了,基礎的功能目前用戶使用的 90% 的瀏覽器都支持,所以大部分情況下還是可以放心使用的。

注意,一定要使用 Canvas 自帶的 width 和 height 屬性,不要使用 CSS 來控制,因為 CSS 控制會導致 Canvas 變形。可以試著與 PhptpShop 對比一下,後者是改變「圖像大小」,前者才是正確的改變「畫布大小」。例如下圖是三張圖片的橫向拼接:最左邊的黑框中是大小為 50px * 50px 的原圖;中間是改變了圖像大小為 100px * 100px 的效果,圖像變得模糊,但是對於圖像本身來說坐標范圍並沒有變大;最右邊才是正確的 100px * 100px 的 Canvas。

Canvas 絕大部分的繪圖方法都與 <canvas> 標簽無關,需要使用 JavaScript 對其進行操作,這就是所謂的 Canvas API。
我們首先獲取到這個元素:
var canvas = document.getElementById('canvas');

然後通過一個方法來獲取可以調用一切 Canvas API 的入口:
var ctx = canvas.getContext('2d');

看到 2d 是不是很激動地聯想到有沒有 3d 呢?沒有 3d 的寫法,不過如果想要開啟 3D 世界的大門,則可以寫 canvas.getContext('webgl')。然而 WebGL 是基於 OpenGL ES 2.0 的一套標准,與本文是徹徹底底的兩條路,因此這里就不討論了。
Canvas 中的基本概念
坐標
與數學上常見的笛卡爾坐標系不太相同,Canvas 的坐標系是計算機中常見的坐標系,它長這樣:

畫布的最左上角是 (0,0),往右 x 增大,往下 y 增大,而且 x 和 y 都是整數(就算在計算過程中不是整數,在繪制的時候也會當作整數處理),單位是像素。
繪圖
帶大家懷舊一下。不知道有多少同學小時候玩過 logo 語言,在裡面你可以控制一隻小海龜在一塊板子上行走、畫畫、提筆、落筆。Canvas 中也一樣,你需要控制一隻畫筆的移動和繪制。然而 Canvas 更高級一些,你可以直接利用一些函數來畫圖,不用去控制那隻畫筆的位置。
Canvas 中的基本圖形
通過上文定義的 ctx 變數可以干許多有意思的事情,我們先看看如何繪制一些基本圖形。
線條
我們指定畫筆移動到某一點,然後告訴畫筆需要從當前這一點畫到另一點。我們可以讓畫筆多次移動、繪制,最後統一輸出到屏幕上。例子如下:
ctx.moveTo(10, 10);
ctx.lineTo(150, 50);
ctx.lineTo(10, 50);
ctx.moveTo(10, 20);
ctx.lineTo(40, 70);
ctx.stroke();

上面的代碼中,lineTo 是產生線條用的函數,執行完之後畫筆就移到了線條的終點。需要注意的是,線條此時並沒有顯示在屏幕上,必須調用 stroke 才會顯示。這樣設計是有道理的,因為向屏幕上輸出內容需要耗費大量的資源,我們完全可以先攢夠一波 lineTo,最後用 stroke 放一個大的。
路徑
繪制路徑非常簡單,只需要先告訴 ctx 一聲「我要開始畫路徑了」,然後通過各種方法(例如 lineTo)繪制路徑。如果需要畫一個封閉路徑,那就最後告訴 ctx一聲:「我畫完了,你把它封閉起來吧。」當然,不要忘記利用 stroke 輸出到屏幕上。
一個簡單的例子:
ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(150, 50);
ctx.lineTo(10, 50);
ctx.closePath();
ctx.stroke();

如果我不想只描繪路徑線條,而是想填充整個路徑呢?可以將最後一行的 stroke 改成 fill,這樣就跟使用了畫圖中的油漆桶一樣,封閉路徑裡面的內容就都被填充上顏色了:
ctx.fill();

弧 / 圓形
繪制弧的函數參數比較多:
ctx.arc(圓心 x 坐標, 圓心 y 坐標, 半徑, 起始角度, 終止角度, 是否為逆時針);

注意,在 Canvas 的坐標系中,角的一邊是以圓心為中心的水平向右的直線。角度單位均為弧度。例如下圖,確定了圓心、起始角度(圖中標明的銳角)和終止角度(圖中標明的鈍角),方向為逆時針,於是就有了這么一個弧。如果方向為順時針,那麼就會是一個跟它互補的、非常非常大的弧……

所以如果轉了 2π 圈之後,弧就成了圓形,因此也可以使用繪制弧的方式來繪制圓形:
ctx.beginPath();
ctx.arc(圓心 x 坐標, 圓心 y 坐標, 半徑, 0, Math.PI * 2, true);
ctx.closePath();

最後一個參數隨便填(當然也可以不填),因為不管是順時針還是逆時針,轉了 2π 圈之後都是一個圓。
矩形
如果只是想繪制一個橫平豎直的矩形,可以使用下面的兩個方法:
// 只描邊
ctx.strokeRect(左上角 x 坐標, 左上角 y 坐標, 寬度, 高度);
// 只填充
ctx.fillRect(左上角 x 坐標, 左上角 y 坐標, 寬度, 高度);

線條樣式 / 填充樣式
之前繪制的所有圖形都是黑色的,但是 Canvas 肯定不止這么一種顏色(不然標準的制定者會被噴的很慘)。事實上,Canvas 可以單獨設置線條樣式和填充樣式,分別使用的是 strokeStyle 和 fillStyle。可能的值有三種:純色、漸變、圖像。既然線條樣式與填充樣式的使用方法相同,那麼下面統一以填充樣式為例。如果想設置線條樣式,直接將所有的 fillStyle改成 strokeStyle 即可,裡面的參數都不變。
/* 純色填充 */
// 普通的顏色
ctx.fillStyle = '#0000ff';
// 帶有透明度的顏色
ctx.fillStyle = 'rgba(64, 0, 127, 0.5)';

/* 漸變填充 */
// 設置漸變的尺寸(參數分別為起始點的 x 和 y、終止點的 x 和 y)
var gradient = ctx.createLinearGradient(0, 0, 170, 0);
// 設置過渡色,第一個參數是漸變的位置,第二個參數是顏色
gradient.addColorStop(0, 'magenta');
gradient.addColorStop(0.5, 'blue');
gradient.addColorStop(1.0, 'red');
// 設置填充樣式
ctx.fillStyle = gradient;

/* 圖片填充 */
// 創建圖片
var image = new Image;
image.src = '/path/to/image.png';
// 創建圖片筆觸,可以指定圖片的平鋪方式,這里是橫向平鋪
var pattern = ctx.createPattern(image, 'repeat-x');
// 設置筆觸填充
ctx.fillStyle = pattern;

關於漸變,除了代碼中提到的線性漸變以外,還有 createRadialGradient,也就是徑向漸變。
設置完填充樣式之後,就可以使用 fill 來填充啦!如果設置的是線條樣式,那麼就可以使用 stroke 來描邊。
當然,對於線條樣式,還有個額外的方法叫 lineWidth 可以用來控制線條的寬度。
文字
要想在畫布上畫文字,首先需要知道所使用的字體和字型大小:
ctx.font = '30px Verdana';

然後就可以通過 strokeText 或者 fillText 來對字體描邊或者填充字體。
ctx.strokeText("Hello Coding!", 23, 33);
ctx.fillText("Hello Coding!", 23, 66);

圖片
在 Canvas 中繪制圖片有三種方法:
// 指定繪制位置
ctx.drawImage(image, x, y);
// 指定繪制位置和圖像寬高
ctx.drawImage(image, x, y, width, height);
// 指定剪裁區域、繪制位置和圖像寬高
ctx.drawImage(image, sx, sy, swidth, sheight, x, y, width, height);

參數的含義依次如下:
image: 要使用的 Image、Canvas 或 Video
sx: 可選,開始剪切的 x 坐標
sy: 可選,開始剪切的 y 坐標
swidth: 可選,被剪切圖像的寬度
sheight: 可選,被剪切圖像的高度
x: 在畫布上放置圖像的 x 坐標
y: 在畫布上放置圖像的 y 坐標
width: 可選,要使用的圖像的寬度
height: 可選,要使用的圖像的高度

畫布設置
細心的同學可能會發現,剛才有些屬性是直接對 ctx 變數做設置,例如 ctx.lineWidth,只要設置了它,那麼後續畫出來的線條全都是這么個寬度。
其實,Canvas 的設置項還有許多,例如我們可以直接移動畫布、旋轉畫布、設置全局的繪制透明度等等。這些設置還可以隨時保存和恢復。
要注意的一點是,所有已經畫在畫布上的東西,是已經定死了的,不管之後再次進行任何設置都不會再改變。這個很像 Windows 下的畫圖程序。
廢話不多說,直接上代碼:
// 移動畫布,其實就是移動坐標系
ctx.translate(往右移動的量, 往下移動的量);
// 旋轉畫布,旋轉中心為坐標系原點
ctx.rotate(順時針旋轉的角度);
// 以坐標系原點為中心縮放畫布
ctx.scale(橫向放大倍數, 縱向放大倍數);
// 設置繪制透明度,如果 fillStyle 等屬性設置了透明度則會疊加
ctx.globalAlpha(零到一的小數);
// 設置全局組合操作
ctx.globalCompositeOperation = 'lighter';
// 保存當前設置
ctx.save();
// 恢復上次保存的設置
ctx.restore();

移動、旋轉、縮放其實就是在控制繪圖的坐標系,如果你在調用這三個方法的時候,腦子里時刻有一個帶刻度的坐標系,效果會非常好。
事實上,Canvas 的坐標變換遵循計算機圖形學的知識:變換矩陣。簡單來說,一個坐標可以看成是一個矩陣,坐標所對應的矩陣乘上變換矩陣就可以實現對坐標的變換。為了提升計算的效率,可以先計算出幾種變換復合之後的變換矩陣,然後直接通過 transform 函數對當前坐標系進行變換,或者通過 setTransform 函數將坐標系重置為初始狀態後再進行變換。至於變換矩陣的內容,對於本文來說就有些超綱了。
全局組合操作有點像 PhotoShop 裡面的「混合選項」,具體的實現方式還沒有完全確定,目前常見瀏覽器都統一了的實現方式有:source-over、source-atop、destination-over、destination-out、lighter、xor。具體的行為可以看 Mozilla 官方文檔,但是由於標准還未完全確定,因此其它瀏覽器不保證所有的行為都跟 Mozilla 的標准一致。一般來說,比較常見的是 source-over 和 lighter 兩種,這兩種的標准在瀏覽器界也算是無可爭議的。
至於保存和恢復設置就有點好玩了,首先需要了解一個叫「棧」的東西。
棧是一個一維數組,規定只能從一個方向操作。棧一開始是空的,我們可以從這個方嚮往數組 push 元素,也只能從這個方向把最後一個元素(棧頂元素)pop 出來,除此以外沒有任何多餘的操作。當然,pop 的次數不能多於 push 的次數,因為 pop 到棧底的時候棧里就已經沒有元素了,此時再 pop 是沒有意義的。棧的用處有很多,例如括弧匹配、表達式求值、深度優先搜索,甚至絕大部分語言的函數調用都要用到棧。
每次我們調用 save 函數,實際上是將當前的全局設置 push 到了一個專門棧上,每次調用 restore 函數的時候將最後一次保存的內容 pop 出來並用它覆蓋當前的全局設置,這樣棧頂就是最近一次保存的內容了。保存和恢復在某些情況下很好用,例如我需要畫一個歪著的圖形,然後繼續畫正著的圖形,這樣就可以先調用 save,然後調用 rotate,畫完圖形之後再 restore 回來,繼續畫其它的圖形。
其實 Canvas 還有許多方法,例如 toDataURL 直接將當前畫布上的內容轉換為十六進制的 data-url,getImageData直接將圖像轉換為 RGBA 數組以供圖像處理演算法使用,putImageData 將 RGBA 數組轉換為圖片顯示在畫布上等等。如果配上 JavaScript 的定時更新(最好用 requestAnimationFrame 而不是 setInterval),則可以產生動畫效果。網上還有許多 Canvas 的庫,可以讓程序員更簡便地基於 Canvas 編寫屬於自己的特效或功能。在這兒我想說一句話:大家的腦洞有多大,Canvas 的能力就有多強~

Ⅳ canvas如何畫這樣的三角形

1:簡單的辦法,畫一個3角,填充紅,畫一個圓,填充背景色,圓位置移動到想要的位置就好,這個java或html5好寫點。canvas大多也就這兩種語言才有吧。
2:用函數,這個好難,不過用微積分演算法也可以實現,點的位置固定好,4段函數,3個線型,一個圓。

Ⅵ android獲取surfaceview裡面的每一幀

屏幕的顯示機制和幀動畫類似,也是一幀一幀的連環畫,只不過刷新頻率很高,感覺像連續的。為了顯示一幀,需要經歷計算和渲染兩個過程,CPU 先計算出這一幀的圖像數據並寫入內存,然後調用 OpenGL 命令將內存中數據渲染成圖像存放在 GPU Buffer 中,顯示設備每隔一定時間從 Buffer 中獲取圖像並顯示。
上述過程中的計算,對於View來說,就好比在主線程遍歷 View樹 以決定視圖畫多大(measure),畫在哪(layout),畫些啥(draw),計算結果存放在內存中,SurfaceFlinger 會調用 OpenGL 命令將內存中的數據渲染成圖像存放在 GPU Buffer 中。每隔16.6ms,顯示器從 Buffer 中取出幀並顯示。所以自定義 View 可以通過重載onMeasure()、onLayout()、onDraw()來定義幀內容,但不能定義幀刷新頻率。
SurfaceView可以突破這個限制。而且它可以將計算幀數據放到獨立的線程中進行。下面是自定義SurfaceView的模版代碼:
public abstract class BaseSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
public static final int DEFAULT_FRAME_DURATION_MILLISECOND = 50;
//用於計算幀數據的線程
private HandlerThread handlerThread;
private Handler handler;
//幀刷新頻率
private int frameDuration = DEFAULT_FRAME_DURATION_MILLISECOND;
//用於繪制幀的畫布
private Canvas canvas;
private boolean isAlive;
public BaseSurfaceView(Context context) {
super(context);
init();
}
protected void init() {
getHolder().addCallback(this);
//設置透明背景,否則SurfaceView背景是黑的
setBackgroundTransparent();
}
private void setBackgroundTransparent() {
getHolder().setFormat(PixelFormat.TRANSLUCENT);
setZOrderOnTop(true);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isAlive = true;
startDrawThread();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
stopDrawThread();
isAlive = false;
}
//停止幀繪制線程
private void stopDrawThread() {
handlerThread.quit();
handler = null;
}
//啟動幀繪制線程
private void startDrawThread() {
handlerThread = new HandlerThread(「SurfaceViewThread」);
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
handler.post(new DrawRunnable());
}
private class DrawRunnable implements Runnable {
@Override
public void run() {
if (!isAlive) {
return;
}
try {
//1.獲取畫布
canvas = getHolder().lockCanvas();
//2.繪制一幀
onFrameDraw(canvas);
} catch (Exception e) {
e.printStackTrace();
} finally {
//3.將幀數據提交
getHolder().unlockCanvasAndPost(canvas);
//4.一幀繪制結束
onFrameDrawFinish();
}
//不停的將自己推送到繪制線程的消息隊列以實現幀刷新
handler.postDelayed(this, frameDuration);
}
}
protected abstract void onFrameDrawFinish();
protected abstract void onFrameDraw(Canvas canvas);
}
用HandlerThread作為獨立幀繪制線程,好處是可以通過與其綁定的Handler方便地實現「每隔一段時間刷新」,而且在Surface被銷毀的時候可以方便的調用HandlerThread.quit()來結束線程執行的邏輯。
DrawRunnable.run()運用模版方法模式定義了繪制演算法框架,其中幀繪制邏輯的具體實現被定義成兩個抽象方法,推遲到子類中實現,因為繪制的東西是多樣的,對於本文來說,繪制的就是一張張圖片,所以新建BaseSurfaceView的子類FrameSurfaceView:
逐幀解析 & 及時回收
public class FrameSurfaceView extends BaseSurfaceView {
public static final int INVALID_BITMAP_INDEX = Integer.MAX_VALUE;
private List bitmaps = new ArrayList<>();
//幀圖片
private Bitmap frameBitmap;
//幀索引
private int bitmapIndex = INVALID_BITMAP_INDEX;
private Paint paint = new Paint();
private BitmapFactory.Options options = new BitmapFactory.Options();
//幀圖片原始大小
private Rect srcRect;
//幀圖片目標大小
private Rect dstRect = new Rect();
private int defaultWidth;
private int defaultHeight;
public void setDuration(int ration) {
int frameDuration = ration / bitmaps.size();
setFrameDuration(frameDuration);
}
public void setBitmaps(List bitmaps) {
if (bitmaps == null || bitmaps.size() == 0) {
return;
}
this.bitmaps = bitmaps;
//默認情況下,計算第一幀圖片的原始大小
getBitmapDimension(bitmaps.get(0));
}
private void getBitmapDimension(Integer integer) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(this.getResources(), integer, options);
defaultWidth = options.outWidth;
defaultHeight = options.outHeight;
srcRect = new Rec

Ⅶ canvas怎樣畫一個抽獎的圓盤

主要的思路: 根據弧度畫扇形 演算法求某個點是否在不規則形狀內。「放射」演算法

Ⅷ Canvas的drawText繪制文本自動換行(支持設置顯示最大行數)

使用Canvas的drawText繪制文本是不會自動換行的,即使一個很長很長的字元串,drawText也只顯示一行,超出部分被隱藏在屏幕之外。可以逐個計算每個字元的寬度,通過一定的演算法將字元串分割成多個部分,然後分別調用drawText一部分一部分的顯示, 但是這種顯示效率會很低。

StaticLayout是android中處理文字換行的一個工具類,StaticLayout已經實現了文本繪制換行處理

StaticLayout的公開的構造函數有三個

以11個參數的構造方法為例,各個參數的意義如下:

通過查看源碼,我們知道,11個參數的構造方法調用的是13個參數的構造方法,但是這個方法是@hide 的,我們是沒有調用的,外部是無法知道的,但是我們可以通過反射獲取,對反射不熟悉的可以參考這一片文章 你必須掌的握反射用法
我們可以看到最後一個參數,可以設置顯示的最大行數,默認是Integer.MAX_VALUE
也就是說,利用這個可以設置這個屬性

Ⅸ Rgb深色過渡到淺色的演算法是什麼我想用h5的canvas做一個煙花效果,有很多顏色,無論哪一種顏

rgba 4個數 用定時器逐漸變化值

Ⅹ 關於canvas在連接多點畫線時使用曲線優化的一點心得

canvas將多個點連接成線,最主要還是用於使用滑鼠繪畫之類的用途,但是我們往往會發現使用這些點連接起來的線非常不規整,很不自然
所以大多數人想到優化這一點的方法應該就是將簡單的點與點的直線連接改為帶一定曲度的曲線

帶著目的我在網上查找相應的文章然後找到了這個 博客
但是這個博客不早知道是沒講清楚還是寫錯了,你是沒辦法直接使用他的方法的,裡面有些參數不清楚,而且因為太久的緣故裡面的鏈接都失效了
所以我在網上搜索了裡面提供的關鍵字: 貝塞爾曲線控制點確定的方法.doc 網路文庫里有

根據裡面的秒速完善了方法

第一個點和最後兩個點的演算法文檔裡面有說明我就不多說了

根據方法使用曲線畫線方法劃線

這里將直線改為曲線算成功了,但是我發現直接使用滑鼠畫的線依然很難看不自熱,這是因為滑鼠劃線點過於密集的原因,可以在劃線時間隔曲線將圖形模糊處理

老實說感覺還是畫出來的線比原來是好點,但是還是不自然的樣子

熱點內容
砸百鬼腳本 發布:2025-05-18 03:53:34 瀏覽:934
安卓手機如何拍視頻和蘋果一樣 發布:2025-05-18 03:40:47 瀏覽:727
為什麼安卓手機連不上蘋果7熱點 發布:2025-05-18 03:40:13 瀏覽:797
網卡訪問 發布:2025-05-18 03:35:04 瀏覽:504
接收和發送伺服器地址 發布:2025-05-18 03:33:48 瀏覽:366
ef資料庫查詢數據 發布:2025-05-18 03:29:36 瀏覽:668
百度雲下載文件夾 發布:2025-05-18 03:17:33 瀏覽:674
php雲開發 發布:2025-05-18 03:12:41 瀏覽:447
sql語句顯示表 發布:2025-05-18 03:12:30 瀏覽:690
資料庫系統的例子 發布:2025-05-18 03:02:42 瀏覽:191