jankovicsandras / imagetracerjs

Simple raster image tracer and vectorizer written in JavaScript.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Consultation on conversion of bitmap images to lines SVG

asegurpe opened this issue · comments

Hi András,

I'm in a project that needs to transform bitmap images to vectorial, but this vectorial has to be built with lines or paths, that is, without fills or other forms, just lines or paths.

I wanted to ask you if your development has this capability. If not, I would ask you for advice on how to face this challenge.

Thank you very much.
Alejandro

Hi Alejandro,

If you need only outline rendering, then you can change line 986 to something like this:

return 'fill="transparent" stroke="rgb('+c.r+','+c.g+','+c.b+')" stroke-width="'+options.strokewidth+'" opacity="'+c.a/255.0+'" ';

then use

var options = { "qtres":0.01, "scale":1, "strokewidth":1 };

for tracing. This results sharp linear outlines. If you need coordinates, then you can process tracedata.

Does this answer your question?

Hi András,

Firstly thanks for your quick answer, but I think that I didn't explain correctly. For this reason, I will try to explain this with a visual example that I've attached.

example

You must think that the left image (black square) is a BMP, and other images are an SVG equivalent made with lines. It is important to be able to define the line thickness with a parameter.

Again, thank you so much for your time.
Alejandro

Hi Alejandro,

As I understand, you need filled shapes, just not the standard SVG fill, but your custom linear strokes. ( These could be used to recreate the image with a plotter or similar device. )

ImageTracer can't do this out of the box, but here's some ideas, which might be useful.

If 1px horizontal or vertical lines are acceptable (similar to the 3. example above), then you can use the original raster image, apply color quantization, and use horizontal or vertical raster scanning. This is very easy to implement, but probably not very useful.

Another method is to draw the outline (you can get this from tracedata), then "shrink" the outline and draw it again (similar to the 2. example above). You can achive shrinking by moving all outline points towards the center. This is relatively easy to do with convex polygons: the center can be the average of all outline points. But it can be more complex with concave shapes, then you need a Straight skeleton algorithm.

I can also think of an inefficient, hacky solution, which might be relatively easy to implement:

  • look at imagetracer_test_automation.html
  • it has a feature which renders the traced SVG back to raster image
  • it has a feature which subtracts this from the original raster image
  • you can find the outline only rendering above (with custom stroke-width)

Maybe it's possible to combine these in a loop:

loop{
1. trace image to tracedata -> get the outline path
2. render back to raster image
3. subtract this from the image 
}

So kind of "peeling" the shapes. It would take a lot of time and I haven't tested this solution.

Are you thinking about something similar?

I hope these helped, you can reopen the Issue if you need more advice.

This is pretty much a similar problem to mine in terms of the desired result (line fills) but I'd like to use Rough.js library to do the stylisation.

Is there a way to tap into each generated <path> and replace it with the modified version by the Rough.js library, before the SVG is appended?

roughSvg.path('M80 80 A 45 45, 0, 0, 0, 125 125 L 125 80 Z', { fill: 'green' });

Thanks!

Hi,

Yes, it's possible, there are multiple solutions.

The simplest is probably modifying the SVG string building process. Please note, that I haven't tested this, but hope it will work:

  • Do not use options.lcpr or options.qcpr (control point rendering for testing, not to be used in production anyway).

  • Comment out or remove Lines 851-856 in svgpathstring() .

  • Comment out or remove Lines 922-924 in svgpathstring() .

  • Change Line 977 in getsvgstring() :

from

svgstr += _this.svgpathstring( tracedata, lcnt, pcnt, options );

to

svgstr += roughSvg.path( _this.svgpathstring( tracedata, lcnt, pcnt, options ) , { fill: 'rgb(' + tracedata.palette[lcnt].r + ',' + tracedata.palette[lcnt].g + ',' + tracedata.palette[lcnt].b + ')' });

I assume here that Rough.js is returning a string to concatenate in the SVGstring. I don't know how Rough.js works, so you might need to experiment a little bit.

Alternatively, you can use imageToTracedata() or imagedataToTracedata() to get a tracedata object, and process the line segments afterwards (i.e. make your own getsvgstring() -like function).