freetype
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [ft] Drawing unfilled shapes with FreeType2


From: Werner LEMBERG
Subject: Re: [ft] Drawing unfilled shapes with FreeType2
Date: Sun, 09 Nov 2014 12:40:30 +0100 (CET)

>> What about using `FT_Stroker_ParseOutline' after transformation of the
>> outline?
> 
> I've tried that of course but it doesn't make a difference and I
> don't understand why.

There were some errors in your code, fixed in the attachment, together
with some comments.


    Werner
#include <stdio.h>
#include <math.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_OUTLINE_H
#include FT_SYNTHESIS_H
#include FT_STROKER_H

static FT_Library freetype_library = NULL;

#define WIDTH 320
#define HEIGHT 240

// desired stroke thickness in pixels
#define STROKE_THICKNESS 8

#define setvector(pv, px, py) \
          (pv).x = ((int) (px)) << 6; \
          (pv).y = ((int) (py)) << 6;
#define Float2Fixed(fl) ((FT_Fixed)((fl)*65536.0f))

#define writew(fp, w) \
          tmpword = (w); \
          fwrite(&tmpword, 2, 1, (fp));
#define writel(fp, l) \
          tmplong = (l); \
          fwrite(&tmplong, 4, 1, (fp));


int main(int argc,
         char *argv[])
{
  FT_Stroker stroker;
  FT_UInt points, contours;
  FT_Outline outline;
  FT_BBox bbox;
  FT_Bitmap bm;
  FT_Vector v;
  FT_Matrix m;
  FT_Pos bbox_xMin, bbox_yMin;
  int x, y;
  int xmin, ymin, xmax, ymax;
  int pixelwidth, pixelheight, bytewidth;
  unsigned char *buf, *ptr;
  unsigned char *linebuf;
  unsigned short tmpword;
  unsigned long tmplong;
  FILE *fp;


  FT_Init_FreeType(&freetype_library);

  memset(&outline, 0, sizeof(FT_Outline));
  FT_Outline_New(freetype_library, 1024, 512, &outline);

  // It would be more efficient to directly construct an FT_Outline object
  // instead of doing that with a zero-radius stroker -- the latter produces
  // three additional overlapping points per point.

  FT_Stroker_New(freetype_library, &stroker);

  setvector(v, 0, 0);
  FT_Stroker_BeginSubPath(stroker, &v, 1);
  FT_Stroker_LineTo(stroker, &v);

  setvector(v, 0, 0);
  FT_Stroker_LineTo(stroker, &v);

  setvector(v, 0, HEIGHT);
  FT_Stroker_LineTo(stroker, &v);

  setvector(v, WIDTH, HEIGHT);
  FT_Stroker_LineTo(stroker, &v);

  setvector(v, WIDTH, 0);
  FT_Stroker_LineTo(stroker, &v);

  setvector(v, 0, 0);
  FT_Stroker_LineTo(stroker, &v);

  FT_Stroker_EndSubPath(stroker);

  // Construct an outline from the stroker.
  FT_Stroker_GetBorderCounts(stroker,
                             FT_STROKER_BORDER_LEFT,
                             &points,
                             &contours);
  outline.n_points = 0;
  outline.n_contours = 0;
  FT_Stroker_ExportBorder(stroker,
                          FT_STROKER_BORDER_LEFT,
                          &outline);

  // Transform the outline.
  m.xx = Float2Fixed(1.0);
  m.xy = Float2Fixed(0.0);
  m.yx = Float2Fixed(0.0);
  m.yy = Float2Fixed(0.5);

  FT_Outline_Transform(&outline, &m);

  // Redo the stroking operation, this time with a non-zero radius.
  FT_Stroker_Set(stroker,
                 (int) ((double) STROKE_THICKNESS * 32.0),
                 FT_STROKER_LINECAP_ROUND,
                 FT_STROKER_LINEJOIN_ROUND,
                 0);
  FT_Stroker_ParseOutline(stroker, &outline, 0);

  // Again construct an outline from the stroker.
  FT_Stroker_GetCounts(stroker,
                       &points,
                       &contours);
  outline.n_points = 0;
  outline.n_contours = 0;
  FT_Stroker_Export(stroker, &outline);

  FT_Stroker_Done(stroker);

  FT_Outline_Get_BBox(&outline, &bbox);

  bbox_xMin = bbox.xMin;
  bbox_yMin = bbox.yMin;

  FT_Outline_Translate(&outline, -bbox_xMin, -bbox_yMin);

  // Directly manipulating the bbox is much cheaper than calling
  // `FT_Outline_Get_BBox' again.
  bbox.xMin = 0;
  bbox.yMin = 0;
  bbox.xMax -= bbox_xMin;
  bbox.yMax -= bbox_yMin;

  xmin = bbox.xMin >> 6;
  ymin = bbox.yMin >> 6;
  xmax = bbox.xMax >> 6;
  ymax = bbox.yMax >> 6;

  if (bbox.xMax & 0x3f)
    xmax++;
  if (bbox.yMax & 0x3f)
    ymax++;

  pixelwidth = xmax - xmin;
  pixelheight = ymax - ymin;

  buf = calloc(pixelwidth * pixelheight, 1);

  memset(&bm, 0, sizeof(FT_Bitmap));
  bm.rows = pixelheight;
  bm.width = pixelwidth;
  bm.pitch = pixelwidth;
  bm.buffer = buf;
  bm.num_grays = 256;
  bm.pixel_mode = FT_PIXEL_MODE_GRAY;

  FT_Outline_Get_Bitmap(freetype_library, &outline, &bm);

  fp = fopen("dump.bmp", "wb");

  bytewidth = pixelwidth * 3 + pixelwidth % 4;
  linebuf = malloc(bytewidth);

  writew(fp, 0x4D42);
  writel(fp, bytewidth * pixelheight + 54);
  writel(fp, 0);
  writel(fp, 0x36);
  writel(fp, 0x28);
  writel(fp, pixelwidth);
  writel(fp, pixelheight);
  writew(fp, 1);
  writew(fp, 24);
  writel(fp, 0);
  writel(fp, 0);
  writel(fp, 0);
  writel(fp, 0);
  writel(fp, 0);
  writel(fp, 0);

  ptr = buf + pixelheight * pixelwidth;

  for (y = 0; y < pixelheight; y++)
  {
    unsigned char *l = linebuf;


    ptr -= pixelwidth;

    for (x = 0; x < pixelwidth; x++)
    {
      unsigned long rgb = ptr[x] * 65793;


      *l++ = (unsigned char) (rgb & 0x0000ff);
      *l++ = (unsigned char) ((rgb & 0x00ff00) >> 8);
      *l++ = (unsigned char) ((rgb & 0xff0000) >> 16);
    }

    fwrite(linebuf, bytewidth, 1, fp);
  }

  fclose(fp);
  free(linebuf);
  free(buf);

  FT_Outline_Done(freetype_library, &outline);
  FT_Done_FreeType(freetype_library);

  return 0;
}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]