Giter Club home page Giter Club logo

canvas's Introduction

Taco de Wolff

A collection of integrated tools and libraries using the Go programming language.

  • prompt: Command line prompting by scanning into any variable type using a text, select, or checkbox input prompt.
  • argp: Command line argument parsing, including parsing lists and maps and configuration files.
  • font: Font parsing and manipulation for TTF, OTF, TTC, WOFF, WOFF2, and EOT file types.
    • cmd/fontinfo: Show font information and draw glyphs in terminal or as image.
    • cmd/fontsubset: Subset a font by selecting the given glyph IDs, glyph names, or literal characters.
  • locale: Handling of locale-specific parsing of dates, date intervals, currencies, etc using the CLDR dataset.
  • mail: Mail related utilities, including parsing DMARC and SMTP TLS reports and the milter protocol.
    • milter: A mail filter to prevent e-mail spoofing, use Sender Rewriting Scheme (SRS), and parse SMTP TLS/DMARC reports.
  • parse: Parsing utilities with parsers for (mainly) web formats, such as HTML, CSS, JS, JSON, and XML.
  • minify: High-performance minifiers for web file formats, such as HTML, CSS, JS, JSON, and XML.
  • canvas: Vector graphics library that can output raster images, SVGs, PDFs, HTML Canvas, TeX, PostScript, etc. file formats.

canvas's People

Contributors

adamgreenhall avatar arvidfm avatar carbocation avatar ceriath avatar dependabot[bot] avatar fengyoulin avatar fredim avatar goccy avatar hrko avatar jilieryuyi avatar kenshaw avatar kpym avatar nadavshatz avatar oliverpool avatar omniskop avatar rickb777 avatar tdewolff avatar ttt43ttt avatar twpayne avatar zzwx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

canvas's Issues

Support emojis

I would like to render emojis embedded in the text.

I have made a proof-of-concept that works like this:

  1. get the emojis as png from https://twemoji.twitter.com/ (they are also available as svg, but rendering svg is not trivial)
  2. make a list of all supported emojis (by converting the hex-name of the icons to the string of the emoji : 1f3c3-200d-2640-fe0f.png => 🏃‍♀️)
  3. give a function as a parameter to RichText to recognize the supported emojis from the input text (in RichText.Add)
  4. return the emojis with their coordinates from RichText.ToText (and replace its text with "" to prevent being it renderer as text)
  5. Get the associated png file from the filesystem and draw it as an image on the context.
  6. Example (ignore the strange newlines):
    out

Since the emoji influence the position of the letters (computed in RichText), this requires a modification of the core (and Text has unexported fields, so a 3-rd party package can't work).

However the rendering of the emojis does not have to be in the core (only the identification of the "supported emojis" must be integrated) - so no dependency on twemoji.

Would you consider such an addition to the library or do you think that this is way out of scope?
I can show you in a draft PR if you want to take a closer look at the modifications that I made.


Background: I am using this project for a small german startup (https://www.bilderbrief.de/) and my customers would ❤️ to send emojis 😉

DrawImage and opacity

I have a few hundred images that I am trying to combine, adding them with adjusted opacity. Just to clarify, along the lines of:

for i:=0; i<100; i++ {
  img := createImage(i)
  ctx.DrawImage(0, 0, img, 10)
}

Now, there are a couple of problems with this:

  1. I would like to change the opacity when drawing the image. I assume I would have to do that beforehand to the image.RGBA? Not sure how yet - but there is no way to do this with canvas, correct?
  2. It seems like drawing a lot of images is very resource hungry. Is there a way to optimize this? Or does it keep the images around and only combines them in the end?

drawImage has size error after image.bounds was modified

I'm adding crop feature now, and found a strange case.

At first, here is my code, I used module "github.com/oliamb/cutter"
@see the doc here, if you need

croppedImg, _ := cutter.Crop(img, cutter.Config{
	Width:  i.Clip.Width,
	Height: i.Clip.Height,
	Anchor: image.Point{i.Clip.X, i.Clip.Y},
})
img = croppedImg

// omitted some code, it doesn't matter
c.DrawImage(x, y, img, scale)

The image size was 430 * 430, I crop it, from startPos(30, 30) to (400, 400). after I doing this, img.Bounds() will lead to (30,30)-(400,400). this could be reason about the case.

image

So, I save the image to local. here is anthoer test,if I do this. the img.bounds() will be (0,0)-(370,370), and result is fine.

croppedImg, _ := cutter.Crop(img, cutter.Config{
	Width:  i.Clip.Width,
	Height: i.Clip.Height,
	Anchor: image.Point{i.Clip.X, i.Clip.Y},
})
img = croppedImg

f, err := os.Create("test_crop.jpg")
if err != nil {
	panic(err)
}
defer f.Close()
jpeg.Encode(f, img, nil)

// omitted some code, it doesn't matter
c.DrawImage(x, y, img, scale)

image

I've tried find reason about this, include try another crop image service from aliyun. but it shows similarity.

Here is some code from module "github.com/oliamb/cutter", I thinks it's normal implementation.

func Crop(img image.Image, c Config) (image.Image, error) {
	maxBounds := c.maxBounds(img.Bounds())
	size := c.computeSize(maxBounds, image.Point{c.Width, c.Height})
	cr := c.computedCropArea(img.Bounds(), size)
	cr = img.Bounds().Intersect(cr)

	if c.Options&Copy == Copy {
		return cropWithCopy(img, cr)
	}
	if dImg, ok := img.(subImageSupported); ok {
		return dImg.SubImage(cr), nil
	}
	return cropWithCopy(img, cr)
}

Thanks.

Printing

This projects outputs are impressive.

does anyone have advise about how to output to a print on each of the 3 os’s ?

I presume that EPS is the favored “protocol” ?

I did sne investigation on this a while ago and realized there is a standard that is cross platform - amen :)

https://en.m.wikipedia.org/wiki/Internet_Printing_Protocol

Consider splitting the Renderer into different packages

Currently this module is flat: all files and functions are in one package (except for the font and htmlcanvas package).

If someone wants to use this package to render PDF, it will still pull all the files and their dependencies (gonum for instance).

It should be possible to restructure this package to let the Canvas and Context at the root package (as well as the Renderer interface) and move all Renderer implementations to sub-packages (just like htmlcanvas).

Possible sub-packages (such structure could also encourage people to write their own Renderer in an external package):

  • pdf
  • raster (JPG, GIF, PNG)
  • svg
  • tex
  • eps
  • gonum

To prevent circular dependency, the SaveXXX methods will have to be moved to the respective sub-package (pdf.WriteFile(canvas.Context, "filename.pdf") for instance.

This could be implemented in 2 phases:

  • duplicate the code into a sub-folder, to see how it feels and if it works, without breaking anything
  • remove the code from the root package (breaking change - but since this package has no release yet, it is not bound by compatibility promises)

Pros/Cons

Benefits:

  • clearer code organization (one responsibility per package)
  • fewer dependencies, when a user exports to specific formats

Disadvantages:

  • breaking change
  • generation of the final file is a bit more complex from the user-side (pdf.WriteFile(c, "filename.pdf") instead of c.SavePDF("filename.pdf"))
  • git history gets harder to follow

Are there any other issues, that I didn't mention?
Do you think it could be worth a try?

SVG rendering: unescaped character in text box results in invalid SVG.

I noticed an issue where if a text box contains a character that needs to be escaped, the character is not escaped and the resulting SVG is invalid and cannot be opened.

If I manually escape the text before passing it into the text box (using html.EscapeString) then the resulting text box is rendered assuming the size of the text is the size of the escaped string, not the original. This means that if the text box has a centered horizontal alignment, then the text is not centered but slightly off to the left of center.

This may be related to text boxes being absolutely positioned, with the exact position being pre-calculated on the input string assuming the string is exactly what will be displayed to the user. If escaping is required, then escaping would need to happen after the position was calculated.

EG: with input string "text with &amp; symbol", the text box assumes the string is the size of "text with &amp; symbol", but as this is escaped, the resulting rendered SVG will display "text with & symbol" but positioned as if the string was "text with &amp; symbol".

I think this may be solved by something as simple as swapping this line here:

s = strings.ReplaceAll(s, `"`, `&quot;`)

With:

s = html.EscapeString(s)

Let me know if this approach would be an adequate solution? If it is, I could send a pull request that implements this.

In the mean time, I have worked around the issue by escaping text box strings post SVG render using a regex:

re := regexp.MustCompile(`(<tspan.*?>)(.*?)(<\/tspan>)`)
out := re.ReplaceAllFunc(renderedSvg, func(s []byte) []byte {
	return []byte(re.ReplaceAllString(string(s), `$1`) +
		html.EscapeString(re.ReplaceAllString(string(s), `$2`)) +
		re.ReplaceAllString(string(s), `$3`))
})

Thanks for all the hard work on this library!

[pdf] Wrong glyph displayed on iOS and Adobe Reader (fine for other font)

I generated the following pdf by running this program:
bug.pdf

package main

import (
	"image/color"
	"os"

	"github.com/tdewolff/canvas"
	"github.com/tdewolff/canvas/pdf"
)

func fontOTF() *canvas.FontFamily {
	fontFamily := canvas.NewFontFamily("SourceSerifPro")
	fontFamily.Use(canvas.CommonLigatures)
	err := fontFamily.LoadFontFile("SourceSerifPro-Regular.otf", canvas.FontRegular)
	if err != nil {
		panic(err)
	}
	return fontFamily
}

func fontDejaVuTTF() *canvas.FontFamily {
	fontFamily := canvas.NewFontFamily("times")
	fontFamily.Use(canvas.CommonLigatures)
	if err := fontFamily.LoadLocalFont("NimbusRoman-Regular", canvas.FontRegular); err != nil {
		panic(err)
	}
	return fontFamily
}

func main() {
	f, err := os.Create("bug.pdf")
	if err != nil {
		panic(nil)
	}
	defer f.Close()
	pdf := pdf.New(f, 100, 100)

	////////////////
	face := fontOTF().Face(16, color.Black, canvas.FontRegular, canvas.FontNormal)
	txt := canvas.NewTextLine(face, "SourceSerifPro-Regular.otf\nL (big l) is like I (big i) on iOS (/ is like [)", canvas.Left)
	pdf.RenderText(txt, canvas.Identity.Translate(0, 50))
	////////////////
	face = fontDejaVuTTF().Face(16, color.Black, canvas.FontRegular, canvas.FontNormal)
	txt = canvas.NewTextLine(face, "NimbusRoman-Regular\nL (big l) is like I (big i) on iOS (/ is like [)", canvas.Left)
	pdf.RenderText(txt, canvas.Identity.Translate(0, 20))

	err = pdf.Close()
	if err != nil {
		panic(nil)
	}
}

(you can get the OTF font at https://github.com/adobe-fonts/source-serif-pro)

It produces the following pdf:
bug.pdf

It displays fine on all PDF reader that I could test on linux (evince, firefox, chromium), but on the first line is wrong on Adobe Reader and iOS: the L is displayed like a I (the other letters look ok)
image

Do you have any idea what might be wrong ? (or at least in which direction should I search?)

PDF output no longer working

Hi,
during one of the changes after 27/12 PDF output got broken. I still get a file with content, but I can't display it in Chrome or OSX preview anymore. Chrome shows an empty canvas, OSX preview just eats all CPUs and crashes.
Converting the PDF to PS and displaying that output however works.

More frontends/backends

Rendering targets:

Implement backend interface:

Related projects:

[pdf] TTF font displayed as dots on iOS and Adobe Reader (OTF equivalent is fine)

I generated the following pdf by running this program:
bug.pdf

package main

import (
	"image/color"
	"os"

	"github.com/tdewolff/canvas"
	"github.com/tdewolff/canvas/pdf"
)

func fontTTF() *canvas.FontFamily {
	fontFamily := canvas.NewFontFamily("SourceSerifPro")
	fontFamily.Use(canvas.CommonLigatures)
	err := fontFamily.LoadFontFile("SourceSerifPro-Regular.ttf", canvas.FontRegular)
	if err != nil {
		panic(err)
	}
	return fontFamily
}

func fontOTF() *canvas.FontFamily {
	fontFamily := canvas.NewFontFamily("SourceSerifPro")
	fontFamily.Use(canvas.CommonLigatures)
	err := fontFamily.LoadFontFile("SourceSerifPro-Regular.otf", canvas.FontRegular)
	if err != nil {
		panic(err)
	}
	return fontFamily
}
func main() {
	f, err := os.Create("bug.pdf")
	if err != nil {
		panic(nil)
	}
	defer f.Close()
	pdf := pdf.New(f, 100, 100)

	////////////////
	face := fontOTF().Face(16, color.Black, canvas.FontRegular, canvas.FontNormal)
	txt := canvas.NewTextLine(face, "OTF font is fine", canvas.Left)
	pdf.RenderText(txt, canvas.Identity.Translate(0, 50))
	////////////////
	face = fontTTF().Face(16, color.Black, canvas.FontRegular, canvas.FontNormal)
	txt = canvas.NewTextLine(face, "Only dots are displayed for TTF", canvas.Left)
	pdf.RenderText(txt, canvas.Identity.Translate(0, 40))
	////////////////

	err = pdf.Close()
	if err != nil {
		panic(nil)
	}
}

(you can get the OTF and TTF font at https://github.com/adobe-fonts/source-serif-pro)

It produces the following pdf:
bug.pdf

It displays fine on all PDF reader that I could test on linux (evince, firefox, chromium), but the second line (the one using the TTF font) displays only dots on Adobe Reader and iOS:
image

Do you have any idea what might be wrong ? (or at least in which direction should I search?)

drawImage has margin

Sorry to disturb again.

Today I wrote some testing code, to test ctx.DrawImage.

Here is my code

func TestBasicDrawImage(t *testing.T) {
  c := Canvas{canvas.New(750, 750)}
  ctx := canvas.NewContext(c)

  // to draw a red background
  ctx.SetFillColor(color.RGBA{0xff, 0x00, 0x00, 0xff})
  ctx.DrawPath(0, 0, canvas.Rectangle(750, 750))

  // image1 start (-1,-1) trying to fix margin
  head, _ := os.Open("../static/head.jpeg")
  img, _ := jpeg.Decode(head)
  ctx.DrawImage(-1, -1, img, 1)

  // image2 at point(0,0)
  bg, _ := os.Open("../static/background.jpeg")
  bgImg, _ := jpeg.Decode(bg)
  ctx.DrawImage(0, 0, bgImg, 1)

  c.SavePNG("out.png", 1)
}

And result is:

image

You can see there are little margin at left-bottom corner of screen.
Maybe I can do something like c.DrawImage(x-5, y-5, 1.0) to fix this, but why ?

And here is my testing image, if you need.
thanks alot.

https://img.laiye.com/checkinAlbum_20200316083737_htqvLACrln.jpg
https://img.laiye.com/cLvgXicdq4RMvFgMeyiarFciatqCEPrkGudP9N6SceHhmA4Tl2unDvK4rNVCFroJZcfqMnUGvnBeDLaZpDYW0TRl9lxmD47gs70.jpg

Rasterization performance

Improve rasterization performance. How does FreeType perform? Why is the vector one slow?

Make sure the new rasterizer supports both fill types: EvenOdd and NonZero (vector does not support EvenOdd).

EDIT: see the following links for some ideas.

EDIT: actually, Nigel Tao has an implementation of font-rs in Go here: https://github.com/google/font-go. It says in https://github.com/golang/image/blob/master/vector/vector.go that font-go is proof of concept, but doesn't actually import vector...?

Support fill patterns and gradients

Besides colors, also support gradients (radial, linear) with multiple colors, and patterns made out of paths (such as stripes). Fun addition would be to add Penrose tiling.

For patterns we need path intersection functionality, to cut the repeating pattern with the path fill boundary.

unrecognized font file format

Why is this failing with unrecognized font file format?

font := canvas.NewFontFamily("times")
font.Use(canvas.CommonLigatures)
if err := font.LoadLocalFont("Times", canvas.FontRegular); err != nil {
	panic(err)
}
face := font.Face(6.0, color.Black, canvas.FontRegular, canvas.FontNormal)

Is this a "fount not found"? How do find which is the correct name? The system lists it as "Times".
This is on macOS.

Export properties to move pdf & svg renderers to sub packages

Following #24 & #25

The pdf and svg subpackages are not completely split from the canvas package because it misses some exported fields .

For instance on Text and its lines:

  • text.lines
  • line.spans (ff, dx...)
  • wordBoundary
  • eofBoundary

I can start a PR to have a precise overview of what is missing and slowly start refactoring what should be done (following your advice).
Or you can take a look yourself and refactor it all at once.

Anyway, please let me know what is your preferred option

Generate linearized PDFs

See Annex F in the PDF 1.7 reference manual. Shouldn't be hard but speeds up display for most devices.

reducing shapes

I am creating a PDF but the amount of shapes makes it really heavy to render.

So my idea was to render it into an image (WriteImage) first and then draw that image into the context for the PDF. Unfortunately it seems like DrawImage does not respect the transparency of the PNG.

Is there something I am missing? Or a better way than having all shapes in the PDF as is?

Not drawing some text

I am flabbergasted. I stripped down a problem to the following.

This works:

  ctx.DrawText(lx, ly, canvas.NewTextLine(face, fmt.Sprintf(
    "XX",
  ), 0))

This doesn't draw anything

  ctx.DrawText(lx, ly, canvas.NewTextLine(face, fmt.Sprintf(
    "XF",
  ), 0))

Any idea?

What is the replacement for WriteImage ?

Hi @tdewolff, thanks for this package.

I've been using this package for several months and it works perfectly. However, today I have to upgrade an old code, so while I'm on it I also upgrade all of its dependencies.

Unfortunately, when I build the code it failed because WriteImage method is not exist anymore. Are there replacement for that method ? I want to render a canvas into image.Image so I can modify it further.

Thank you.

panics when parsing SVG

I'm trying to parse an svg for rasterizing:

    menuSvg := `<svg id="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<defs><style>.cls-1{fill:none;}</style></defs>
<title>menu</title>
<rect x="4" y="6" width="24" height="2"/>
<rect x="4" y="24" width="24" height="2"/>
<rect x="4" y="12" width="24" height="2"/>
<rect x="4" y="18" width="24" height="2"/>
<rect id="_Transparent_Rectangle_" data-name="&lt;Transparent Rectangle&gt;" class="cls-1" width="32" height="32"/>
</svg>\`

    path := canvas.MustParseSVG(menuSvg)

but the code panics with an error:

panic: bad path: path should start with command

goroutine 1 [running]:
github.com/tdewolff/canvas.MustParseSVG(...)
        /home/fourthsun/go/src/github.com/tdewolff/canvas/path.go:1378

it's nonsense, this path can't be bad, cause I've downloaded it as an icon.
Please fix this bug. Thanks

multi-page pdfs

Is there a way a generating multi-page pdfs?

Right now I am generating the pages individually and then combine them later on.

Improving text rendering

Instead of reinventing the wheel, we should be using existing solutions. Especially important to me is using HarfBuzz for text shaping (rendering glyphs correctly in all languages, such as direction, accents, kerning, etc.). See https://github.com/grisha/hbshape for an example of a port.

See https://harfbuzz.github.io/ch01s03.html for what HarfBuzz does, and https://harfbuzz.github.io/what-harfbuzz-doesnt-do.html for what it doesn't do. The latter is what we need to implement here:

  • Line-break, word break, justification: Knuths algorithm. Note that "boxes" can also be a path (not just text) to support inline images, and that the text box boundaries may not be rectangular but a path (hard?)
  • Breaking text in pieces of different font faces, we already do this
  • Solving bidirectionality, no idea, probably use https://github.com/fribidi/fribidi
  • Rendering, we already do this but the rasterizer is slow! Why not use FreeType?

For an example see https://github.com/anoek/ex-sdl-cairo-freetype-harfbuzz/. (NB: they don't use FreeType for rasterization?)

Additionally, but with less priority, I'd like to support the TCC file format (how does that pan out with fc-match?). And finally I'd like to support OpenGL rendering using Blinn and Loop algorithm or something similar (see https://lambdacube3d.wordpress.com/2014/11/12/playing-around-with-font-rendering/ as well). This needs proper tesselation of paths which is not that trivial. Low priority.

Improved text settings

  • Leave out ligatures as they complicate it a lot
  • Separate out ligatures/smart text transformations
  • Allow paths/images to be part of the text line (i.e. incompressible/unexpandable objects)
  • Use path to define bounding area

Make path transformation matrix apply to stroke too

Which file formats support transformations of path strokes? That is, applying a view transformation to Context such as ctx.SetView(canvas.Identity.Scale(2.0, 1.0)), does the stroke of a path get transformed as well? Works for PDF, PNG and SVG so far.

Move origin to left-top and draw from top left to bottom right

From what I understand, the coordinate system is designed in such a way that the origin is in the lower left corner of canvas and that you draw from left to right and bottom to top, correct?

Is there a way to change it so that the 0,0 point is in the upper left corner (like most design programs do) and draw from left to right and top to bottom?

Is it currently possible to generate multi-page pdf?

Your library looks great, and I am thinking about using it to generate multipage PDFs.

As far as I see this is currently not possible using the public API.

The pdfWriter (not exported) struct seems to be ready for it (with its NewPage method).

I can't reuse the same io.Writer for NewPDF (only exported way to trigger the NewPage method), because it calls newPDFWriter which always writes w.write("%%PDF-1.7\n") at the beginning.


I have no idea how multipages work in pdfs, but I think that this feature could be implemented the following way:

  • add an exported NewPage(width, height float64) method to PDF, which would forward the call to w.pdf.NewPage and replace w with the newly created page

What do you think?
I could try to craft a MR if you think that this sounds like a good idea.

Reduce the Renderer interface

Currently the Renderer interface has 4 methods (Size, RenderPath, RenderText and RenderImage).

Many renderers don't actually implement the RenderText, but fallback to rendering the text as path and calling RenderPath.

Instead of duplicating this "trick" everywhere, one could reduce the Renderer interface and introduce a TextRenderer interface (naming inspired from https://go.googlesource.com/proposal/+/master/design/draft-iofs.md#possible-future-or-third_party-extensions)

// Renderer is an interface that renderers implement. It defines the size of the target (in mm) and functions to render paths, text objects and raster images.
// If the Renderer does not implement TextRenderer, the text will be converted to path.
type Renderer interface {
	Size() (float64, float64)
	RenderPath(path *Path, style Style, m Matrix)
	RenderImage(img image.Image, m Matrix)
}

// TextRenderer should be implemented to prevent text from being converted to path before rendering
type TextRenderer interface {
	Renderer
	RenderText(text *Text, m Matrix)
}

And then context.DrawText would use this method if available, or fallback to the RenderPath method:

// DrawText draws text at position (x,y) using the current draw state. In particular, it only uses the current affine transformation matrix.
func (c *Context) DrawText(x, y float64, texts ...*Text) {
	m := c.view.Translate(x, y)
	for _, text := range texts {
		if text.Empty() {
			continue
		}
		renderText(c.Renderer, text, m)
	}
}

func renderText(r Renderer, text *Text, m Matrix) {
	t, ok := r.(TextRenderer)
	if ok {
		t.RenderText(text, m)
	} else {
		// transform text to path
		paths, colors := text.ToPaths()
		for i, path := range paths {
			style := DefaultStyle
			style.FillColor = colors[i]
			r.RenderPath(path, style, m)
		}
	}
}

Do you think this is a good idea? Would you be willing to accept a PR with those changes?

Why splitting bezier for length calculation?

I have been reading your blog and part of you code to learn more about arc length computation for cubic bezier curves and found that in cubicBezierLength() you are splitting the curve before applying the Gauss quadrature to calculate the length of each piece of curve. As I understand it this should not be necessary, because you can choose t0 and t1 (or a and b in your case) to calculate the length of each piece without splitting.

Is this a possible optimization for your code?

PDF --> SVG

i need to convert PDF to SVG & SVG to PDF.

Hoping to do it with just golang... If you happen to knwo of any libs for this :)

Thread safety font.go

the font.go class is using a shared buffer sfntBuffer , resulting in errors when drawing in parallel:

2020/01/22 17:52:44 http: panic serving [::1]:54444: runtime error: index out of range [6] with length 0
goroutine 213 [running]:
net/http.(*conn).serve.func1(0xc0003c01e0)
	/home/tobias/sdk/go1.14beta1/src/net/http/server.go:1772 +0x139
panic(0x97f4e0, 0xc00044a100)
	/home/tobias/sdk/go1.14beta1/src/runtime/panic.go:973 +0x396
golang.org/x/image/font/sfnt.(*Font).LoadGlyph(0xc00014c420, 0x1048420, 0x3160000002a, 0x0, 0x0, 0x0, 0x203000, 0x203000, 0x203000)
	/home/tobias/go/pkg/mod/golang.org/x/[email protected]/font/sfnt/sfnt.go:1395 +0x486
github.com/tdewolff/canvas.FontFace.ToPath(0xc0001202e0, 0xc000238000, 0x4028b1c71c71c71d, 0x0, 0x2, 0xffffffff, 0x0, 0x0, 0x0, 0x3ff0000000000000, ...)
	/home/tobias/go/pkg/mod/github.com/tdewolff/[email protected]/fontface.go:292 +0x418
github.com/tdewolff/canvas.textSpan.ToPath(0xc0001202e0, 0xc000238000, 0x4028b1c71c71c71d, 0x0, 0x2, 0xffffffff, 0x0, 0x0, 0x0, 0x3ff0000000000000, ...)
	/home/tobias/go/pkg/mod/github.com/tdewolff/[email protected]/text.go:669 +0x154
github.com/tdewolff/canvas.(*Text).ToPaths(0xc0003a5920, 0xc0001fe500, 0xffffffff, 0x3ff0000000000000, 0xa767c0, 0x1072300, 0xa767e0)
	/home/tobias/go/pkg/mod/github.com/tdewolff/[email protected]/text.go:523 +0x5d8
github.com/tdewolff/canvas.(*Rasterizer).RenderText(0xc000358000, 0xc0003a5920, 0x3ff0000000000000, 0x0, 0x405c5ae33c678cf0, 0x0, 0x3ff0000000000000, 0x40566b8000000000)
	/home/tobias/go/pkg/mod/github.com/tdewolff/[email protected]/rasterizer.go:86 +0x43
github.com/tdewolff/canvas.(*Canvas).Render(0xc00058e720, 0xa80300, 0xc000358000)
	/home/tobias/go/pkg/mod/github.com/tdewolff/[email protected]/canvas.go:447 +0x2c3
github.com/tdewolff/canvas.(*Canvas).WriteImage(0xc00058e720, 0x4000000000000000, 0x4c7557)
	/home/tobias/go/pkg/mod/github.com/tdewolff/[email protected]/canvas.go:513 +0x2c7
main.main.func1(0xa7efc0, 0xc0003da460, 0xc0000fe100)
	/home/tobias/Projects/flussibanner/cmd/flussibanner-server/main.go:42 +0x133
net/http.HandlerFunc.ServeHTTP(0xc00012e9c0, 0xa7efc0, 0xc0003da460, 0xc0000fe100)
	/home/tobias/sdk/go1.14beta1/src/net/http/server.go:2012 +0x44
net/http.(*ServeMux).ServeHTTP(0x1046fc0, 0xa7efc0, 0xc0003da460, 0xc0000fe100)
	/home/tobias/sdk/go1.14beta1/src/net/http/server.go:2387 +0x1a5
net/http.serverHandler.ServeHTTP(0xc0001480e0, 0xa7efc0, 0xc0003da460, 0xc0000fe100)
	/home/tobias/sdk/go1.14beta1/src/net/http/server.go:2807 +0xa3
net/http.(*conn).serve(0xc0003c01e0, 0xa80040, 0xc000080000)
	/home/tobias/sdk/go1.14beta1/src/net/http/server.go:1895 +0x86c
created by net/http.(*Server).Serve
	/home/tobias/sdk/go1.14beta1/src/net/http/server.go:2933 +0x35c

how to use pixel sizes

I noticed that if I create an SVG with a width of 2700, then I'll get a much wider image than 2700pixels. I assume it's because canvas uses DPMM instead of pixels. I have to wonder if it's possible to change or should I do the math on my side to compensate for it.

Thanks in advance!

Add API to set ID on SVG elements

At first glance this package does exactly what I’m looking for! One thing for me that it doesn’t do is allowing to assign an ID to a SVG element so it can be referenced from JavaScript for things like animation or highlighting a particular part of the drawing.

It would be great if something could be added that helps the use cases I mentioned.

[pdf] Add RenderJpeg method

Currently pdf.RenderImage decodes and re-encodes the image.

I would prefer to have a way to embed a compressed jpeg without those 2 steps (for performance and pdf-size reason).

Would you accept such a PR ?
Since the renderers are now completely decoupled from the main package, I could also maintain my own package without issue, if you prefer.

I am not sure how this could be integrated for other renders, but this question can be solved later.

Improve inner-bend optimization for stroking

Path stroking adds overlapping paths in the inner-bend of corners. Optimize these so that there is no overlap. What if large parts of the path are overlapping due to stroking?

Question about text series api (TextLine、NewTextBox..)

hi, I want to draw a text content at the top-left of the screen, and without spacing. like this.

image

so I do a simply transform

// c.H is canvas height
c := Canvas{canvas.New(1000, 1000)}
canvas.NewContext(c).SetView(canvas.Identity.Translate(0, 1000))

and call c.DrawText, set y * -1

c.DrawText(x, y*-1, text)

but, I have trouble in the "TextBox".

I tried to do some tests, you can see the text.Bounds() has little offsets. and here is my code

for i := 5; i > 0; i-- {
    face := fontFamily[fontKey].Face(t.Size+float64(i*30)*ptPerMm, color, t.FontStyle, canvas.FontNormal)
    text := canvas.NewTextBox(face, content, 0, 0, canvas.Left, canvas.Top, indent, lineStretch)

    rect := text.Bounds()
    if i%2 == 0 {
        c.SetFillColor(canvas.Red)
    } else {
        c.SetFillColor(canvas.Blue)
    }
    c.DrawPath(t.X, t.Y, rect.ToPath())

    c.SetFillColor(color)
    c.DrawText(t.X, t.Y, text)
}

image

sorry for bad english

Proposal : Draw behind, z index ?

I'm trying to draw a path behind. But it looks like the RenderPath can add only on top of the layers stack.

Is it possible to append a new method RenderPathBehind ? Or even better add z-index parameter to the layers and when new path is added it is inserted at the right 'z'-position.

PDF text copying

Currently, copying text from generated PDFs are incorrect when pasted.

Uneven number of pages, corrupts pdf

First of all, I like to compliment you on this awesome package!

However, I hit a snag during Multiple PDF page generation (more than 2 that is) the following code should illustrate the issue.

        buf := &bytes.Buffer{}
	pdf := canvas.NewPDF(buf, 210, 297)

	pdf.NewPage(210, 297)

	pdf.NewPage(210, 297) // if this is commented out, pdf = ok

	pdf.Close()

	ioutil.WriteFile("out.pdf", buf.Bytes(), 0644) // more then 2 pages corrupts pdf

Am I doing something wrong?

Error with font spacing

When converting a font to path the spaces between the letters are not respected.

I think that the kern displacement in func (ff FontFace) ToPath(s string) (*Path, float64) should be done before to add the glyph to the path.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.