public void Draw(GlyphBitmap other, int x, int y) { for (int j = 0; j < other.Height; j++) { for (int i = 0; i < other.Width; i++) { var srcOfs = i + j * other.Width; var destOfs = (x + i) + (y + j) * this.Width; Pixels[destOfs] = other.Pixels[srcOfs]; } } }
private void Rasterize(GlyphBitmap bitmap, float flatnessInPixels, List <Vertex> vertices, float scaleX, float scaleY, float shiftX, float shiftY, int XOff, int YOff, bool Invert) { float scale = scaleX < scaleY ? scaleX : scaleY; int[] windingLengths; List <Point> windings; FlattenCurves(vertices, flatnessInPixels / scale, out windingLengths, out windings); if (windings.Count > 0) { Rasterize(bitmap, windings, windingLengths, scaleX, scaleY, shiftX, shiftY, XOff, YOff, Invert); } }
/* * Computes a distance field transform of a high resolution binary source channel and returns the result as a low resolution channel. * * scale_down : The amount the source channel will be scaled down. * A value of 8 means the destination image will be 1/8th the size of the source * * spread: The spread in pixels before the distance field clamps to (zero/one). * The valueis specified in units of the destination image. The spread in the source image will be spread*scale_down. */ public static GlyphBitmap CreateDistanceField(GlyphBitmap source, int scale, float spread) { var result = new GlyphBitmap(source.Width / scale, source.Height / scale); var values = source.Pixels.Select(x => (x / 255.0f) - 0.5f).ToArray(); for (int y = 0; y < result.Height; y++) { for (int x = 0; x < result.Width; x++) { var sd = SignedDistance(values, source.Width, source.Height, x * scale, y * scale, spread); var n = (sd + spread) / (spread * 2.0f); var c = (byte)(n * 255); var offset = x + y * result.Width; result.Pixels[offset] = c; } } return(result); }
private GlyphBitmap GetGlyphBitmap(float scale_x, float scale_y, float shift_x, float shift_y, int glyph, out int xoff, out int yoff) { var vertices = GetGlyphShape(glyph); if (scale_x == 0) { scale_x = scale_y; } if (scale_y == 0) { if (scale_x == 0) { throw new Exception("invalid scale"); } scale_y = scale_x; } int ix0, iy0, ix1, iy1; GetGlyphBitmapBox(glyph, scale_x, scale_y, shift_x, shift_y, out ix0, out iy0, out ix1, out iy1); int w = (ix1 - ix0); int h = (iy1 - iy0); if (w <= 0 || h <= 0) { throw new Exception("invalid glyph size"); } // now we get the size var result = new GlyphBitmap(w, h); xoff = ix0; yoff = iy0; Rasterize(result, 0.35f, vertices, scale_x, scale_y, shift_x, shift_y, ix0, iy0, true); return(result); }
private void RasterizeSortedEdges(GlyphBitmap bitmap, List <Edge> e, int vSubSamples, int offX, int off_y) { int eIndex = 0; ActiveEdge active = null; int max_weight = 255 / vSubSamples; // weight per vertical scanline int y = off_y * vSubSamples; int n = e.Count - 1; var tempEdge = e[n]; tempEdge.y0 = (off_y + bitmap.Height) * vSubSamples + 1; e[n] = tempEdge; var scanline = new byte[bitmap.Width]; float scanY = 0; int j = 0; while (j < bitmap.Height) { for (int iii = 0; iii < bitmap.Width; iii++) { scanline[iii] = 0; } for (int s = 0; s < vSubSamples; s++) { // find center of pixel for this scanline scanY = y + 0.5f; // update all active edges; // remove all active edges that terminate before the center of this scanline var curr = active; ActiveEdge prev = null; while (curr != null) { if (curr.ey <= scanY) { // delete from list if (prev != null) { prev.next = curr.next; } else { active = curr.next; } curr = curr.next; } else { curr.x += curr.dx; // advance to position for current scanline prev = curr; curr = curr.next; // advance through list } } // resort the list if needed bool changed; do { changed = false; curr = active; prev = null; while (curr != null && curr.next != null) { var prox = curr.next; if (curr.x > prox.x) { if (prev == null) { active = prox; } else { prev.next = prox; } curr.next = prox.next; prox.next = curr; Console.WriteLine("Sorted " + curr.ey + " with " + prox.ey); changed = true; } prev = curr; curr = curr.next; // advance through list } } while (changed); // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline while (e[eIndex].y0 <= scanY) { if (e[eIndex].y1 > scanY) { var z = CreateActiveEdge(e[eIndex], offX, scanY); // find insertion point if (active == null) { active = z; } else if (z.x < active.x) // insert at front { z.next = active; active = z; } else { // find thing to insert AFTER var p = active; while (p.next != null && p.next.x < z.x) { p = p.next; } // at this point, p->next->x is NOT < z->x z.next = p.next; p.next = z; } } eIndex++; } // now process all active edges in XOR fashion if (active != null) { FillActiveEdges(scanline, bitmap.Width, active, max_weight); } y++; } for (int iii = 0; iii < bitmap.Width; iii++) { if (scanline[iii] > 0) // OPTIMIZATION? { int ofs = iii + j * bitmap.Width; bitmap.Pixels[ofs] = scanline[iii]; } } j++; } }
private void Rasterize(GlyphBitmap bitmap, List <Point> points, int[] windings, float scaleX, float scaleY, float shiftX, float shiftY, int XOff, int YOff, bool invert) { int ptOfs = 0; float yScaleInv = invert ? -scaleY : scaleY; // this value should divide 255 evenly; otherwise we won't reach full opacity int vSubSamples = (bitmap.Height < 8) ? 15 : 5; var edgeList = new List <Edge>(16); int m = 0; for (int i = 0; i < windings.Length; i++) { ptOfs = m; m += windings[i]; int j = windings[i] - 1; int k = 0; while (k < windings[i]) { int a = k; int b = j; var en = new Edge(); // skip the edge if horizontal if (points[ptOfs + j].y != points[ptOfs + k].y) { // add edge from j to k to the list en.invert = false; if ((invert && points[ptOfs + j].y > points[ptOfs + k].y) || (!invert && points[ptOfs + j].y < points[ptOfs + k].y)) { en.invert = true; a = j; b = k; } en.x0 = points[ptOfs + a].x * scaleX + shiftX; en.y0 = points[ptOfs + a].y * yScaleInv * vSubSamples + shiftY; en.x1 = points[ptOfs + b].x * scaleX + shiftX; en.y1 = points[ptOfs + b].y * yScaleInv * vSubSamples + shiftY; edgeList.Add(en); } j = k; k++; } } points.Clear(); // now sort the edges by their highest point (should snap to integer, and then by x) edgeList.Sort((x, y) => EdgeCompare(x, y)); var temp = new Edge(); temp.y0 = 10000000; edgeList.Add(temp); // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule RasterizeSortedEdges(bitmap, edgeList, vSubSamples, XOff, YOff); }