2016-05-30 16 views
3

Ich habe einen Pixbuf in einigen Demo-Code Ich habe und ich derzeit drehen im oder gegen den Uhrzeigersinn je nach Berührungen des Bildschirms.Kann ein GDK Pixbuf um etwas weniger als 90 Grad gedreht werden?

Ich mache dies mit RotateSimple, aber das ist auf ein Vielfaches von 90 Grad beschränkt.

Gibt es innerhalb GDK eine Möglichkeit, Bilder in Pixbuf-Puffern um 45 Grad (oder weniger) zu drehen?

Antwort

1

Nein, nicht mit RotateSimple (oder gdk_pixbuf_rotate_simple() in den zugrunde liegenden Bibliotheken). Gemäß der documentation ist das auf "um ein Vielfaches von 90 Grad" begrenzt.

jedoch eine Sache, die Sie kann tun ist, mehrere Bilder zur Verfügung stellen, um es erscheinen , als ob Sie durch einen kleineren Wert drehen.

Für Ihr spezifisches Beispiel von 45 Grad werden nur zwei Bilder benötigt. Das erste ist das "aufrechte" Bild, für das Sie 90-Grad-Drehungen verwenden können (d. H. Unter Verwendung von SimpleRotate), um vier der acht erforderlichen Drehungen zu erhalten, 0, 90, 180 und 270.

Um die andere vier Möglichkeiten zu erhalten, legen Sie das Bild in einige Bildbearbeitungssoftware und verwenden Sie das, um es um 45 Grad zu drehen, speichern Sie es als das "gekippte" Bild.

Auf diese Weise können Sie alle Möglichkeiten durch den Einsatz verschiedener Drehungen der beiden Bilder erhalten:

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 

Für weitere feinkörnige Drehungen Sie eine ähnliche Sache tun können, besonders, wenn die Auflösung der Rotation ist ein Faktor von 360. Und dank der vorausschauenden Natur der Babylonier (oder Sumerer oder jemand, meine Geschichte ist ein bisschen eingerostet), hat 360 eine ziemlich große Anzahl von Faktoren.

2

Ich habe eine Allzweck-Pixbuf-Rotater-Funktion geschrieben. Argumente:

  1. src - pixbuf
  2. Radiant zu drehen - Winkel, um den sich zu drehen (in Bogenmaß)
  3. full_size - Diese Funktion arbeitet in zwei Modi . Es wird entweder einen neuen Pixbuf erzeugen, der gerade groß genug ist, um das vollständig gedrehte Bild zu enthalten (plus ein paar zusätzliche Dreiecke, wo Alpha = 0 ist), oder es wird ein Pixbuf erzeugt, der so groß ist wie das Maximum (horizontal/vertikal)) Rechteck innerhalb des gedrehten Bildes. Wenn full_size true ist, wird das größere Rechteck mit (leere Ecken) erzeugt. Wenn full_size false ist, dann das kleinere Rechteck. Wenn sich um fast 45 Grad dreht, kann das kleine Rechteck eine Größe 0 haben und ein NULL Pixbuf wird zurückgegeben.

    #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); 
    }
Verwandte Themen