private bool PtinConvexPolygon(AafPnt[] p, AafPnt pt) { int dir = 0; int j; //Basically what we are doing is seeing if pt is on the same side of each face of the polygon through cross multiplication for (int i = 0; i < 4; i++) { j = ja[i]; double cross = (p[i].x - pt.x) * (p[j].y - pt.y) - (p[j].x - pt.x) * (p[i].y - pt.y); if (cross == 0) { continue; } if (cross > 0) { if (dir == -1) { return(false); } dir = 1; } else { if (dir == 1) { return(false); } dir = -1; } } return(true); }
private void DoTransform(Bitmap src, Bitmap dst, Aaf_callback callbackfunc) { //Get source bitmap's information if (src == null) { return; } //Create the source dib array and the dstdib array aaf_dblrgbquad[] dbldstdib = new aaf_dblrgbquad[outwidth * outheight]; for (int i = 0; i < dbldstdib.Length; i++) { dbldstdib[i] = new aaf_dblrgbquad(); } //Create polygon arrays AafPnt[] p = new AafPnt[4]; AafPnt[] poffset = new AafPnt[4]; //Loop through the source's pixels //遍历原图(实质上是pixelgrid)各个点 for (int x = 0; x < src.Width; x++) { for (int y = 0; y < src.Height; y++) { //取当前点 下一点 右一点 斜右下角点 四点才组成一个四边形 //这个四边形是原图像的一个像素点 //Construct the source pixel's rotated polygon from pixelgrid p[0] = pixelgrid[x + y * (src.Width + 1)]; p[1] = pixelgrid[(x + 1) + y * (src.Width + 1)]; p[2] = pixelgrid[(x + 1) + (y + 1) * (src.Width + 1)]; p[3] = pixelgrid[x + (y + 1) * (src.Width + 1)]; //Find the scan area on the destination's pixels int mindx = int.MaxValue; int mindy = int.MaxValue; int maxdx = int.MinValue; int maxdy = int.MinValue; for (int i = 0; i < 4; i++) { if (rounddown(p[i].x) < mindx) { mindx = rounddown(p[i].x); } if (roundup(p[i].x) > maxdx) { maxdx = roundup(p[i].x); } if (rounddown(p[i].y) < mindy) { mindy = rounddown(p[i].y); } if (roundup(p[i].y) > maxdy) { maxdy = roundup(p[i].y); } } int SrcIndex = x + y * src.Width; //遍历四边形包含了目标图几个像素点 //按照相交面积占整个像素的的百分比,把颜色按照该比例存放一个目标像素点颜色的数组中 //这里计算出来的颜色只是初步颜色,还没到最终结果 //loop through the scan area to find where source(x, y) overlaps with the destination pixels for (int xx = mindx - 1; xx <= maxdx; xx++) { if (xx < 0 || xx >= dst.Width) { continue; } for (int yy = mindy - 1; yy <= maxdy; yy++) { if (yy < 0 || yy >= dst.Height) { continue; } //offset p and by (xx,yy) and put that into poffset for (int i = 0; i < 4; i++) { poffset[i].x = p[i].x - xx; poffset[i].y = p[i].y - yy; } //FIND THE OVERLAP *a whole lot of code pays off here* //这里则是计算出覆盖了面积占当前像素的百分比 double dbloverlap = PixOverlap(poffset); //按照百分比来为目标像素点累加颜色 //因为一个目标像素点有可能有几个原来像素的覆盖了 if (dbloverlap > 0) { int dstindex = xx + yy * outwidth; int srcWidth = src.Width; Color srcColor; if (SrcIndex == 0) { srcColor = src.GetPixel(0, 0); } else { srcColor = src.GetPixel(SrcIndex % src.Width, SrcIndex / src.Width); } //Add the rgb and alpha values in proportion to the overlap area dbldstdib[dstindex].Red += (double)((srcColor.R) * dbloverlap); dbldstdib[dstindex].Blue += (double)(srcColor.B) * dbloverlap; dbldstdib[dstindex].Green += (double)(srcColor.G) * dbloverlap; dbldstdib[dstindex].Alpha += dbloverlap; } } } } if (callbackfunc != null) { //Send the callback message double percentdone = (double)(x + 1) / (double)(src.Width); if (callbackfunc(percentdone)) { dbldstdib = null; p = null; poffset = null; return; } } } //Free memory no longer needed //Create final destination bits RGBQUDA[] dstdib = new RGBQUDA[dst.Width * dst.Height]; for (int i = 0; i < dstdib.Length; i++) { dstdib[i] = new RGBQUDA() { R = 0, G = 0, B = 0, A = 1 } } ; //这里是实际上真正像素点的颜色,并且填到了目标图片中去 //Write to dstdib with the information stored in dbldstdib for (int x = 0; x < outwidth; x++) { if (x + outstartx >= dst.Width) { continue; } for (int y = 0; y < outheight; y++) { if (y + outstarty >= dst.Height) { continue; } int offindex = x + y * outwidth; int dstindex = x + outstartx + (y + outstarty) * dst.Width; int dstIndexX = dstindex / dst.Width; int dstIndexY = dstindex % dst.Width; if (dbldstdib[offindex].Alpha > 1) { //handles wrap around for non-convex transformations dstdib[dstindex].R = byterange(dbldstdib[offindex].Red / dbldstdib[offindex].Alpha); dstdib[dstindex].G = byterange(dbldstdib[offindex].Green / dbldstdib[offindex].Alpha); dstdib[dstindex].B = byterange(dbldstdib[offindex].Blue / dbldstdib[offindex].Alpha); dstdib[dstindex].A = byterange(dbldstdib[offindex].Alpha / dbldstdib[offindex].Alpha); } else { //Color dstColor = dst.GetPixel(dstIndexX, dstIndexY); dstdib[dstindex].R = byterange(dbldstdib[offindex].Red + (1 - dbldstdib[offindex].Alpha) * (double)dstdib[dstindex].R); dstdib[dstindex].G = byterange(dbldstdib[offindex].Green + (1 - dbldstdib[offindex].Alpha) * (double)dstdib[dstindex].G); dstdib[dstindex].B = byterange(dbldstdib[offindex].Blue + (1 - dbldstdib[offindex].Alpha) * (double)dstdib[dstindex].B); dstdib[dstindex].A = byterange(dbldstdib[offindex].Alpha + (1 - dbldstdib[offindex].Alpha) * (double)dstdib[dstindex].A); } dst.SetPixel(dstIndexY, dstIndexX, Color.FromArgb((int)(1.0 * dbldstdib[dstindex].Alpha * 255), dstdib[dstindex].R, dstdib[dstindex].G, dstdib[dstindex].B)); //dst.SetPixel(dstIndexY, dstIndexX, Color.FromArgb((int)dbldstdib[offindex].Red, (int)dbldstdib[offindex].Green, (int)dbldstdib[offindex].Blue, (int)dbldstdib[offindex].Alpha)); } } //:D return; } double PixOverlap(AafPnt[] p) { polyoverlapsize = 0; polysortedsize = 0; double minx, maxx, miny, maxy; int j; double z; for (int i = 0; i < 4; i++) { //Search for source points within the destination quadrolateral if (p[i].x >= 0 && p[i].x <= 1 && p[i].y >= 0 && p[i].y <= 1) { polyoverlap[polyoverlapsize++] = p[i]; } //Search for destination points within the source quadrolateral if (PtinConvexPolygon(p, corners[i])) { polyoverlap[polyoverlapsize++] = corners[i]; } //Search for line intersections j = ja[i]; minx = aaf_min(p[i].x, p[j].x); miny = aaf_min(p[i].y, p[j].y); maxx = aaf_max(p[i].x, p[j].x); maxy = aaf_max(p[i].y, p[j].y); if (minx < 0.0 && 0.0 < maxx) {//Cross left z = p[i].y - p[i].x * (p[i].y - p[j].y) / (p[i].x - p[j].x); if (z >= 0.0 && z <= 1.0) { polyoverlap[polyoverlapsize].x = 0.0; polyoverlap[polyoverlapsize++].y = z; } } if (minx < 1.0 && 1.0 < maxx) {//Cross right z = p[i].y + (1 - p[i].x) * (p[i].y - p[j].y) / (p[i].x - p[j].x); if (z >= 0.0 && z <= 1.0) { polyoverlap[polyoverlapsize].x = 1.0; polyoverlap[polyoverlapsize++].y = z; } } if (miny < 0.0 && 0.0 < maxy) {//Cross bottom z = p[i].x - p[i].y * (p[i].x - p[j].x) / (p[i].y - p[j].y); if (z >= 0.0 && z <= 1.0) { polyoverlap[polyoverlapsize].x = z; polyoverlap[polyoverlapsize++].y = 0.0; } } if (miny < 1.0 && 1.0 < maxy) {//Cross top z = p[i].x + (1 - p[i].y) * (p[i].x - p[j].x) / (p[i].y - p[j].y); if (z >= 0.0 && z <= 1.0) { polyoverlap[polyoverlapsize].x = z; polyoverlap[polyoverlapsize++].y = 1.0; } } } //Sort the points and return the area SortPoints(); return(Area()); }