support HTML <img src=.. />
authoryu.dongliang <18588496441@163.com>
Fri, 20 Sep 2024 12:07:20 +0000 (20:07 +0800)
committeryu.dongliang <18588496441@163.com>
Fri, 20 Sep 2024 12:07:20 +0000 (20:07 +0800)
17 files changed:
examples/img.html [new file with mode: 0644]
examples/img.png [new file with mode: 0644]
ffmpeg/Makefile [new file with mode: 0644]
ffmpeg/abc_ffmpeg.h [new file with mode: 0644]
ffmpeg/abc_ffmpeg_img.c [new file with mode: 0644]
ffmpeg/main.c [new file with mode: 0644]
html/abc_html.c
html/abc_obj.h
ui/Makefile
ui/abc.h
ui/abc_layout.c
ui/abc_layout_img.c [new file with mode: 0644]
ui/abc_render.c
ui/abc_render_a.c
ui/abc_render_a_href.c
ui/abc_render_h1.c
ui/abc_render_img.c [new file with mode: 0644]

diff --git a/examples/img.html b/examples/img.html
new file mode 100644 (file)
index 0000000..47cfb78
--- /dev/null
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>图片</title>
+</head>
+<body>
+<img src="../examples/img.png" width="400" height="380" />
+</body>
+</html>
diff --git a/examples/img.png b/examples/img.png
new file mode 100644 (file)
index 0000000..a3a560b
Binary files /dev/null and b/examples/img.png differ
diff --git a/ffmpeg/Makefile b/ffmpeg/Makefile
new file mode 100644 (file)
index 0000000..1b8f12a
--- /dev/null
@@ -0,0 +1,17 @@
+CFILES += ../util/scf_string.c
+
+CFILES += main.c
+CFILES += abc_ffmpeg_img.c
+
+CFLAGS += -g
+CFLAGS += -I../util
+
+LDFLAGS += -lavformat -lavcodec -lavfilter -lavutil
+LDFLAGS += -lcairo
+LDFLAGS += -ldl
+
+all:
+       gcc $(CFLAGS) $(CFILES) $(LDFLAGS)
+
+clean:
+       rm *.o
diff --git a/ffmpeg/abc_ffmpeg.h b/ffmpeg/abc_ffmpeg.h
new file mode 100644 (file)
index 0000000..60c8620
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef ABC_FFMPEG_H
+#define ABC_FFMPEG_H
+
+#include"scf_def.h"
+
+#include "libavformat/avformat.h"
+#include "libavcodec/avcodec.h"
+#include "libavutil/avutil.h"
+#include "libavutil/opt.h"
+#include "libavfilter/avfilter.h"
+#include "libavfilter/buffersrc.h"
+#include "libavfilter/buffersink.h"
+
+typedef struct {
+       AVFormatContext*   fmt_ctx;
+       AVCodecContext*    dec_ctx;
+       int                video_index;
+
+       AVFilterContext*   buffersrc_ctx;
+       AVFilterContext*   buffersink_ctx;
+       AVFilterGraph*     filter_graph;
+
+       int                width;
+       int                height;
+} abc_img_t;
+
+
+int  abc_img_open (abc_img_t** pimg, const char* path);
+void abc_img_close(abc_img_t*   img);
+
+// ffmpeg BGRA == cario ARGB, Blue in byte[0].
+int  abc_img_read (abc_img_t*   img, uint8_t* bgra, int size);
+
+#endif
diff --git a/ffmpeg/abc_ffmpeg_img.c b/ffmpeg/abc_ffmpeg_img.c
new file mode 100644 (file)
index 0000000..a9bf794
--- /dev/null
@@ -0,0 +1,266 @@
+#include "abc_ffmpeg.h"
+
+static int __ffmpeg_init(abc_img_t* img, const char* filename)
+{
+       int ret = avformat_open_input(&img->fmt_ctx, filename, NULL, NULL);
+       if (ret < 0) {
+               scf_loge("avformat_open_input, %s\n", av_err2str(ret));
+               return ret;
+       }
+
+       ret = avformat_find_stream_info(img->fmt_ctx, NULL);
+       if (ret < 0) {
+               scf_loge("avformat_find_stream_info, %s\n", av_err2str(ret));
+               return ret;
+       }
+
+       AVStream* s = NULL;
+       AVCodec*  c = NULL;
+
+       int i;
+       for (i = 0; i < img->fmt_ctx->nb_streams; i++) {
+               s  =        img->fmt_ctx->streams[i];
+
+               if (AVMEDIA_TYPE_VIDEO == s->codecpar->codec_type) {
+                       img->video_index = i;
+                       break;
+               }
+       }
+
+       if (i == img->fmt_ctx->nb_streams) {
+               scf_loge("video stream not found\n");
+               return -1;
+       }
+
+       c = avcodec_find_decoder(s->codecpar->codec_id);
+       if (!c) {
+               scf_loge("decoder not found, codec_id: %d\n", s->codecpar->codec_id);
+               return -EINVAL;
+       }
+
+       img->dec_ctx = avcodec_alloc_context3(c);
+       if (!img->dec_ctx) {
+               scf_loge("avcodec_alloc_context3() failed\n");
+               return -ENOMEM;
+       }
+
+       ret = avcodec_parameters_to_context(img->dec_ctx, s->codecpar);
+       if (ret < 0) {
+               scf_loge("avcodec_parameters_to_context, %s\n", av_err2str(ret));
+               return ret;
+       }
+
+       ret = avcodec_open2(img->dec_ctx, c, NULL);
+       if (ret < 0) {
+               scf_loge("avcodec_parameters_to_context, %s\n", av_err2str(ret));
+               return ret;
+       }
+
+       img->width  = img->dec_ctx->width;
+       img->height = img->dec_ctx->height;
+       return 0;
+}
+
+static int __init_filters(abc_img_t* img, const char *filters_desc)
+{
+    char args[512];
+    int  ret = 0;
+
+    const AVFilter     *buffersrc  = avfilter_get_by_name("buffer");
+    const AVFilter     *buffersink = avfilter_get_by_name("buffersink");
+
+       AVFilterInOut      *outputs    = avfilter_inout_alloc();
+    AVFilterInOut      *inputs     = avfilter_inout_alloc();
+
+       AVCodecContext*     dec_ctx    = img->dec_ctx;
+       AVStream*           s          = img->fmt_ctx->streams[img->video_index];
+
+       enum AVPixelFormat  pix_fmts[] = {AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE};
+
+    img->filter_graph = avfilter_graph_alloc();
+    if (!outputs || !inputs || !img->filter_graph) {
+        ret = AVERROR(ENOMEM);
+        goto end;
+    }
+
+       snprintf(args, sizeof(args),
+                       "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
+                       dec_ctx->width,   dec_ctx->height, dec_ctx->pix_fmt,
+                       s->time_base.num, s->time_base.den,
+                       dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);
+
+       ret = avfilter_graph_create_filter(&img->buffersrc_ctx, buffersrc, "in", args, NULL, img->filter_graph);
+    if (ret < 0)
+        goto end;
+
+    ret = avfilter_graph_create_filter(&img->buffersink_ctx, buffersink, "out", NULL, NULL, img->filter_graph);
+    if (ret < 0)
+        goto end;
+
+    ret = av_opt_set_int_list(img->buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
+       if (ret < 0)
+               goto end;
+
+    outputs->name       = av_strdup("in");
+    outputs->filter_ctx = img->buffersrc_ctx;
+    outputs->pad_idx    = 0;
+    outputs->next       = NULL;
+
+    inputs->name       = av_strdup("out");
+    inputs->filter_ctx = img->buffersink_ctx;
+    inputs->pad_idx    = 0;
+    inputs->next       = NULL;
+
+    if ((ret = avfilter_graph_parse_ptr(img->filter_graph, filters_desc, &inputs, &outputs, NULL)) < 0)
+        goto end;
+
+    if ((ret = avfilter_graph_config(img->filter_graph, NULL)) < 0)
+        goto end;
+
+end:
+    avfilter_inout_free(&inputs);
+    avfilter_inout_free(&outputs);
+    return ret;
+}
+
+int abc_img_open(abc_img_t** pimg, const char* path)
+{
+       if (!pimg || !path)
+               return -EINVAL;
+
+       abc_img_t* img = calloc(1, sizeof(abc_img_t));
+       if (!img)
+               return -ENOMEM;
+
+       int ret = __ffmpeg_init(img, path);
+       if (ret < 0) {
+               abc_img_close(img);
+               return ret;
+       }
+
+       *pimg = img;
+       return 0;
+}
+
+void abc_img_close(abc_img_t* img)
+{
+       if (img) {
+               avcodec_free_context(&img->dec_ctx);
+               avformat_close_input(&img->fmt_ctx);
+
+               if (img->filter_graph)
+                       avfilter_graph_free(&img->filter_graph);
+
+               free(img);
+       }
+}
+
+int abc_img_read(abc_img_t* img, uint8_t* bgra, int size)
+{
+       if (!img || !bgra || size < img->width * img->height * 4)
+               return -EINVAL;
+
+       char filters_desc[256];
+       snprintf(filters_desc, sizeof(filters_desc), "scale=%dx%d", img->width, img->height);
+
+       int ret = __init_filters(img, filters_desc);
+       if (ret < 0) {
+               scf_loge("ffmpeg_init error\n");
+               return ret;
+       }
+
+       AVFrame* frame = av_frame_alloc();
+       if (!frame)
+               return -ENOMEM;
+
+       AVFrame* frame2 = av_frame_alloc();
+       if (!frame2) {
+               av_frame_free(&frame);
+               return -ENOMEM;
+       }
+
+       AVPacket* pkt = av_packet_alloc();
+       if (!pkt) {
+               av_frame_free(&frame);
+               av_frame_free(&frame2);
+               return -ENOMEM;
+       }
+
+       int key_frame = 0;
+
+       while (1) {
+               ret = av_read_frame(img->fmt_ctx, pkt);
+               if (ret < 0) {
+                       scf_loge("av_read_frame, %s\n", av_err2str(ret));
+                       goto end;
+               }
+
+               if (pkt->stream_index != img->video_index) {
+                       av_packet_unref(pkt);
+                       continue;
+               }
+
+               if (pkt->flags & AV_PKT_FLAG_KEY)
+                       key_frame++;
+
+               if (key_frame > 0)
+                       break;
+
+               av_packet_unref(pkt);
+       }
+
+       ret = avcodec_send_packet(img->dec_ctx, pkt);
+       if (ret < 0) {
+               scf_loge("avcodec_send_packet, %s\n", av_err2str(ret));
+               goto end;
+       }
+
+       while (ret >= 0) {
+               ret = avcodec_receive_frame(img->dec_ctx, frame);
+
+               if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+                       break;
+               else if (ret < 0) {
+                       scf_loge("avcodec_receive_frame, %s\n", av_err2str(ret));
+                       goto end;
+               }
+
+               frame->pts = frame->best_effort_timestamp;
+
+               ret = av_buffersrc_add_frame_flags(img->buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);
+               if (ret < 0) {
+                       scf_loge("av_buffersrc_add_frame_flags, %s\n", av_err2str(ret));
+                       goto end;
+               }
+
+               while (1) {
+                       ret = av_buffersink_get_frame(img->buffersink_ctx, frame2);
+
+                       if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+                               break;
+                       else if (ret < 0) {
+                               scf_loge("av_buffersink_get_frame, %s\n", av_err2str(ret));
+                               goto end;
+                       }
+
+                       assert(img->width  == frame2->width);
+                       assert(img->height == frame2->height);
+
+                       scf_logi("frame2->linesize[0]: %d\n", frame2->linesize[0]);
+
+                       int i;
+                       for (i = 0; i < frame2->height; i++)
+                               memcpy(bgra + i * frame2->width * 4, frame2->data[0] + i * frame2->linesize[0], frame2->width * 4);
+
+                       av_frame_unref(frame2);
+               }
+               av_frame_unref(frame);
+       }
+
+       ret = 0;
+end:
+       av_packet_free(&pkt);
+       av_frame_free(&frame);
+       av_frame_free(&frame2);
+       return ret;
+}
diff --git a/ffmpeg/main.c b/ffmpeg/main.c
new file mode 100644 (file)
index 0000000..92093b4
--- /dev/null
@@ -0,0 +1,49 @@
+#include<cairo/cairo.h>
+#include"abc_ffmpeg.h"
+
+int main(int argc, char* argv[])
+{
+       abc_img_t* img = NULL;
+
+       if (argc < 2) {
+               scf_loge("\n");
+               return -1;
+       }
+
+       if (abc_img_open(&img, argv[1]) < 0) {
+               scf_loge("\n");
+               return -1;
+       }
+
+       scf_logi("img->width: %d, img->height: %d\n", img->width, img->height);
+
+       int      size = img->width * img->height * 4;
+
+       uint8_t* rgba = calloc(1, size);
+       if (!rgba) {
+               scf_loge("\n");
+               return -1;
+       }
+
+       if (abc_img_read(img, rgba, size) < 0) {
+               scf_loge("\n");
+               return -1;
+       }
+
+
+       cairo_surface_t* surface;
+       cairo_t*         cr;
+
+       surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, img->width, img->height, img->width * 4);
+       cr      = cairo_create(surface);
+
+       cairo_surface_write_to_png(surface, "1.png");
+
+       cairo_destroy(cr);
+       cairo_surface_destroy(surface);
+
+       printf("\n");
+
+       scf_logi("main ok\n");
+       return 0;
+}
index 1c4791ef76f8c06b5f59fc29f6eb0cf4cb5229ff..a49508b1d99ddafbe99da957b9d4bce954682e68 100644 (file)
@@ -21,6 +21,36 @@ static html_attr_t  h1_attrs[] =
        {"font-size",   "32",                ABC_HTML_ATTR_FONT_SIZE},
 };
 
+static html_attr_t  h2_attrs[] =
+{
+       {"font",        "Liberation Serif",  ABC_HTML_ATTR_FONT},
+       {"font-size",   "28",                ABC_HTML_ATTR_FONT_SIZE},
+};
+
+static html_attr_t  h3_attrs[] =
+{
+       {"font",        "Liberation Serif",  ABC_HTML_ATTR_FONT},
+       {"font-size",   "24",                ABC_HTML_ATTR_FONT_SIZE},
+};
+
+static html_attr_t  h4_attrs[] =
+{
+       {"font",        "Liberation Serif",  ABC_HTML_ATTR_FONT},
+       {"font-size",   "20",                ABC_HTML_ATTR_FONT_SIZE},
+};
+
+static html_attr_t  h5_attrs[] =
+{
+       {"font",        "Liberation Serif",  ABC_HTML_ATTR_FONT},
+       {"font-size",   "16",                ABC_HTML_ATTR_FONT_SIZE},
+};
+
+static html_attr_t  h6_attrs[] =
+{
+       {"font",        "Liberation Serif",  ABC_HTML_ATTR_FONT},
+       {"font-size",   "12",                ABC_HTML_ATTR_FONT_SIZE},
+};
+
 static html_attr_t  a_attrs[] =
 {
        {"href",        "",                  ABC_HTML_ATTR_HREF},
@@ -29,6 +59,13 @@ static html_attr_t  a_attrs[] =
        {"font-color",  "blue",              ABC_HTML_ATTR_FONT_COLOR},
 };
 
+static html_attr_t  img_attrs[] =
+{
+       {"src",         "",                  ABC_HTML_ATTR_SRC},
+       {"width",       "100",               ABC_HTML_ATTR_WIDTH},
+       {"height",      "100",               ABC_HTML_ATTR_HEIGHT},
+};
+
 static html_label_t  html_labels[] =
 {
        {"html",   ABC_HTML,        0, NULL},
@@ -39,7 +76,14 @@ static html_label_t  html_labels[] =
        {"div",    ABC_HTML_DIV,    0, NULL},
 
        {"h1",     ABC_HTML_H1,     sizeof(h1_attrs) / sizeof(h1_attrs[0]), h1_attrs},
-       {"a",      ABC_HTML_A,      sizeof(a_attrs)  / sizeof(a_attrs[0]),  a_attrs},
+       {"h2",     ABC_HTML_H2,     sizeof(h2_attrs) / sizeof(h2_attrs[0]), h2_attrs},
+       {"h3",     ABC_HTML_H3,     sizeof(h3_attrs) / sizeof(h3_attrs[0]), h3_attrs},
+       {"h4",     ABC_HTML_H4,     sizeof(h4_attrs) / sizeof(h4_attrs[0]), h4_attrs},
+       {"h5",     ABC_HTML_H5,     sizeof(h5_attrs) / sizeof(h5_attrs[0]), h5_attrs},
+       {"h6",     ABC_HTML_H6,     sizeof(h6_attrs) / sizeof(h6_attrs[0]), h6_attrs},
+
+       {"a",      ABC_HTML_A,      sizeof(a_attrs)   / sizeof(a_attrs[0]),   a_attrs},
+       {"img",    ABC_HTML_IMG,    sizeof(img_attrs) / sizeof(img_attrs[0]), img_attrs},
 };
 
 static int __html_parse_obj(abc_html_t* html, abc_char_t* c);
@@ -308,7 +352,7 @@ static int __html_parse_value(abc_html_t* html, abc_obj_t* attr)
                scf_string_free(attr->value);
 
        attr->value = value;
-       return '>' == tmp;
+       return tmp;
 }
 
 static int __html_parse_attr2(abc_html_t* html, abc_obj_t* obj, const html_attr_t* attrs, int n_attrs)
@@ -332,13 +376,19 @@ static int __html_parse_attr2(abc_html_t* html, abc_obj_t* obj, const html_attr_
                if ('=' == c->c)
                        break;
 
+               if ('/' == c->c) {
+                       free(c);
+                       scf_string_free(key);
+                       return '/';
+               }
+
                if ('_' == c->c
                                || '-' == c->c
                                || ('a' <= c->c && 'z' >= c->c))
                        scf_string_cat_cstr_len(key, c->utf8, c->len);
                else {
-                       scf_loge("invalid char in HTML attribute, file: %s, line: %d\n",
-                                       html->file->data, html->n_lines);
+                       scf_loge("invalid char '%c' in HTML attribute, file: %s, line: %d\n",
+                                       c->c, html->file->data, html->n_lines);
                        free(c);
                        scf_string_free(key);
                        return -1;
@@ -389,13 +439,16 @@ static int __html_parse_attr(abc_html_t* html, abc_obj_t* obj, const html_attr_t
 {
        int ret = 0;
 
-       while (!ret) {
+       while (1) {
                ret = __html_parse_attr2(html, obj, attrs, n_attrs);
                if (ret < 0)
                        return ret;
+
+               if ('>' == ret || '/' == ret)
+                       break;
        }
 
-       return 0;
+       return ret;
 }
 
 static int __html_parse_obj(abc_html_t* html, abc_char_t* c)
@@ -464,6 +517,7 @@ static int __html_parse_obj(abc_html_t* html, abc_char_t* c)
                return ret;
        }
 
+       ret = 0;
        if (' ' == tmp) {
                ret = __html_parse_attr(html, obj, label->attrs, label->n_attrs);
                if (ret < 0) {
@@ -486,7 +540,25 @@ static int __html_parse_obj(abc_html_t* html, abc_char_t* c)
                html->current = obj;
        }
 
-       ret = __html_parse_text(html, obj);
+       if ('/' == ret) {
+               c = __html_pop_char(html);
+               if (!c) {
+                       scf_loge("\n");
+                       return -1;
+               }
+
+               int tmp = c->c;
+
+               free(c);
+               c = NULL;
+
+               if ('>' != tmp) {
+                       scf_loge("HTML label '%s' not closed, in file: %s, line: %d\n",
+                                       obj->key->data, html->file->data, html->n_lines);
+                       return -1;
+               }
+       } else
+               ret = __html_parse_text(html, obj);
 
        html->current = obj->parent;
        return ret;
index 431e6f42028cf339ab69604bff71dcb13d5ecc65..f1babf8a710dc7d20cde31be3dd92cf605ec1fd9 100644 (file)
@@ -15,18 +15,34 @@ enum abc_objs
 
        // 4
        ABC_HTML_DIV,
+
+       // 5
        ABC_HTML_H1,
+       ABC_HTML_H2,
+       ABC_HTML_H3,
+       ABC_HTML_H4,
+       ABC_HTML_H5,
+       ABC_HTML_H6,
+
+       // 11
        ABC_HTML_A,
        ABC_HTML_A_HREF,
 
+       // 13
+       ABC_HTML_IMG,
+
        ABC_HTML_NB, // total HTML objects
 
        ABC_HTML_ATTR_ID,
        ABC_HTML_ATTR_HREF,
+       ABC_HTML_ATTR_SRC,
 
        ABC_HTML_ATTR_FONT,
        ABC_HTML_ATTR_FONT_SIZE,
        ABC_HTML_ATTR_FONT_COLOR,
+
+       ABC_HTML_ATTR_WIDTH,
+       ABC_HTML_ATTR_HEIGHT,
 };
 
 struct abc_obj_s
index b06f22cf180beb5d588698db3a1a93f344197032..4dc7d040c5db484bfdbec93a23271ae0bea8630e 100644 (file)
@@ -8,6 +8,7 @@ CFILES += abc_layout_body.c
 CFILES += abc_layout_div.c
 CFILES += abc_layout_h1.c
 CFILES += abc_layout_a.c
+CFILES += abc_layout_img.c
 
 CFILES += abc_render.c
 CFILES += abc_render_html.c
@@ -18,16 +19,20 @@ CFILES += abc_render_div.c
 CFILES += abc_render_h1.c
 CFILES += abc_render_a.c
 CFILES += abc_render_a_href.c
+CFILES += abc_render_img.c
 
 CFILES += ../html/abc_html.c
 CFILES += ../html/abc_html_util.c
 CFILES += ../html/abc_obj.c
 
+CFILES += ../ffmpeg/abc_ffmpeg_img.c
+
 CFILES += ../util/scf_string.c
 
 CFLAGS += -g -O3
 CFLAGS += -I./
 CFLAGS += -I../html
+CFLAGS += -I../ffmpeg
 CFLAGS += -I../util
 CFLAGS += `pkg-config --cflags gtk+-3.0`
 
index 347e88b4275c1c5f18550389d1c021d5b084ecc8..02ac07e89935b4504b0dfa7bfb0c1606926af300 100644 (file)
--- a/ui/abc.h
+++ b/ui/abc.h
@@ -72,4 +72,6 @@ int  __init_texture(GLuint* ptex, GLenum format, int w, int h, uint8_t* data);
 
 int  __init_program(GLuint* pprog, const char* vert_shader, const char* frag_shader);
 
+int  __init_buffers(GLuint* vao, GLuint buffers[2]);
+
 #endif
index 3ebf72c091c34ac2c700be45709fb7f98bec6376..b205320be1376a32d6e9e68779f2fc9a8dbfac04 100644 (file)
@@ -8,6 +8,7 @@ int abc_layout_body (abc_layout_t* layout, abc_obj_t* root, int width, int heigh
 int abc_layout_div  (abc_layout_t* layout, abc_obj_t* root, int width, int height);
 int abc_layout_h1   (abc_layout_t* layout, abc_obj_t* root, int width, int height);
 int abc_layout_a    (abc_layout_t* layout, abc_obj_t* root, int width, int height);
+int abc_layout_img  (abc_layout_t* layout, abc_obj_t* root, int width, int height);
 
 static abc_layout_pt abc_layouts[ABC_HTML_NB] =
 {
@@ -18,8 +19,19 @@ static abc_layout_pt abc_layouts[ABC_HTML_NB] =
 
        // 4
        abc_layout_div,
+
+       abc_layout_h1,
+       abc_layout_h1,
+       abc_layout_h1,
        abc_layout_h1,
+       abc_layout_h1,
+       abc_layout_h1,
+
+       // 11
        abc_layout_a,
+       NULL,
+
+       abc_layout_img,
 };
 
 int abc_layout_obj(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
diff --git a/ui/abc_layout_img.c b/ui/abc_layout_img.c
new file mode 100644 (file)
index 0000000..5744271
--- /dev/null
@@ -0,0 +1,33 @@
+#include"abc.h"
+
+int abc_layout_img(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
+{
+       scf_list_t*  l;
+       abc_obj_t*   attr;
+
+       for (l   = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) {
+               attr = scf_list_data(l, abc_obj_t, list);
+
+               switch (attr->type) {
+
+                       case ABC_HTML_ATTR_WIDTH:
+                               obj->w = atoi(attr->value->data);
+                               break;
+
+                       case ABC_HTML_ATTR_HEIGHT:
+                               obj->h = atoi(attr->value->data);
+                               break;
+                       default:
+                               break;
+               };
+       }
+
+       obj->x = 4;
+       obj->y = 4;
+
+       obj->w = (obj->w + 3) & ~0x3;
+       obj->h = (obj->h + 3) & ~0x3;
+
+       scf_logd("%s, w: %d, h: %d\n", obj->text->data, obj->w, obj->h);
+       return 0;
+}
index d97b6c23223bf2a7495f9996e64f8d6976ebaba8..a1485efefd781f644cd67857fdabdafe956eabca 100644 (file)
@@ -9,6 +9,7 @@ extern abc_render_t  abc_render_div;
 extern abc_render_t  abc_render_h1;
 extern abc_render_t  abc_render_a;
 extern abc_render_t  abc_render_a_href;
+extern abc_render_t  abc_render_img;
 
 static abc_render_t* abc_renders[ABC_HTML_NB] =
 {
@@ -19,9 +20,19 @@ static abc_render_t* abc_renders[ABC_HTML_NB] =
 
        // 4
        &abc_render_div,
+
+       &abc_render_h1,
+       &abc_render_h1,
+       &abc_render_h1,
        &abc_render_h1,
+       &abc_render_h1,
+       &abc_render_h1,
+
+       // 11
        &abc_render_a,
        &abc_render_a_href,
+
+       &abc_render_img,
 };
 
 int abc_renders_fini()
@@ -160,6 +171,29 @@ int __init_texture(GLuint* ptex, GLenum format, int w, int h, uint8_t* data)
        return 0;
 }
 
+int __init_buffers(GLuint* vao, GLuint buffers[2])
+{
+       glGenBuffers(2, buffers);
+       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+       glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW);
+       glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
+       glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW);
+
+       glGenVertexArrays(1, vao);
+       glBindVertexArray(*vao);
+
+       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+       glEnableVertexAttribArray(0);
+       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+       glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
+       glEnableVertexAttribArray(1);
+       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+       glBindVertexArray(0);
+       return 0;
+}
+
 int __init_program(GLuint* pprog, const char* vert_shader, const char* frag_shader)
 {
        GLint status = 0;
index 02b37ba9f2287ceccee5bd986c6d5e76d9f1871b..a5eef25154f4674daf23374eb3e5d4e365536ca4 100644 (file)
@@ -32,31 +32,6 @@ static GLuint texture_rgba = 0;
 static GLuint uniform_mvp;
 static GLuint uniform_rgba;
 
-static int    __width  = 0;
-static int    __height = 0;
-
-static int __init_buffers(GLuint* vao, GLuint buffers[2])
-{
-       glGenBuffers(2, buffers);
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
-       glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW);
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
-       glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW);
-
-       glGenVertexArrays(1, vao);
-       glBindVertexArray(*vao);
-
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
-       glEnableVertexAttribArray(0);
-       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
-       glEnableVertexAttribArray(1);
-       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
-       glBindVertexArray(0);
-       return 0;
-}
 
 static int _render_fini_a(abc_render_t* render)
 {
@@ -81,11 +56,11 @@ static int _render_draw_a(abc_render_t* render, abc_obj_t* obj, int width, int h
        scf_list_t*           l;
        abc_obj_t*            attr;
 
-       uint8_t* rgba = calloc(1, obj->w * obj->h * 4);
-       if (!rgba)
+       uint8_t* bgra = calloc(1, obj->w * obj->h * 4);
+       if (!bgra)
                return -ENOMEM;
 
-       surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
+       surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
        cr      = cairo_create(surface);
 
        cairo_set_line_width(cr, 1);
@@ -163,7 +138,7 @@ static int _render_draw_a(abc_render_t* render, abc_obj_t* obj, int width, int h
        // board
        glActiveTexture(GL_TEXTURE0);
        glBindTexture  (GL_TEXTURE_2D, texture_rgba);
-       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
        glUniform1i(uniform_rgba, 0);
 
        // draw
@@ -177,7 +152,7 @@ static int _render_draw_a(abc_render_t* render, abc_obj_t* obj, int width, int h
        glBindVertexArray(0);
        glUseProgram(0);
 
-       free(rgba);
+       free(bgra);
        return 0;
 }
 
index 96365c05e8c9c7a7736aed8e46ea9ac4918ab68b..4eaddf1ce6deab5b6cdea57ef61fc87226f6ed8d 100644 (file)
@@ -32,31 +32,6 @@ static GLuint texture_rgba = 0;
 static GLuint uniform_mvp;
 static GLuint uniform_rgba;
 
-static int    __width  = 0;
-static int    __height = 0;
-
-static int __init_buffers(GLuint* vao, GLuint buffers[2])
-{
-       glGenBuffers(2, buffers);
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
-       glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW);
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
-       glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW);
-
-       glGenVertexArrays(1, vao);
-       glBindVertexArray(*vao);
-
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
-       glEnableVertexAttribArray(0);
-       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
-       glEnableVertexAttribArray(1);
-       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
-       glBindVertexArray(0);
-       return 0;
-}
 
 static int _render_fini_a_href(abc_render_t* render)
 {
@@ -81,11 +56,11 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width,
        scf_list_t*           l;
        abc_obj_t*            attr;
 
-       uint8_t* rgba = malloc(width * 32 * 4);
-       if (!rgba)
+       uint8_t* bgra = malloc(width * 32 * 4);
+       if (!bgra)
                return -ENOMEM;
 
-       surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, width, 32, width * 4);
+       surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, width, 32, width * 4);
        cr      = cairo_create(surface);
 
        cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
@@ -116,23 +91,23 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width,
        if (l == scf_list_sentinel(&obj->attrs)) {
                scf_loge("hyper link '%s' not found a URL\n", obj->text->data);
 
-               free(rgba);
-               rgba = NULL;
+               free(bgra);
+               bgra = NULL;
                return -EINVAL;
        }
 
        scf_logd("extents: x_bearing: %f, width: %f, y_bearing: %f, height: %f\n",
                        extents.x_bearing, extents.width, extents.y_bearing, extents.height);
 
-       void* p = realloc(rgba, w * h * 4);
+       void* p = realloc(bgra, w * h * 4);
        if (!p) {
-               free(rgba);
-               rgba = NULL;
+               free(bgra);
+               bgra = NULL;
                return -ENOMEM;
        }
-       rgba = p;
+       bgra = p;
 
-       surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, w, h, w * 4);
+       surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, w, h, w * 4);
        cr      = cairo_create(surface);
 
        cairo_set_line_width(cr, 1);
@@ -188,7 +163,7 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width,
        // board
        glActiveTexture(GL_TEXTURE0);
        glBindTexture  (GL_TEXTURE_2D, texture_rgba);
-       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
        glUniform1i(uniform_rgba, 0);
 
        // draw
@@ -202,7 +177,7 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width,
        glBindVertexArray(0);
        glUseProgram(0);
 
-       free(rgba);
+       free(bgra);
        return 0;
 }
 
index 8a94b5c3428d3ce4daae53242ba3847762c39188..db72fc27dafcb78f8885f1aab518a3cad223a531 100644 (file)
@@ -32,31 +32,6 @@ static GLuint texture_rgba = 0;
 static GLuint uniform_mvp;
 static GLuint uniform_rgba;
 
-static int    __width  = 0;
-static int    __height = 0;
-
-static int __init_buffers(GLuint* vao, GLuint buffers[2])
-{
-       glGenBuffers(2, buffers);
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
-       glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW);
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
-       glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW);
-
-       glGenVertexArrays(1, vao);
-       glBindVertexArray(*vao);
-
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
-       glEnableVertexAttribArray(0);
-       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
-       glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
-       glEnableVertexAttribArray(1);
-       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
-       glBindVertexArray(0);
-       return 0;
-}
 
 static int _render_fini_h1(abc_render_t* render)
 {
@@ -81,11 +56,11 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int
        scf_list_t*           l;
        abc_obj_t*            attr;
 
-       uint8_t* rgba = calloc(1, obj->w * obj->h * 4);
-       if (!rgba)
+       uint8_t* bgra = calloc(1, obj->w * obj->h * 4);
+       if (!bgra)
                return -ENOMEM;
 
-       surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
+       surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
        cr      = cairo_create(surface);
 
        cairo_set_line_width(cr, 1);
@@ -152,7 +127,7 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int
        // board
        glActiveTexture(GL_TEXTURE0);
        glBindTexture  (GL_TEXTURE_2D, texture_rgba);
-       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
        glUniform1i(uniform_rgba, 0);
 
        // draw
@@ -166,7 +141,7 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int
        glBindVertexArray(0);
        glUseProgram(0);
 
-       free(rgba);
+       free(bgra);
        return 0;
 }
 
diff --git a/ui/abc_render_img.c b/ui/abc_render_img.c
new file mode 100644 (file)
index 0000000..5e9feb7
--- /dev/null
@@ -0,0 +1,140 @@
+#include"abc.h"
+#include"abc_ffmpeg.h"
+
+static const char* vert_shader =
+       "#version 330 core\n"
+       "layout(location = 0) in vec4 position; \n"
+       "layout(location = 1) in vec2 a_texCoord; \n"
+       "out vec2 v_texCoord; \n"
+       "uniform mat4 mvp; \n"
+       "void main() { \n"
+               "gl_Position = mvp * position; \n"
+               "v_texCoord  = a_texCoord; \n"
+       "} \n";
+
+static const char* frag_shader =
+       "#version 330 core\n"
+       "in  vec2 v_texCoord; \n"
+       "out vec4 outputColor; \n"
+       "uniform sampler2D tex_rgba; \n"
+       "void main() { \n"
+       "    vec2 xy = v_texCoord; \n"
+       "    vec4 v  = texture2D(tex_rgba, xy).rgba; \n"
+       "    outputColor = vec4(v.b, v.g, v.r, 1.0); \n"
+       "} \n";
+
+
+static GLuint program = 0;
+
+static GLuint vao = 0;
+static GLuint buffers[2]   = {0};
+static GLuint texture_rgba = 0;
+
+static GLuint uniform_mvp;
+static GLuint uniform_rgba;
+
+
+static int _render_fini_img(abc_render_t* render)
+{
+       return 0;
+}
+
+static int _render_draw_img(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+       scf_list_t*  l;
+       abc_obj_t*   attr;
+       abc_img_t*   img = NULL;
+
+       for (l   = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) {
+               attr = scf_list_data(l, abc_obj_t, list);
+
+               if (ABC_HTML_ATTR_SRC == attr->type)
+                       break;
+       }
+
+       if (l == scf_list_sentinel(&obj->attrs)) {
+               scf_loge("src image of '%s' not found\n", obj->key->data);
+               return -1;
+       }
+
+       int ret = abc_img_open(&img, attr->value->data);
+       if (ret < 0)
+               return ret;
+
+       uint8_t* bgra = calloc(1, img->width * img->height * 4);
+       if (!bgra) {
+               abc_img_close(img);
+               return -ENOMEM;
+       }
+
+       ret = abc_img_read(img, bgra, img->width * img->height * 4);
+       if (ret < 0) {
+               abc_img_close(img);
+               free(bgra);
+               return ret;
+       }
+
+       if (0 == program)
+               __init_program(&program, vert_shader, frag_shader);
+
+       if (0 == vao)
+               __init_buffers(&vao, buffers);
+
+       if (0 == texture_rgba)
+               __init_texture(&texture_rgba, GL_RGBA, img->width, img->height, NULL);
+
+       float mvp[16];
+       __compute_mvp(mvp, 0, 0, 0);
+
+       scf_logi("%s, x: %d, y: %d, w: %d, h: %d\n", obj->key->data, obj->x, obj->y, obj->w, obj->h);
+
+       GLfloat vert_update[] =
+       {
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+       };
+
+       glUseProgram(program);
+       uniform_rgba = glGetUniformLocation(program, "tex_rgba");
+       uniform_mvp  = glGetUniformLocation(program, "mvp");
+
+       glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp);
+
+       // board
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture  (GL_TEXTURE_2D, texture_rgba);
+       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, img->width, img->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
+       glUniform1i(uniform_rgba, 0);
+
+       // draw
+       glBindBuffer   (GL_ARRAY_BUFFER, buffers[0]);
+       glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update);
+
+       glBindVertexArray(vao);
+
+       glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+       glBindVertexArray(0);
+       glUseProgram(0);
+
+       abc_img_close(img);
+       free(bgra);
+       return 0;
+}
+
+abc_render_t  abc_render_img =
+{
+       .type = ABC_HTML_IMG,
+
+       .draw = _render_draw_img,
+       .fini = _render_fini_img,
+};