Back to index

php5  5.3.10
gd_rotate.c
Go to the documentation of this file.
00001 #if HAVE_GD_BUNDLED
00002 # include "gd.h"
00003 #else
00004 # include <gd.h>
00005 #endif
00006 
00007 #include "gd_intern.h"
00008 #include <math.h>
00009 
00010 /*
00011  * Rotate function Added on 2003/12
00012  * by Pierre-Alain Joye (pierre@php.net)
00013  **/
00014 /* Begin rotate function */
00015 #ifdef ROTATE_PI
00016 #undef ROTATE_PI
00017 #endif /* ROTATE_PI */
00018 
00019 #define ROTATE_DEG2RAD  3.1415926535897932384626433832795/180
00020 void gdImageSkewX (gdImagePtr dst, gdImagePtr src, int uRow, int iOffset, double dWeight, int clrBack, int ignoretransparent)
00021 {
00022        typedef int (*FuncPtr)(gdImagePtr, int, int);
00023        int i, r, g, b, a, clrBackR, clrBackG, clrBackB, clrBackA;
00024        FuncPtr f;
00025 
00026        int pxlOldLeft, pxlLeft=0, pxlSrc;
00027 
00028        /* Keep clrBack as color index if required */
00029        if (src->trueColor) {
00030               pxlOldLeft = clrBack;
00031               f = gdImageGetTrueColorPixel;
00032        } else {
00033               pxlOldLeft = clrBack;
00034               clrBackR = gdImageRed(src, clrBack);
00035               clrBackG = gdImageGreen(src, clrBack);
00036               clrBackB = gdImageBlue(src, clrBack);
00037               clrBackA = gdImageAlpha(src, clrBack);
00038               clrBack =  gdTrueColorAlpha(clrBackR, clrBackG, clrBackB, clrBackA);
00039               f = gdImageGetPixel;
00040        }
00041 
00042        for (i = 0; i < iOffset; i++) {
00043               gdImageSetPixel (dst, i, uRow, clrBack);
00044        }
00045 
00046        if (i < dst->sx) {
00047               gdImageSetPixel (dst, i, uRow, clrBack);
00048        }
00049 
00050        for (i = 0; i < src->sx; i++) {
00051               pxlSrc = f (src,i,uRow);
00052 
00053               r = (int)(gdImageRed(src,pxlSrc) * dWeight);
00054               g = (int)(gdImageGreen(src,pxlSrc) * dWeight);
00055               b = (int)(gdImageBlue(src,pxlSrc) * dWeight);
00056               a = (int)(gdImageAlpha(src,pxlSrc) * dWeight);
00057 
00058               pxlLeft = gdImageColorAllocateAlpha(src, r, g, b, a);
00059 
00060               if (pxlLeft == -1) {
00061                      pxlLeft = gdImageColorClosestAlpha(src, r, g, b, a);
00062               }
00063 
00064               r = gdImageRed(src,pxlSrc) - (gdImageRed(src,pxlLeft) - gdImageRed(src,pxlOldLeft));
00065               g = gdImageGreen(src,pxlSrc) - (gdImageGreen(src,pxlLeft) - gdImageGreen(src,pxlOldLeft));
00066               b = gdImageBlue(src,pxlSrc) - (gdImageBlue(src,pxlLeft) - gdImageBlue(src,pxlOldLeft));
00067               a = gdImageAlpha(src,pxlSrc) - (gdImageAlpha(src,pxlLeft) - gdImageAlpha(src,pxlOldLeft));
00068 
00069         if (r>255) {
00070               r = 255;
00071         }
00072 
00073               if (g>255) {
00074                      g = 255;
00075               }
00076 
00077               if (b>255) {
00078                      b = 255;
00079               }
00080 
00081               if (a>127) {
00082                      a = 127;
00083               }
00084 
00085               if (ignoretransparent && pxlSrc == dst->transparent) {
00086                      pxlSrc = dst->transparent;
00087               } else {
00088                      pxlSrc = gdImageColorAllocateAlpha(dst, r, g, b, a);
00089 
00090                      if (pxlSrc == -1) {
00091                             pxlSrc = gdImageColorClosestAlpha(dst, r, g, b, a);
00092                      }
00093               }
00094 
00095               if ((i + iOffset >= 0) && (i + iOffset < dst->sx)) {
00096                      gdImageSetPixel (dst, i+iOffset, uRow,  pxlSrc);
00097               }
00098 
00099               pxlOldLeft = pxlLeft;
00100        }
00101 
00102        i += iOffset;
00103 
00104        if (i < dst->sx) {
00105               gdImageSetPixel (dst, i, uRow, pxlLeft);
00106        }
00107 
00108        gdImageSetPixel (dst, iOffset, uRow, clrBack);
00109 
00110        i--;
00111 
00112        while (++i < dst->sx) {
00113               gdImageSetPixel (dst, i, uRow, clrBack);
00114        }
00115 }
00116 
00117 void gdImageSkewY (gdImagePtr dst, gdImagePtr src, int uCol, int iOffset, double dWeight, int clrBack, int ignoretransparent)
00118 {
00119        typedef int (*FuncPtr)(gdImagePtr, int, int);
00120        int i, iYPos=0, r, g, b, a;
00121        FuncPtr f;
00122        int pxlOldLeft, pxlLeft=0, pxlSrc;
00123 
00124        if (src->trueColor) {
00125               f = gdImageGetTrueColorPixel;
00126        } else {
00127               f = gdImageGetPixel;
00128        }
00129 
00130        for (i = 0; i<=iOffset; i++) {
00131               gdImageSetPixel (dst, uCol, i, clrBack);
00132        }
00133        r = (int)((double)gdImageRed(src,clrBack) * dWeight);
00134        g = (int)((double)gdImageGreen(src,clrBack) * dWeight);
00135        b = (int)((double)gdImageBlue(src,clrBack) * dWeight);
00136        a = (int)((double)gdImageAlpha(src,clrBack) * dWeight);
00137 
00138        pxlOldLeft = gdImageColorAllocateAlpha(dst, r, g, b, a);
00139 
00140        for (i = 0; i < src->sy; i++) {
00141               pxlSrc = f (src, uCol, i);
00142               iYPos = i + iOffset;
00143 
00144               r = (int)((double)gdImageRed(src,pxlSrc) * dWeight);
00145               g = (int)((double)gdImageGreen(src,pxlSrc) * dWeight);
00146               b = (int)((double)gdImageBlue(src,pxlSrc) * dWeight);
00147               a = (int)((double)gdImageAlpha(src,pxlSrc) * dWeight);
00148 
00149               pxlLeft = gdImageColorAllocateAlpha(src, r, g, b, a);
00150 
00151               if (pxlLeft == -1) {
00152                      pxlLeft = gdImageColorClosestAlpha(src, r, g, b, a);
00153               }
00154 
00155               r = gdImageRed(src,pxlSrc) - (gdImageRed(src,pxlLeft) - gdImageRed(src,pxlOldLeft));
00156               g = gdImageGreen(src,pxlSrc) - (gdImageGreen(src,pxlLeft) - gdImageGreen(src,pxlOldLeft));
00157               b = gdImageBlue(src,pxlSrc) - (gdImageBlue(src,pxlLeft) - gdImageBlue(src,pxlOldLeft));
00158               a = gdImageAlpha(src,pxlSrc) - (gdImageAlpha(src,pxlLeft) - gdImageAlpha(src,pxlOldLeft));
00159 
00160               if (r>255) {
00161                      r = 255;
00162               }
00163 
00164               if (g>255) {
00165                      g = 255;
00166               }
00167 
00168               if (b>255) {
00169                      b = 255;
00170               }
00171 
00172               if (a>127) {
00173                      a = 127;
00174               }
00175 
00176               if (ignoretransparent && pxlSrc == dst->transparent) {
00177                      pxlSrc = dst->transparent;
00178               } else {
00179                      pxlSrc = gdImageColorAllocateAlpha(dst, r, g, b, a);
00180 
00181                      if (pxlSrc == -1) {
00182                             pxlSrc = gdImageColorClosestAlpha(dst, r, g, b, a);
00183                      }
00184               }
00185 
00186               if ((iYPos >= 0) && (iYPos < dst->sy)) {
00187                      gdImageSetPixel (dst, uCol, iYPos, pxlSrc);
00188               }
00189 
00190               pxlOldLeft = pxlLeft;
00191        }
00192 
00193        i = iYPos;
00194        if (i < dst->sy) {
00195               gdImageSetPixel (dst, uCol, i, pxlLeft);
00196        }
00197 
00198        i--;
00199        while (++i < dst->sy) {
00200               gdImageSetPixel (dst, uCol, i, clrBack);
00201        }
00202 }
00203 
00204 /* Rotates an image by 90 degrees (counter clockwise) */
00205 gdImagePtr gdImageRotate90 (gdImagePtr src, int ignoretransparent)
00206 {
00207        int uY, uX;
00208        int c,r,g,b,a;
00209        gdImagePtr dst;
00210        typedef int (*FuncPtr)(gdImagePtr, int, int);
00211        FuncPtr f;
00212 
00213        if (src->trueColor) {
00214               f = gdImageGetTrueColorPixel;
00215        } else {
00216               f = gdImageGetPixel;
00217        }
00218        dst = gdImageCreateTrueColor(src->sy, src->sx);
00219        dst->transparent = src->transparent;
00220 
00221        if (dst != NULL) {
00222               int old_blendmode = dst->alphaBlendingFlag;
00223               dst->alphaBlendingFlag = 0;
00224 
00225               gdImagePaletteCopy (dst, src);
00226 
00227               for (uY = 0; uY<src->sy; uY++) {
00228                      for (uX = 0; uX<src->sx; uX++) {
00229                             c = f (src, uX, uY);
00230                             if (!src->trueColor) {
00231                                    r = gdImageRed(src,c);
00232                                    g = gdImageGreen(src,c);
00233                                    b = gdImageBlue(src,c);
00234                                    a = gdImageAlpha(src,c);
00235                                    c = gdTrueColorAlpha(r, g, b, a);
00236                             }
00237                             if (ignoretransparent && c == dst->transparent) {
00238                                    gdImageSetPixel(dst, uY, (dst->sy - uX - 1), dst->transparent);
00239                             } else {
00240                                    gdImageSetPixel(dst, uY, (dst->sy - uX - 1), c);
00241                             }
00242                      }
00243               }
00244               dst->alphaBlendingFlag = old_blendmode;
00245        }
00246 
00247        return dst;
00248 }
00249 
00250 /* Rotates an image by 180 degrees (counter clockwise) */
00251 gdImagePtr gdImageRotate180 (gdImagePtr src, int ignoretransparent)
00252 {
00253        int uY, uX;
00254        int c,r,g,b,a;
00255        gdImagePtr dst;
00256        typedef int (*FuncPtr)(gdImagePtr, int, int);
00257        FuncPtr f;
00258 
00259        if (src->trueColor) {
00260               f = gdImageGetTrueColorPixel;
00261        } else {
00262               f = gdImageGetPixel;
00263        }
00264        dst = gdImageCreateTrueColor(src->sx, src->sy);
00265        dst->transparent = src->transparent;
00266 
00267        if (dst != NULL) {
00268               int old_blendmode = dst->alphaBlendingFlag;
00269               dst->alphaBlendingFlag = 0;
00270 
00271               gdImagePaletteCopy (dst, src);
00272 
00273               for (uY = 0; uY<src->sy; uY++) {
00274                      for (uX = 0; uX<src->sx; uX++) {
00275                             c = f (src, uX, uY);
00276                             if (!src->trueColor) {
00277                                    r = gdImageRed(src,c);
00278                                    g = gdImageGreen(src,c);
00279                                    b = gdImageBlue(src,c);
00280                                    a = gdImageAlpha(src,c);
00281                                    c = gdTrueColorAlpha(r, g, b, a);
00282                             }
00283 
00284                             if (ignoretransparent && c == dst->transparent) {
00285                                    gdImageSetPixel(dst, (dst->sx - uX - 1), (dst->sy - uY - 1), dst->transparent);
00286                             } else {
00287                                    gdImageSetPixel(dst, (dst->sx - uX - 1), (dst->sy - uY - 1), c);
00288                             }
00289                      }
00290               }
00291               dst->alphaBlendingFlag = old_blendmode;
00292        }
00293 
00294        return dst;
00295 }
00296 
00297 /* Rotates an image by 270 degrees (counter clockwise) */
00298 gdImagePtr gdImageRotate270 (gdImagePtr src, int ignoretransparent)
00299 {
00300        int uY, uX;
00301        int c,r,g,b,a;
00302        gdImagePtr dst;
00303        typedef int (*FuncPtr)(gdImagePtr, int, int);
00304        FuncPtr f;
00305 
00306        if (src->trueColor) {
00307               f = gdImageGetTrueColorPixel;
00308        } else {
00309               f = gdImageGetPixel;
00310        }
00311        dst = gdImageCreateTrueColor (src->sy, src->sx);
00312        dst->transparent = src->transparent;
00313 
00314        if (dst != NULL) {
00315               int old_blendmode = dst->alphaBlendingFlag;
00316               dst->alphaBlendingFlag = 0;
00317 
00318               gdImagePaletteCopy (dst, src);
00319 
00320               for (uY = 0; uY<src->sy; uY++) {
00321                      for (uX = 0; uX<src->sx; uX++) {
00322                             c = f (src, uX, uY);
00323                             if (!src->trueColor) {
00324                                    r = gdImageRed(src,c);
00325                                    g = gdImageGreen(src,c);
00326                                    b = gdImageBlue(src,c);
00327                                    a = gdImageAlpha(src,c);
00328                                    c = gdTrueColorAlpha(r, g, b, a);
00329                             }
00330 
00331                             if (ignoretransparent && c == dst->transparent) {
00332                                    gdImageSetPixel(dst, (dst->sx - uY - 1), uX, dst->transparent);
00333                             } else {
00334                                    gdImageSetPixel(dst, (dst->sx - uY - 1), uX, c);
00335                             }
00336                      }
00337               }
00338               dst->alphaBlendingFlag = old_blendmode;
00339        }
00340 
00341        return dst;
00342 }
00343 
00344 gdImagePtr gdImageRotate45 (gdImagePtr src, double dAngle, int clrBack, int ignoretransparent)
00345 {
00346        typedef int (*FuncPtr)(gdImagePtr, int, int);
00347        gdImagePtr dst1,dst2,dst3;
00348        FuncPtr f;
00349        double dRadAngle, dSinE, dTan, dShear;
00350        double dOffset;     /* Variable skew offset */
00351        int u, iShear, newx, newy;
00352        int clrBackR, clrBackG, clrBackB, clrBackA;
00353 
00354        /* See GEMS I for the algorithm details */
00355        dRadAngle = dAngle * ROTATE_DEG2RAD; /* Angle in radians */
00356        dSinE = sin (dRadAngle);
00357        dTan = tan (dRadAngle / 2.0);
00358 
00359        newx = (int)(src->sx + src->sy * fabs(dTan));
00360        newy = src->sy;
00361 
00362        /* 1st shear */
00363        if (src->trueColor) {
00364               f = gdImageGetTrueColorPixel;
00365        } else {
00366               f = gdImageGetPixel;
00367        }
00368 
00369        dst1 = gdImageCreateTrueColor(newx, newy);
00370        /******* Perform 1st shear (horizontal) ******/
00371        if (dst1 == NULL) {
00372               return NULL;
00373        }
00374 #ifdef HAVE_GD_BUNDLED
00375        dst1->alphaBlendingFlag = gdEffectReplace;
00376 #else
00377        gdImageAlphaBlending(dst1, 0);
00378 #endif
00379        if (dAngle == 0.0) {
00380               /* Returns copy of src */
00381               gdImageCopy (dst1, src,0,0,0,0,src->sx,src->sy);
00382               return dst1;
00383        }
00384 
00385        gdImagePaletteCopy (dst1, src);
00386 
00387        if (ignoretransparent) {
00388               if (gdImageTrueColor(src)) {
00389                      dst1->transparent = src->transparent;
00390               } else {
00391 
00392                      dst1->transparent = gdTrueColorAlpha(gdImageRed(src, src->transparent), gdImageBlue(src, src->transparent), gdImageGreen(src, src->transparent), 127);
00393               }
00394        }
00395 
00396        dRadAngle = dAngle * ROTATE_DEG2RAD; /* Angle in radians */
00397        dSinE = sin (dRadAngle);
00398        dTan = tan (dRadAngle / 2.0);
00399 
00400        for (u = 0; u < dst1->sy; u++) {
00401               if (dTan >= 0.0) {
00402                      dShear = ((double)(u + 0.5)) * dTan;
00403               } else {
00404                      dShear = ((double)(u - dst1->sy) + 0.5) * dTan;
00405               }
00406 
00407               iShear = (int)floor(dShear);
00408               gdImageSkewX(dst1, src, u, iShear, (dShear - iShear), clrBack, ignoretransparent);
00409        }
00410 
00411        /*
00412        The 1st shear may use the original clrBack as color index
00413        Convert it once here
00414        */
00415        if(!src->trueColor) {
00416               clrBackR = gdImageRed(src, clrBack);
00417               clrBackG = gdImageGreen(src, clrBack);
00418               clrBackB = gdImageBlue(src, clrBack);
00419               clrBackA = gdImageAlpha(src, clrBack);
00420               clrBack =  gdTrueColorAlpha(clrBackR, clrBackG, clrBackB, clrBackA);
00421        }
00422        /* 2nd shear */
00423        newx = dst1->sx;
00424 
00425        if (dSinE > 0.0) {
00426               dOffset = (src->sx-1) * dSinE;
00427        } else {
00428               dOffset = -dSinE *  (src->sx - newx);
00429        }
00430 
00431        newy = (int) ((double) src->sx * fabs( dSinE ) + (double) src->sy * cos (dRadAngle))+1;
00432 
00433        if (src->trueColor) {
00434               f = gdImageGetTrueColorPixel;
00435        } else {
00436               f = gdImageGetPixel;
00437        }
00438        dst2 = gdImageCreateTrueColor(newx, newy);
00439        if (dst2 == NULL) {
00440               gdImageDestroy(dst1);
00441               return NULL;
00442        }
00443 
00444 #ifdef HAVE_GD_BUNDLED
00445        dst2->alphaBlendingFlag = gdEffectReplace;
00446 #else
00447        gdImageAlphaBlending(dst2, 0);
00448 #endif
00449 
00450        if (ignoretransparent) {
00451               dst2->transparent = dst1->transparent;
00452        }
00453 
00454        for (u = 0; u < dst2->sx; u++, dOffset -= dSinE) {
00455               iShear = (int)floor (dOffset);
00456               gdImageSkewY(dst2, dst1, u, iShear, (dOffset - (double)iShear), clrBack, ignoretransparent);
00457        }
00458 
00459        /* 3rd shear */
00460        gdImageDestroy(dst1);
00461 
00462        newx = (int) ((double)src->sy * fabs (dSinE) + (double)src->sx * cos (dRadAngle)) + 1;
00463        newy = dst2->sy;
00464 
00465        if (src->trueColor) {
00466               f = gdImageGetTrueColorPixel;
00467        } else {
00468               f = gdImageGetPixel;
00469        }
00470        dst3 = gdImageCreateTrueColor(newx, newy);
00471        if (dst3 == NULL) {
00472               gdImageDestroy(dst2);
00473               return NULL;
00474        }
00475 
00476 #ifdef HAVE_GD_BUNDLED
00477        dst3->alphaBlendingFlag = gdEffectReplace;
00478 #else
00479        gdImageAlphaBlending(dst3, 0);
00480 #endif
00481 
00482        if (ignoretransparent) {
00483               dst3->transparent = dst2->transparent;
00484        }
00485 
00486        if (dSinE >= 0.0) {
00487               dOffset = (double)(src->sx - 1) * dSinE * -dTan;
00488        } else {
00489               dOffset = dTan * ((double)(src->sx - 1) * -dSinE + (double)(1 - newy));
00490        }
00491 
00492        for (u = 0; u < dst3->sy; u++, dOffset += dTan) {
00493               int iShear = (int)floor(dOffset);
00494               gdImageSkewX(dst3, dst2, u, iShear, (dOffset - iShear), clrBack, ignoretransparent);
00495        }
00496 
00497        gdImageDestroy(dst2);
00498 
00499        return dst3;
00500 }
00501 
00502 gdImagePtr gdImageRotate (gdImagePtr src, double dAngle, int clrBack, int ignoretransparent)
00503 {
00504        gdImagePtr pMidImg;
00505        gdImagePtr rotatedImg;
00506 
00507        if (src == NULL) {
00508               return NULL;
00509        }
00510 
00511        if (!gdImageTrueColor(src) && (clrBack < 0 || clrBack>=gdImageColorsTotal(src))) {
00512               return NULL;
00513        }
00514 
00515        while (dAngle >= 360.0) {
00516               dAngle -= 360.0;
00517        }
00518 
00519        while (dAngle < 0) {
00520               dAngle += 360.0;
00521        }
00522 
00523        if (dAngle == 90.00) {
00524               return gdImageRotate90(src, ignoretransparent);
00525        }
00526        if (dAngle == 180.00) {
00527               return gdImageRotate180(src, ignoretransparent);
00528        }
00529        if(dAngle == 270.00) {
00530               return gdImageRotate270 (src, ignoretransparent);
00531        }
00532 
00533        if ((dAngle > 45.0) && (dAngle <= 135.0)) {
00534               pMidImg = gdImageRotate90 (src, ignoretransparent);
00535               dAngle -= 90.0;
00536        } else if ((dAngle > 135.0) && (dAngle <= 225.0)) {
00537               pMidImg = gdImageRotate180 (src, ignoretransparent);
00538               dAngle -= 180.0;
00539        } else if ((dAngle > 225.0) && (dAngle <= 315.0)) {
00540               pMidImg = gdImageRotate270 (src, ignoretransparent);
00541               dAngle -= 270.0;
00542        } else {
00543               return gdImageRotate45 (src, dAngle, clrBack, ignoretransparent);
00544        }
00545 
00546        if (pMidImg == NULL) {
00547               return NULL;
00548        }
00549 
00550        rotatedImg = gdImageRotate45 (pMidImg, dAngle, clrBack, ignoretransparent);
00551        gdImageDestroy(pMidImg);
00552 
00553        return rotatedImg;
00554 }
00555 /* End Rotate function */
00556 
00557