I am adding a layer over my video stream with custom drawn graphics, but when I save the drawn layer for my current frame I have a pretty big file (~10MB). When analyzing the data, it's mostly 0's (representing the actual pixels of the video and not the drawn layer). I understand that PPM and BMP files will inherently be pretty sizable files, but is there a way to handle the repetitiveness of 0's? Is there a different file format I should be checking out?
-
1Use PNG for best compression of line drawings and similar. Use JPEG for photographic images (or better JPEG2000, but that's not as wide-spread). – Cris Luengo Nov 24 '20 at 05:32
-
As Cris says, but GIF also compresses computer graphics and *"blocky"*, repetitive stuff with less than 250 colours well. – Mark Setchell Nov 24 '20 at 07:44
-
1Although a *"blast from the past"*, `PCX` also does RLE (run length encoding) and works fine with Photoshop, GIMP and ImageMagick https://en.wikipedia.org/wiki/PCX – Mark Setchell Nov 24 '20 at 08:41
-
@MarkSetchell also decoding PCX is easy just few lines of code [in C++](https://stackoverflow.com/a/56097346/2521214) or [in ASM](https://stackoverflow.com/a/45780565/2521214) encoding is also easy and fast ... – Spektre Nov 24 '20 at 10:28
-
1@MarkSetchell I got also RT GIF encoder/decoder but that is much much bigger and too slwo for big resolutions ... I got also DCT based image compression working but that one is too slow for RT encoding... however may be [my optimized NTT](https://stackoverflow.com/q/18577076/2521214) could make a difference – Spektre Nov 24 '20 at 14:05
1 Answers
Here's a "blocky", computer graphics type of overlay with 1182x862 pixels.
Here are the sizes it come out as in the other formats you might like to try:
-rw-r--r--@ 1 mark staff 3056668 24 Nov 08:49 overlay.ppm
-rw-r--r--@ 1 mark staff 23699 24 Nov 08:49 overlay.gif
-rw-r--r-- 1 mark staff 134723 24 Nov 08:49 overlay.pcx
-rw-r--r--@ 1 mark staff 22585 24 Nov 08:48 overlay.png
Be aware that they all have some tradeoffs. Whilst PNG is smallest, it is likely to take longer to write. GIF acquits itself pretty well, but will do poorly if you have too many colours. PCX is a bit archaic, but usable. PPM is large and directly proportional in size to your overlay size.
Note that if your overlays really are very blocky, you could consider reducing them to 1/4 their height and width and make them 16x smaller in volume if you can handle a couple of pixels inaccuracy when scaling back up.
You could also consider generating the overlay in a vector format which should be many, many times smaller in size.
Lifted straight form the documentation from DrawSvg, here is an SVG vector example:
#!/usr/bin/env python3
import drawSvg as draw
d = draw.Drawing(200, 100, origin='center', displayInline=False)
# Draw an irregular polygon
d.append(draw.Lines(-80, -45,
70, -49,
95, 49,
-90, 40,
close=False,
fill='#eeee00',
stroke='black'))
# Draw a rectangle
r = draw.Rectangle(0,0,40,50, fill='#1248ff')
r.appendTitle("Our first rectangle") # Add a tooltip
d.append(r)
# Draw a circle
d.append(draw.Circle(-40, -10, 30,
fill='red', stroke_width=2, stroke='black'))
# Draw an arbitrary path (a triangle in this case)
p = draw.Path(stroke_width=2, stroke='green',
fill='black', fill_opacity=0.5)
p.M(-30,5) # Start path at point (-30, 5)
p.l(60,30) # Draw line to (60, 30)
p.h(-70) # Draw horizontal line to x=-70
p.Z() # Draw line to start
d.append(p)
# Draw multiple circular arcs
d.append(draw.ArcLine(60,-20,20,60,270,
stroke='red', stroke_width=5, fill='red', fill_opacity=0.2))
d.append(draw.Arc(60,-20,20,60,270,cw=False,
stroke='green', stroke_width=3, fill='none'))
d.append(draw.Arc(60,-20,20,270,60,cw=True,
stroke='blue', stroke_width=1, fill='black', fill_opacity=0.3))
# Draw arrows
arrow = draw.Marker(-0.1, -0.5, 0.9, 0.5, scale=4, orient='auto')
arrow.append(draw.Lines(-0.1, -0.5, -0.1, 0.5, 0.9, 0, fill='red', close=True))
p = draw.Path(stroke='red', stroke_width=2, fill='none',
marker_end=arrow) # Add an arrow to the end of a path
p.M(20, -40).L(20, -27).L(0, -20) # Chain multiple path operations
d.append(p)
d.append(draw.Line(30, -20, 0, -10,
stroke='red', stroke_width=2, fill='none',
marker_end=arrow)) # Add an arrow to the end of a line
d.setPixelScale(2) # Set number of pixels per geometry unit
#d.setRenderSize(400,200) # Alternative to setPixelScale
d.saveSvg('example.svg')
d.savePng('example.png')
That comes up as 14,202 bytes of PNG or 1,348 bytes of SVG - so the vector graphics are a massive 10x smaller!
-rw-r--r-- 1 mark staff 1348 24 Nov 10:01 example.svg
-rw-r--r-- 1 mark staff 14202 24 Nov 10:01 example.png
Here is the SVG:
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="400" height="200" viewBox="-100.0 -50.0 200 100">
<defs>
<marker markerWidth="4.0" markerHeight="4.0" viewBox="-0.1 -0.5 1.0 1.0" orient="auto" id="d0">
<path d="M-0.1,0.5 L-0.1,-0.5 L0.9,0 Z" fill="red" />
</marker>
</defs>
<path d="M-80,45 L70,49 L95,-49 L-90,-40" fill="#eeee00" stroke="black" />
<rect x="0" y="-50" width="40" height="50" fill="#1248ff">
<title>Our first rectangle</title>
</rect>
<circle cx="-40" cy="10" r="30" fill="red" stroke-width="2" stroke="black" />
<path d="M-30,-5 l60,-30 h-70 Z" stroke-width="2" stroke="green" fill="black" fill-opacity="0.5" />
<circle cx="60" cy="20" r="20" stroke-dasharray="73.30382858376184 52.35987755982988" stroke-dashoffset="-31.41592653589793" stroke="red" stroke-width="5" fill="red" fill-opacity="0.2" />
<path d="M70.0,2.679491924311229 A20,20,0,1,0,59.99999999999999,40.0" stroke="green" stroke-width="3" fill="none" />
<path d="M59.99999999999999,40.0 A20,20,0,1,1,70.0,2.679491924311229" stroke="blue" stroke-width="1" fill="black" fill-opacity="0.3" />
<path d="M20,40 L20,27 L0,20" stroke="red" stroke-width="2" fill="none" marker-end="url(#d0)" />
<path d="M30,20 L0,10" stroke="red" stroke-width="2" fill="none" marker-end="url(#d0)" />
</svg>
If you want to experiment yourself with your actual data, try ImageMagick in the Terminal. You can convert from PPM to PNG like this:
magick input.ppm output.png
or from PPM to quarter-height and quarter-width GIF like this:
magick input.ppm -scale 25% result.gif
Note that ImageMagick will not convert to SVG - as it is a raster graphics program, and rasterises everything before it even starts. It will convert from SVG to raster though.

- 191,897
- 31
- 273
- 432