2016-05-30 27 views
3

我在一些演示代碼中有一個Pixbuf,我現在將其順時針或逆時針旋轉,具體取決於屏幕接觸。GDK Pixbuf可以旋轉少於90度的東西嗎?

我這樣做使用RotateSimple但這是限制在90度的倍數。

在GDK中有什麼方法可以將Pixbuf緩衝區中的圖像旋轉45度(或更少)?

回答

1

不,與RotateSimple(或底層庫中的gdk_pixbuf_rotate_simple())不一致。根據documentation,這限於旋轉「90度的倍數」。

然而,有一件事你可以做的是提供多個圖像進行,如果你是一個較小的值旋轉它出現

對於45度的具體示例,只需要兩個圖像。首先是可以使用90度旋轉(即使用SimpleRotate)獲得八個所需旋轉中的四個的「直立」圖像,即0,90,180270

要獲得其他四種可能性,請將圖像放入一些圖像編輯軟件,並使用它將其旋轉45度,將其保存爲「傾斜」圖像。

這樣的話,你可以通過使用兩個圖像的各種旋轉得到所有的可能性:

Desired rotation Uses image Actual rotation 
---------------- ---------- --------------- 
     0   upright   0 
     45   tilted    0 
     90   upright   90 
     135   tilted   90 
     180   upright   180 
     225   tilted   180 
     270   upright   270 
     315   tilted   270 

對於更精細的旋轉,你可以做類似的事情,尤其如果分辨率的旋轉是360的一個因素。並且,由於巴比倫人(或蘇美爾人或某人,我的歷史有點生疏)的前瞻性質,360有相當多的因素。

2

我寫了一個通用的pixbuf旋轉函數。參數:

  1. SRC - pixbuf的旋轉
  2. 弧度 - 通過旋轉角度(以弧度表示)
  3. full_size - 此功能有兩種模式 工作。它將產生一個新的pixbuf,它足夠大以便包含完全旋轉的圖像(加上一些額外的三角形,其中 alpha = 0),或者它將產生與最大刻寫的(最大爲 (水平/垂直)旋轉圖像中的矩形。 如果full_size爲true,則會生成帶有(空白邊角) 的較大矩形,如果full_size爲false,則爲較小的矩形。當 旋轉接近45度時,小矩形的大小可能爲0 ,並返回NULL pixbuf。

    #include <gtk/gtk.h> 
    
    /* There are two reasonable sizes for a rotated image-- Either the minimum */ 
    /* bounding box which contains all rotated pixels (and a bunch of white space)*/ 
    /* or the maximum rectangle where all pixels come from the source image (but */ 
    /* where we lose some of the corners) */ 
    /* The first is easy to calculate: The minimum bounding box will have the corners */ 
    /* of the rotated image on its edges, this leaves us with four triangles in */ 
    /* the corners of the bb. Two triangles have edges width*sin(theta), width*cos(theta) */ 
    /* and two have edges height*sin(theta), height*cos(theta) */ 
    /* so the new width height will be the sum of two adjacent triangle edges: */ 
    /* width" = width*cos + height*sin */ 
    /* height"= width*sin + height*cos */ 
    /* Now for the maximum inscribed rectangle we draw a similar picture (except */ 
    /* the unknown rectangle is internal now) and get similar triangles. Here the*/ 
    /* equations are: */ 
    /* width = width'*cos + height'*sin */ 
    /* height= width'*sin + height'*cos */ 
    /* solving for height'... */ 
    /* height' = (width-width'*cos)/sin */ 
    /* height' = (height-width'*sin)/cos */ 
    /* (width-width'*cos)/sin = (height-width'*sin)/cos */ 
    /* width*cos - width'*cos^2 = height*sin - width'*sin^2 */ 
    /* width' * (sin^2-cos^2) = height*sin-width*cos */ 
    /* width' = (height*sin - width*cos)/(sin^2-cos^2) */ 
    /* height'= (width*sin - height*cos)/(sin^2-cos^2) */ 
    /* Note this produces garbage (0/0) when rotated by 45 degrees (135,225,...) */ 
    /* A little experimentation shows that at 45 degrees the only thing with */ 
    /* an internal rectangle is a square, all other aspect ratios have a height */ 
    /* of 0. A square, however, has an internal square with sides 1/sqrt(2) of the original */ 
    /* When creating a full_size image (minimum bounding box) we should return */ 
    /* an image with an alpha channel (whether the original had one or no). */ 
    /* otherwise we should create an alpha channel only if the original had one */ 
    
    /* A pixel at (x,y) will be rotated to: */ 
    /* ((x-width/2)*cos + (y-height/2)*sin + width'/2 ,    */ 
    /* =(x-width/2)*sin + (y-height/2)*cos + height'/2)    */ 
    /* A pixel at (x',y') will have come from: */ 
    /* ((x'-width'/2)*cos - (y'-height'/2)*sin + width/2 ,    */ 
    /*  (x'-width'/2)*sin + (y'-height'/2)*cos + height/2)    */ 
    static GdkPixbuf *gdk_pixbuf_rotate(GdkPixbuf *src,double radian,gboolean full_size) { 
        double s = sin(radian), c = cos(radian); 
        double as= s<0 ? -s : s, ac= c<0 ? -c : c; 
        int width, height, nwidth, nheight; 
        int hasalpha, nhasalpha; 
        GdkPixbuf *ret; 
        int nr,nc,r,col; 
        double nmodr, nmodc; 
        int alpha=0; 
        guchar *pixels, *npixels, *pt, *npt; 
        int rowstride, nrowstride, pixellen; 
        if (src==NULL) 
         return(NULL); 
        width  = gdk_pixbuf_get_width(src); 
        height = gdk_pixbuf_get_height(src); 
        hasalpha = gdk_pixbuf_get_has_alpha(src); 
        rowstride = gdk_pixbuf_get_rowstride(src); 
        pixels = gdk_pixbuf_get_pixels(src); 
        pixellen = hasalpha ? 4 : 3; 
        if (full_size) { 
         nwidth = round(ac*width + as*height); 
         nheight= round(as*width + ac*height); 
         nhasalpha = TRUE; 
        } else { 
         double denom = as*as - ac*ac; 
         if (denom<.1e-7 && denom>-1.e-7) { 
          if (width!=height) 
           return(NULL); 
          nwidth = nheight = round(width/sqrt(2.0)); 
         } else { 
          nwidth = round((height*as - width*ac)/denom); 
          nheight = round((width*as - height*ac)/denom); 
         } 
         if (nwidth<=0 || nheight<=0) 
          return(NULL); 
         nhasalpha = hasalpha; 
        } 
        ret = gdk_pixbuf_new(GDK_COLORSPACE_RGB,nhasalpha,8,nwidth,nheight); 
        if (ret==NULL) 
         return(NULL); 
        nrowstride = gdk_pixbuf_get_rowstride(ret); 
        npixels = gdk_pixbuf_get_pixels(ret); 
        for (nr=0; nr<nheight; ++nr) { 
         nmodr = nr-nheight/2.0; 
         npt = npixels + nr*nrowstride; 
         for (nc=0; nc<nwidth; ++nc) { 
          nmodc = nc-nwidth/2.0; 
          /* Where did this pixel come from? */ 
          r = round(height/2 - nmodc*s + nmodr*c); 
          col = round(width/2 + nmodc*c + nmodr*s); 
          if (r<0 || col<0 || r>=height || col>=width) { 
           alpha = 0; 
           if (r<0) r=0; 
           else if (r>=height) r = height-1; 
           if (col<0) col = 0; 
           else if (col>=width) col = width-1; 
          } else 
           alpha = 0xff; 
          pt = pixels + r*rowstride + col*pixellen; 
          *npt++ = *pt++; 
          *npt++ = *pt++; 
          *npt++ = *pt++; 
          if (hasalpha && alpha!=0) 
           alpha = *pt; 
          if (nhasalpha) 
           *npt++ = alpha;   
         } 
        } 
        return(ret); 
    }