Skip to content

SVG file is enormous #177

@SteepAtticStairs

Description

@SteepAtticStairs

I have been using this library with go-nexrad, and I am able to generate PNG and SVG files. However, the SVG files that are generated are enormous, with a less than 10MB PNG file becoming a 28MB SVG file with the same options. Here is the code:

func render(out string, radials []*archive2.Message31, label string) {

	width := float64(imageSize)
	height := float64(imageSize)

	SVGcanvas := draw2dsvg.NewSvg()
	SVGcanvas.Width = strconv.Itoa(int(width)) + "px"
	SVGcanvas.Height = strconv.Itoa(int(width)) + "px"
	//fmt.Println(canvas.Width)
	//fmt.Println(canvas.Height)
	//draw.Draw(canvas, canvas.Bounds(), image.Black, image.ZP, draw.Src)

	SVGgc := draw2dsvg.NewGraphicContext(SVGcanvas)

	xc := width / 2
	yc := height / 2
	pxPerKm := width / 2 / 460
	firstGatePx := float64(radials[0].ReflectivityData.DataMomentRange) / 1000 * pxPerKm
	gateIntervalKm := float64(radials[0].ReflectivityData.DataMomentRangeSampleInterval) / 1000
	gateWidthPx := gateIntervalKm * pxPerKm

	t := time.Now()
	log.Println("rendering radials")
	// valueDist := map[float32]int{}

	for _, radial := range radials {
		// round to the nearest rounded azimuth for the given resolution.
		// ex: for radial 20.5432, round to 20.5
		azimuthAngle := float64(radial.Header.AzimuthAngle) - 90
		if azimuthAngle < 0 {
			azimuthAngle = 360.0 + azimuthAngle
		}
		azimuthSpacing := radial.Header.AzimuthResolutionSpacing()
		azimuth := math.Floor(azimuthAngle)
		if math.Floor(azimuthAngle+azimuthSpacing) > azimuth {
			azimuth += azimuthSpacing
		}
		startAngle := azimuth * (math.Pi / 180.0)      /* angles are specified */
		endAngle := azimuthSpacing * (math.Pi / 180.0) /* clockwise in radians           */

		// start drawing gates from the start of the first gate
		distanceX, distanceY := firstGatePx, firstGatePx
		SVGgc.SetLineWidth(gateWidthPx + 1)
		SVGgc.SetLineCap(draw2d.ButtCap)

		var gates []float32
		switch product {
		case "vel":
			gates = radial.VelocityData.ScaledData()
		case "sw":
			gates = radial.SwData.ScaledData()
		case "rho":
			gates = radial.RhoData.ScaledData()
		default:
			gates = radial.ReflectivityData.ScaledData()
		}

		numGates := len(gates)
		for i, v := range gates {
			if v != archive2.MomentDataBelowThreshold {

				//fmt.Println(gateWidthPx)
				if i == 0 {
					SVGgc.SetLineWidth(0)
				} else if i > 0 {
					SVGgc.SetLineWidth(gateWidthPx + 1)
				}

				// valueDist[v] += 1

				SVGgc.MoveTo(xc+math.Cos(startAngle)*distanceX, yc+math.Sin(startAngle)*distanceY)

				// make the gates connect visually by extending arcs so there is no space between adjacent gates.
				if i == 0 {
					SVGgc.ArcTo(xc, yc, distanceX, distanceY, startAngle-.001, endAngle+.001)
				} else if i == numGates-1 {
					SVGgc.ArcTo(xc, yc, distanceX, distanceY, startAngle, endAngle)
				} else {
					SVGgc.ArcTo(xc, yc, distanceX, distanceY, startAngle, endAngle+.001)
				}

				SVGgc.SetStrokeColor(colorSchemes[product][colorScheme](v))
				SVGgc.Stroke()
			}

			distanceX += gateWidthPx
			distanceY += gateWidthPx
			azimuth += radial.Header.AzimuthResolutionSpacing()
		}
	}

	// Save to file
	draw2dsvg.SaveToSvgFile(out, SVGcanvas)
	fmt.Println("Finished in", time.Since(t))
}

The full file can be found in my fork of the project here.

The reason I think the SVG is so large is because it is generating the file very inefficiently, possibly by trying to render every pixel instead of just a start and end point. I have tried setting the DPI with SVGgc.setDPI(), but that hasn't worked.

If you have any idea about why the file is so large, or any idea of how to fix it, I would greatly appreciate your input. Hopefully you won't have to go through the entire go-nexrad project to understand this, I have included the code block that I am almost certain is causing the issue, and is the part that uses your library.

If you would like a screen recording of me generating the file and showing the file size with both PNG and SVG, please let me know, if you have difficulty building the project and replicating the issue yourself, if that is needed.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions