3

私が持っているいくつかのデモコードにPixbufがあり、現在、画面のタッチに応じて時計回りまたは反時計回りに回転させています。

を使用してこれを行いますRotateSimpleが、それは 90 度の倍数に制限されています。

GDK 内で Pixbuf バッファ内の画像を 45 度 (またはそれ以下) 回転させる方法はありますか?

4

2 に答える 2

3

汎用の pixbuf 回転関数を作成しました。引数:

  1. src -- 回転するpixbuf
  2. radian -- 回転する角度 (ラジアンで表現)
  3. full_size -- この関数は 2 つのモードで動作します。完全に回転した画像 (およびアルファ = 0 の余分な三角形) を格納するのに十分な大きさの新しい pixbuf を生成するか、最大内接 (水平/垂直) 長方形と同じ大きさの pixbuf を生成します。回転した画像。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 );
    }
于 2016-08-24T18:14:45.920 に答える