Cairo编程
一、簡介
cairo 是一個免費的矢量繪圖軟件庫,它可以繪制多種輸出格式。cairo 支持許多平臺,包括 Linux、BSD、Microsoft? Windows? 和 OSX(BeOS 和 OS2 后端也正在開發)。Linux 繪圖可以通過 X Window 系統、Quartz、圖像緩沖格式或 OpenGL 上下文來實現。另外,cairo 還支持生成 PostScript 或 PDF 輸出,從而產生高質量的打印結果。在理想情況下,cairo 的用戶可以在打印機和屏幕上獲得非常接近的輸出效果。
專業術語
1、環境 (Context)
使用 Cairo 繪圖,必須要首先創建 Cairo 環境 (Context)。Cairo 環境保存著所有的圖形狀態參數,這些參數描述了圖形的構成,譬如線條寬度、顏色、要繪制的外觀 (Surface) 以及其它一些信息。Cairo 環境允許真正的繪圖函數使用很少的一部分參數,以此提高接口的易用性。調用 gdk_cairo_create () 函數可為所繪制的圖形創建一個 Cairo 環境。
cairo_t * cr; cr = gdk_cairo_create (widget->window);
這兩行代碼創建了一個 Cairo 環境,并且這個 Cairo 環境是關聯到 GdkDrawable 對象上的。cairo_t 結構體包含了當前渲染設備的狀態,也包含了所繪制圖形的坐標。從技術上來講,cairo_t 就是所謂的 Cairo 環境。
Cairo 所有的繪圖函數都要去操作 cairo_t 對象。一個 Cairo 環境可以被關聯到一種特定的外觀,譬如 pdf、svg、png、GdkDrawable 等。
GDK 沒有對 Cairo API 進行封裝,它只允許創建一個可基于 GdkDrawable 對象繪制圖形的 Cairo 環境。有一些 GDK 函數可以將 GDK 的矩形或填充區域轉換為 Cairo Path (路徑),然后使用 Cairo 繪圖與渲染。
2、路徑 (Path)
一條 Path(路徑)通常是由一條或多條首尾相接的直線段構成的,也可以由直線段與曲線段構成。路徑可分為 Open(開放)類型與 Closed(閉合)類型,前者的首尾端點不重合,后者的首尾端點重合。
在 Cairo 中,繪圖要從一條空路徑開始,首先定義一條路徑,然后通過繪制/填充操作使之可見。要注意的是,每次調用 cairo_stroke () 或 cairo_fill () 函數之后,路徑會被清空,不得不再定義新的路徑。
一條路徑可由一些子路徑構成。
3、源 (Source)
源好比繪圖中所使用的畫筆/顏料,使用它來繪制/填充圖形輪廓。有 4 種基本的源:color、gradient、pattern 與 image。
4、外觀 (Surface)
Surface 就是要繪制圖形的最終體現形式,譬如可使用 PDF 或 PostScript 外觀實現文本內容的渲染,或者使用 Xlib、Win32 外觀實現屏幕繪圖。
Cairo 具體有那些外觀類型,可參考其定義:
typedef enum _cairo_surface_type {
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_SURFACE_TYPE_PDF,
CAIRO_SURFACE_TYPE_PS,
CAIRO_SURFACE_TYPE_XLIB,
CAIRO_SURFACE_TYPE_XCB,
CAIRO_SURFACE_TYPE_GLITZ,
CAIRO_SURFACE_TYPE_QUARTZ,
CAIRO_SURFACE_TYPE_WIN32,
CAIRO_SURFACE_TYPE_BEOS,
CAIRO_SURFACE_TYPE_DIRECTFB,
CAIRO_SURFACE_TYPE_SVG,
CAIRO_SURFACE_TYPE_OS2
} cairo_surface_type_t;
5、蒙板 (Mask)
在源作用于外觀之前,可對其實現過濾,蒙板 (mask) 即是過濾器。蒙板決定哪些源可被顯示。蒙板不透明的部分允許復制源至外觀,蒙板透明的部分則禁止復制源至外觀。、
6、圖案 (Pattern)
圖案表示被繪制到外觀的源。在 Cairo 中,圖案是一種可以讀取的內容,可用作繪圖操作的源或蒙板。圖案可以是純色模式、基于外觀的模式以及漸變模式。
二、編譯與安裝
參考:http://cairographics.org/download/
執行以下命令,即可完成安裝
sudo yum install cairo-devel
如下圖
三、編程
程序1:用于生成 PNG 圖像
#include <cairo.h>
int main (int argc, char *argv[])
{
cairo_surface_t *surface;
cairo_t *cr;
surface =cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400, 800);
cr = cairo_create (surface);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_rectangle(cr,0,0,400,800);
cairo_fill(cr);
cairo_select_font_face (cr, "Adobe Heiti Std", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 30.0);
cairo_move_to (cr, 100, 400);
cairo_set_source_rgb (cr, 0, 1, 0);
cairo_show_text (cr, "I Love Chinese !");
cairo_surface_write_to_png (surface, "image.png");
cairo_destroy (cr);
cairo_surface_destroy (surface);
return 0;
}
編譯
gcc -o example-1.o example-1.c -lcairo -I/usr/include/cairo
運行
程序2:用于生成 PDF 圖像
#include <cairo.h>
#include <cairo-pdf.h>
int main (int argc, char *argv[])
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_pdf_surface_create ("pdffile.pdf", 20, 40);
cr = cairo_create (surface);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_rectangle(cr,0,0,20,40);
cairo_fill(cr);
cairo_select_font_face (cr, "WenQuanYi Zen Hei", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 5);
cairo_move_to (cr, 0, 20);
cairo_set_source_rgb (cr, 0, 1, 0);
cairo_show_text (cr, "熱愛編程");
cairo_show_page (cr);
cairo_destroy (cr);
cairo_surface_destroy (surface);
return 0;
}
編譯
gcc -o example-2.o example-2.c -lcairo -I/usr/include/cairo
運行
程序3:用于生成 SVG 圖像
#include <cairo.h>
#include <cairo-svg.h>
int main (int argc, char *argv[])
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_svg_surface_create ("svgfile.svg", 20, 40);
cr = cairo_create (surface);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_rectangle(cr,0,0,20,40);
cairo_fill(cr);
cairo_select_font_face (cr, "WenQuanYi Zen Hei", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 5);
cairo_move_to (cr, 0, 20);
cairo_set_source_rgb (cr, 0, 1, 0);
cairo_show_text (cr, "熱愛編程");
cairo_destroy (cr);
cairo_surface_destroy (surface);
return 0;
}
編譯
gcc -o example-3.o example-3.c -lcairo -I/usr/include/cairo
運行
程序4:在 GTK 窗口中使用 Cairo 繪制圖形
要在 GTK+ 窗口中繪制 Cairo 圖形,可以使用 GtkDrawingArea widget 或者更為簡單的 GtkWindow widget,本例選擇 GtkWindow 。由 GtkWindow widget 對 expose-event 信號處理后,默認要重新繪制窗口背景,這會將我們在 on_expose_event () 函數中定義的 Cairo 圖形覆蓋掉,因此需要調用 gtk_widget_set_app_paintable () 函數通知 GTK+ 不要這么干。如果是在 GtkDrawingArea widget 中繪制 Cairo 圖形,則可省區這一步。
#include <cairo.h>
#include <gtk/gtk.h>
static gboolean on_expose_event (GtkWidget * widget, GdkEventExpose * event, gpointer data)
{
cairo_t *cr;
cr = gdk_cairo_create (widget->window);
cairo_set_source_rgb (cr, 0.627, 0, 0);
cairo_select_font_face (cr, "WenQuanYi Zen Hei", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 24.0);
cairo_move_to (cr, 10.0, 34.0);
cairo_show_text (cr, "編程藝術");
cairo_destroy (cr);
return FALSE;
}
int main (int argc, char *argv[])
{
GtkWidget *window;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "expose-event", G_CALLBACK (on_expose_event), NULL);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size (GTK_WINDOW (window), 320, 48);
gtk_widget_set_app_paintable (window, TRUE);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
編譯
gcc -o example-5.o example-5.c -lcairo -I/usr/include/cairo `pkg-config --cflags --libs gtk+-2.0`
運行
程序5:繪制動態圖形
#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>
cairo_surface_t *image;
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr;
static gint pos_x = 128;
static gint pos_y = 128;
gint radius = 40;
static gint delta[] = { 3, 3 };
cr = gdk_cairo_create(widget->window);
gint width, height;
gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
if (pos_x < 0 + radius)
{
delta[0] = rand() % 4 + 5;
}
else if (pos_x > width - radius)
{
delta[0] = -(rand() % 4 + 5);
}
if (pos_y < 0 + radius)
{
delta[1] = rand() % 4 + 5;
}
else if (pos_y > height - radius)
{
delta[1] = -(rand() % 4 + 5);
}
pos_x += delta[0];
pos_y += delta[1];
cairo_set_source_surface(cr, image, 1, 1);
cairo_arc(cr, pos_x, pos_y, radius, 0, 2*M_PI);
cairo_clip(cr);
cairo_paint(cr);
cairo_destroy(cr);
return FALSE;
}
static gboolean time_handler (GtkWidget *widget)
{
if (widget->window == NULL) return FALSE;
gtk_widget_queue_draw(widget);
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
gint width, height;
image = cairo_image_surface_create_from_png("turnacastle.png");
width = cairo_image_surface_get_width(image);
height = cairo_image_surface_get_height(image);
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(on_expose_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), width+2, height+2);
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
g_timeout_add(100, (GSourceFunc) time_handler, (gpointer) window);
gtk_main();
cairo_surface_destroy(image);
return 0;
}
編譯
gcc -o example-6.o example-6.c -lcairo -I/usr/include/cairo `pkg-config --cflags --libs gtk+-2.0`
運行
程序6:相交區域處理示例
#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr;
cr = gdk_cairo_create(widget->window);
static gboolean xdirection = TRUE;
static gint counter = 0;
int width, height;
gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
static gdouble rotate = 0;
static gint bigx = 20;
static gint bigy = 200;
static gint delta = 1;
counter += 1;
if (bigx > width)
{
xdirection = FALSE;
delta = -delta;
bigx = width;
}
if (bigx < 1)
{
bigx = 1;
delta = -delta;
}
if (bigy > height)
{
xdirection = TRUE;
delta = -delta;
bigy = height;
}
if (bigy < 1)
{
delta = -delta;
bigy = 1;
}
if (xdirection)
{
bigx += delta;
}
else
{
bigy += delta;
}
cairo_translate(cr, width / 2, height /2);
cairo_rectangle(cr, -bigx/2, -bigy/2, bigx-2, bigy-2);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_set_line_width(cr, 1);
cairo_stroke(cr);
cairo_rotate(cr, rotate);
rotate += 0.01;
cairo_rectangle(cr, -50, -25, 100, 50);
cairo_stroke(cr);
GdkRectangle bigrect;
GdkRectangle rect;
GdkRectangle intersect;
bigrect.x = -bigx/2;
bigrect.y = -bigy/2;
bigrect.width = bigx -2;
bigrect.height = bigy -2;
rect.x = -50;
rect.y = -25;
rect.width = 100;
rect.height = 50;
gdk_rectangle_intersect(&bigrect, &rect, &intersect);
cairo_rectangle(cr, intersect.x, intersect.y, intersect.width, intersect.height);
cairo_fill(cr);
cairo_destroy(cr);
return FALSE;
}
static gboolean time_handler (GtkWidget *widget)
{
if (widget->window == NULL) return FALSE;
gtk_widget_queue_draw(widget);
return TRUE;
}
int main (int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(on_expose_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
g_timeout_add(5, (GSourceFunc) time_handler, (gpointer) window);
gtk_main();
return 0;
}
編譯
gcc -o example-7.o example-7.c -lcairo -I/usr/include/cairo `pkg-config --cflags --libs gtk+-2.0`
運行
程序7:遮蔽應用示例
#include <cairo.h>
#include <gtk/gtk.h>
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr;
cairo_surface_t *surface;
cr = gdk_cairo_create(widget->window);
cairo_set_source_rgb(cr, 0, 0, 0);
surface = cairo_image_surface_create_from_png("omen.png");
cairo_mask_surface(cr, surface, 0, 0);
cairo_fill(cr);
cairo_surface_destroy(surface);
cairo_destroy(cr);
return FALSE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(on_expose_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 305, 100);
gtk_window_set_title(GTK_WINDOW(window), "mask");
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
編譯
gcc -o example-8.o example-8.c -lcairo -I/usr/include/cairo `pkg-config --cflags --libs gtk+-2.0`
運行
程序8:平移變換示例
#include <cairo.h>
#include <gtk/gtk.h>
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr;
cr = gdk_cairo_create (widget->window);
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
cairo_rectangle(cr, 20, 20, 80, 50);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_translate(cr, 100, 100); //通過平移用于空間的原點來修改當前的變換矩陣
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
cairo_rectangle(cr, 20, 20, 80, 50);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_destroy(cr);
return FALSE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "expose-event", G_CALLBACK (on_expose_event), NULL);
g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 300, 230);
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
編譯
gcc -o example-9.o example-9.c -lcairo -I/usr/include/cairo `pkg-config --cflags --libs gtk+-2.0`
運行
程序9:旋轉變換示例
#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr;
cr = gdk_cairo_create (widget->window);
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
cairo_rectangle(cr, 20, 20, 80, 50);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_translate(cr, 150, 100);
cairo_rotate(cr, M_PI/2); //圍繞原點旋轉180°
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
cairo_rectangle(cr, 20, 20, 80, 50);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_destroy(cr);
return FALSE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "expose-event", G_CALLBACK (on_expose_event), NULL);
g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 300, 230);
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
編譯
gcc -o example-10.o example-10.c -lcairo -I/usr/include/cairo `pkg-config --cflags --libs gtk+-2.0`
運行
程序10:縮放變換示例
#include <cairo.h>
#include <gtk/gtk.h>
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr;
cr = gdk_cairo_create (widget->window);
cairo_save(cr);
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
cairo_rectangle(cr, 20, 30, 80, 50);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_restore(cr);
cairo_save(cr);
cairo_translate(cr, 130, 30);
cairo_scale(cr, 0.7, 0.7); //對圖形進行縮小操作
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
cairo_rectangle(cr, 0, 0, 80, 50);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_restore(cr);
cairo_save(cr);
cairo_translate(cr, 220, 30);
cairo_scale(cr, 1.5, 1.5); //對圖形進行放大操作
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
cairo_rectangle(cr, 0, 0, 80, 50);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_restore(cr);
cairo_destroy(cr);
return FALSE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "expose-event", G_CALLBACK (on_expose_event), NULL);
g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 360, 140);
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
編譯
gcc -o example-11.o example-11.c -lcairo -I/usr/include/cairo `pkg-config --cflags --libs gtk+-2.0`
運行
程序11:錯切變換示例
#include <cairo.h>
#include <gtk/gtk.h>
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr;
cairo_matrix_t matrix;
cr = gdk_cairo_create (widget->window);
cairo_save(cr);
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
cairo_rectangle(cr, 20, 30, 80, 50);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_restore(cr);
cairo_save(cr);
cairo_translate(cr, 130, 30);
cairo_matrix_init(&matrix,
1.0, 0.5,
0.0, 1.0,
0.0, 0.0);
cairo_transform (cr, &matrix);
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
cairo_rectangle(cr, 0, 0, 80, 50);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_restore(cr);
cairo_save(cr);
cairo_translate(cr, 220, 30);
cairo_matrix_init(&matrix,
1.0, 0.0,
0.7, 1.0,
0.0, 0.0);
cairo_transform(cr, &matrix);
cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
cairo_rectangle(cr, 0, 0, 80, 50);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_restore(cr);
cairo_destroy(cr);
return FALSE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "expose-event", G_CALLBACK(on_expose_event), NULL);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 360, 140);
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
編譯
gcc -o example-12.o example-12.c -lcairo -I/usr/include/cairo `pkg-config --cflags --libs gtk+-2.0`
運行
總結
- 上一篇: java设计模式之设计原则①开闭原则
- 下一篇: PC电脑看电视 / 电视直播 / 高清频