who9394 发表于 2011-5-8 18:10:57

将图片转换成C语言数据文件,然后在程序中调用重现图片

将图片转换为数据(imgtodata)
第一步,先获取图片的数据信息:
pixbuf = gdk_pixbuf_new_from_file(open_filename, NULL);
    data = gdk_pixbuf_get_pixels(pixbuf);//获得图片像素的数据,数据类型为guchar
    width = gdk_pixbuf_get_width(pixbuf);
    height = gdk_pixbuf_get_height(pixbuf);
    stride = gdk_pixbuf_get_rowstride(pixbuf);//一行像素所占的字节数。
    n_channels = gdk_pixbuf_get_n_channels (pixbuf);//如果图片为RGB格式即此值为3,如果是RGBA格式则此值为4

由于本例中图片再现是用cairo_image_surface_create_for_data() 来实现的,数据的排列方式跟PIXBUF不一样,所以要做一下处理。
第二步,数据重新排列:
bytesperpixel = n_channels;
    cairostride = stride;
    if(n_channels == 3)
    {   
      bytesperpixel += 1;
      cairostride = width * 4;
    }

    if(cairodata != NULL)
      g_free(cairodata);
    cairodata = g_malloc0(cairostride*height);
    for(y = 0; y < height; y++)
    {
      for(x = 0; x < width; x++)
      {
            pdata = data + y * stride + x * n_channels;
            pcdata = cairodata + y * cairostride + x * bytesperpixel;
            pcdata = pdata;
            pcdata = pdata;
            pcdata = pdata;
            if(n_channels == bytesperpixel)
                pcdata = pdata;
      }
    }
至此cairodata就得到我们所要的像素数据。
第三步,就是将cairodata保存到文件。
FILE* fp = NULL;
    GtkWidget *message_dlg;
    gint return_value;
    gchar **dcharTemp;
    GString *gstringTemp;
    gint i, j, k;
    guchar tempchar;
   
    if ((fp = fopen(filename,"rb")) != NULL)
    {
      fclose(fp);
      message_dlg = gtk_message_dialog_new(GTK_WINDOW(NULL),GTK_DIALOG_MODAL,
                GTK_MESSAGE_QUESTION,GTK_BUTTONS_YES_NO,_("Over write the file?"));
      return_value = gtk_dialog_run(GTK_DIALOG(message_dlg));
      gtk_widget_destroy(message_dlg);
      if( return_value != GTK_RESPONSE_YES)
            return -2;
    }
    if ((fp = fopen(filename,"wb")) == NULL)
    {
//      g_warning("error open %s\n",filename);
      message_dlg = gtk_message_dialog_new(GTK_WINDOW(NULL),GTK_DIALOG_MODAL,
                GTK_MESSAGE_INFO,GTK_BUTTONS_OK,_("Can not save file."));      
      gtk_dialog_run(GTK_DIALOG(message_dlg));
      gtk_widget_destroy(message_dlg);
      return -1;
    }
    fputs("const unsigned char ",fp);
    dcharTemp = g_strsplit(g_filename_display_basename(filename),".",-1);
    gstringTemp = g_string_new(NULL);

    g_string_printf(gstringTemp,"%s_mark%d[] = {\n",*dcharTemp,width);
    fputs(gstringTemp->str, fp);
    for(i = 0; i < height; i++)
    {
      g_string_free(gstringTemp, TRUE);
      gstringTemp = g_string_new(NULL);
      for(j = 0; j < width; j++)
      {
            pcdata = cairodata + i * cairostride + j * bytesperpixel;
            g_string_append_printf(gstringTemp, "0x%x, 0x%x, 0x%x, 0x%x, ",pcdata,pcdata,pcdata,pcdata);
      }
      g_string_append_printf(gstringTemp, "\n");
      fputs(gstringTemp->str, fp);
    }

    fseek(fp, -3, SEEK_CUR);
    fputs("\n};\n",fp);
    fclose(fp);
    g_string_free(gstringTemp, TRUE);
至此,转换功能完成。
下面是如何将数据重现为图片(datatoimg)。
第一步,建立一个新工程,转换生成的*.c(如本例中生成gtk_logo_rgb.c)加到工程中。
第二步,在drawingarea的“expose“回调中重现图片。
cairo_t *cr;
    cairo_surface_t *surface;
    gint cairosurfacex, cairosurfacey;
    gint mark_width = 107;
    gint mark_height = 140;
    gint mark_stride = 428;/* BGRA is 4 channels, so width*channels=107*4=428*/
   
    cr = gdk_cairo_create(widget->window);
    surface = cairo_image_surface_create_for_data(gtk_logo_rgb_mark107,CAIRO_FORMAT_ARGB32,mark_width,mark_height,mark_stride);
    cairosurfacex = MAX (((widget->allocation.width-mark_width)/2), 0);
    cairosurfacey = MAX (((widget->allocation.height-mark_height)/2), 0);
    cairo_set_source_surface (cr, surface, cairosurfacex, cairosurfacey);
    cairo_paint(cr);
    cairo_destroy(cr);
    cairo_surface_destroy(surface);

附上源代码,编程环境,windowxp,devcpp,gtk-2.12.9-dev

zjm3712 发表于 2011-5-9 19:22:51

学习 学习啊

tarofriend 发表于 2012-3-12 20:45:27

想学

发表于 2012-3-20 18:21:51

谢谢

wzwzwz 发表于 2012-9-26 02:12:38

学习了
页: [1]
查看完整版本: 将图片转换成C语言数据文件,然后在程序中调用重现图片