png bottom image flipped
hello,
using the test files attached I got a perfect image from the up, but a wrong image in the bottom:

As you can see the silkscreen and the drill files should be inversed. Uploading the same files on OSHPark brings to correct images
This is my test file:
import os
from gerber import load_layer
from gerber.render import RenderSettings, theme
from gerber.render.cairo_backend import GerberCairoContext
GERBER_FOLDER = "C:\\Users\\vincenzo\\Desktop\\Gerber-test\\"
output = "C:\\Users\\vincenzo\\Desktop\\"
# The default style can be overridden by passing a RenderSettings instance to
# render_layer().
# First, create a settings object:
our_settings = RenderSettings(color=theme.COLORS['white'], alpha=0.85)
# Open the gerber files
drill = load_layer(os.path.join(GERBER_FOLDER, 'ATMEGA328.drl'))
copper = load_layer(os.path.join(GERBER_FOLDER, 'ATMEGA328-F_Cu.gbr'))
mask = load_layer(os.path.join(GERBER_FOLDER, 'ATMEGA328-F_Mask.gbr'))
silk = load_layer(os.path.join(GERBER_FOLDER, 'ATMEGA328-F_SilkS.gbr'))
# Create a new drawing context
ctx = GerberCairoContext()
# Draw the copper layer. render_layer() uses the default color scheme for the
# layer, based on the layer type. Copper layers are rendered as
ctx.render_layer(copper)
ctx.render_layer(mask)
ctx.render_layer(silk, settings=our_settings)
ctx.render_layer(drill)
# Write output to png file
ctx.dump(os.path.join(os.path.dirname(__file__), 'cairo_example.png'))
# Clear the drawing
ctx.clear()
# Load the bottom layers
copper = load_layer(os.path.join(GERBER_FOLDER, 'ATMEGA328-B_Cu.gbr'))
mask = load_layer(os.path.join(GERBER_FOLDER, 'ATMEGA328-B_Mask.gbr'))
silk = load_layer(os.path.join(GERBER_FOLDER, 'ATMEGA328-B_SilkS.gbr'))
# Render bottom layers
ctx.render_layer(copper)
ctx.render_layer(mask)
ctx.render_layer(silk, settings=our_settings)
ctx.render_layer(drill)
# Write png file
ctx.dump(os.path.join(os.path.dirname(__file__), 'cairo_bottom.png'))
Hello, It seems that your filenames are not matching the pattern detected by the library, as such, pcb-tools is unaware that your bottom files are to be flipped. I do not know this file pattern so I cannot tell if pcb-tools is right or wrong. I'll let the maintainers be the judge of that.
Meanwhile, a quick fix to your problem would be to change the names of the files to the following: ATMEGA328-B.Cu.gbr ATMEGA328-B.Mask.gbr ATMEGA328-B.SilkS.gbr
Alternatively, you can bypass load_layer and directly use:
PCBLayer(fileame, layer_class, common.read(filename))
Where layer_class is any of the following: top, bottom, internal, topsilk, bottomsilk, topmask, bottommask, toppaste, bottompaste
Tomorrow I will try the second approach
My files are generated by the latest stable release of kicad 5, I guess them are right, but my knowledge about gerbers file is limited
ok that's a little better: only the drill file is inverted

Do you know how to reduce the size of the images? both are about 1.6Mb I don't need such a resolution
EDIT: found ctx = GerberCairoContext(scale=100)
import os
from gerber.layers import *
from gerber.render.cairo_backend import GerberCairoContext
from PIL import Image
def render_pcb(input_path, output_file):
img_front_path = os.path.join(input_path, 'front.png')
img_bottom_path = os.path.join(input_path, 'bottom.png')
# Open the gerber files
for r, d, f in os.walk(input_path):
for file in f:
if '.drl' in file:
real_path = os.path.join(r, file)
drill = DrillLayer(real_path, common.read(real_path))
# Front
elif '-F_Cu.gbr' in file:
real_path = os.path.join(r, file)
copper_front = PCBLayer(real_path, 'top', common.read(real_path))
elif '-F_Mask.gbr' in file:
real_path = os.path.join(r, file)
mask_front = PCBLayer(real_path, 'topmask', common.read(real_path))
pass
elif '-F_SilkS.gbr' in file:
real_path = os.path.join(r, file)
silk_front = PCBLayer(real_path, 'topsilk', common.read(real_path))
pass
# Bottom
elif '-B_Cu.gbr' in file:
real_path = os.path.join(r, file)
copper_bottom = PCBLayer(real_path, 'bottom', common.read(real_path))
elif '-B_Mask.gbr' in file:
real_path = os.path.join(r, file)
mask_bottom = PCBLayer(real_path, 'bottommask', common.read(real_path))
elif '-B_SilkS.gbr' in file:
real_path = os.path.join(r, file)
silk_bottom = PCBLayer(real_path, 'bottomsilk', common.read(real_path))
else:
pass
# Create a new drawing context
ctx = GerberCairoContext()
ctx.render_layer(copper_front)
ctx.render_layer(mask_front)
ctx.render_layer(silk_front)
ctx.render_layer(drill)
# Write png file
ctx.dump(img_front_path)
# Clear the drawing
ctx.clear()
# Render bottom layers
ctx.render_layer(copper_bottom)
ctx.render_layer(mask_bottom)
ctx.render_layer(silk_bottom)
ctx.render_layer(drill) #not working, it is inverted
# Write png file
ctx.dump(img_bottom_path)
ctx.clear()
'''
# Concatenate
front = Image.open(img_front_path)
bottom = Image.open(img_bottom_path)
render = Image.new('RGB', (front.width, front.height * 2))
render.paste(front, (0, 0))
render.paste(bottom, (0, front.height))
render.save(output_file)
'''
project_path = os.path.dirname(os.path.realpath(__file__))
gerber_path = os.path.join(project_path, 'Gerber-test')
project_name = "test-pcb"
output_path = os.path.join(project_path, project_name + ".png")
print('Project:{}\nGerber:\t{}\nPNG:\t{}'.format(project_path, gerber_path, output_path))
render_pcb(gerber_path, output_path)
Is it correct that I am passing the filename twice? copper_front = PCBLayer(real_path, 'top', common.read(real_path))
You can also mirror the layer using RenderSettings:
from gerber.render import RenderSettings
ctx.render_layer(drill, settings=RenderSettings(mirror=True))
If you want more control about the appearance of your pcb, RenderSettings is the way to go.
I recommend you to use file.endswith(pattern) to check for patterns instead of for ".." in file.
It is simply perfect, thank you very much @MarinMikael I really appreciated your help 😀
I will leave the issue open in case the mantainers would like to add more support out of the box for the kicad gerbers files

here there is the final code:
still i do not understand why i am passing two times the path of the gerber file
DrillLayer(real_path, common.read(real_path))
import os
from gerber import common
from gerber.layers import PCBLayer, DrillLayer
from gerber.render import RenderSettings
from gerber.render.cairo_backend import GerberCairoContext
from PIL import Image
SCALE = 25
OFFSET = 20
def render_pcb(input_path, output_file):
img_front_path = os.path.join(input_path, 'front.png')
img_bottom_path = os.path.join(input_path, 'bottom.png')
for file in os.listdir(input_path):
if not os.path.isfile(os.path.join(input_path, file)):
continue
real_path = os.path.join(input_path, file)
# Drill
if file.endswith('.drl'):
drill = DrillLayer(real_path, common.read(real_path))
# Front
elif file.endswith('-F_Cu.gbr'):
copper_front = PCBLayer(real_path, 'top', common.read(real_path))
elif file.endswith('-F_Mask.gbr'):
mask_front = PCBLayer(real_path, 'topmask', common.read(real_path))
elif file.endswith('-F_SilkS.gbr'):
silk_front = PCBLayer(real_path, 'topsilk', common.read(real_path))
# Bottom
elif file.endswith('-B_Cu.gbr'):
copper_bottom = PCBLayer(real_path, 'bottom', common.read(real_path))
elif file.endswith('-B_Mask.gbr'):
mask_bottom = PCBLayer(real_path, 'bottommask', common.read(real_path))
elif file.endswith('-B_SilkS.gbr'):
silk_bottom = PCBLayer(real_path, 'bottomsilk', common.read(real_path))
else:
continue
# Create a new drawing context
ctx = GerberCairoContext(scale=SCALE)
ctx.render_layer(copper_front)
ctx.render_layer(mask_front)
ctx.render_layer(silk_front)
ctx.render_layer(drill)
# Write png file
ctx.dump(img_front_path)
# Clear the drawing
ctx.clear()
# Render bottom layers
ctx.render_layer(copper_bottom)
ctx.render_layer(mask_bottom)
ctx.render_layer(silk_bottom)
ctx.render_layer(drill, settings=RenderSettings(mirror=True))
# Write png file
ctx.dump(img_bottom_path)
ctx.clear()
# Concatenate
front = Image.open(img_front_path)
bottom = Image.open(img_bottom_path)
render = Image.new('RGB', (front.width, front.height * 2 + OFFSET))
render.paste(front, (0, 0))
render.paste(bottom, (0, front.height + OFFSET))
render.save(output_file)
render.show()
project_path = os.path.dirname(os.path.realpath(__file__))
gerber_path = os.path.join(project_path, 'Gerber-test')
project_name = "test-pcb"
output_path = os.path.join(project_path, project_name + ".png")
print('Project:{}\nGerber:\t{}\nPNG:\t{}'.format(project_path, gerber_path, output_path))
render_pcb(gerber_path, output_path)
:)
still i do not understand why i am passing two times the path of the gerber file
DrillLayer(real_path, common.read(real_path))
DrillLayer needs the path and the content of the file. common.read needs the path to get the content of the file.
Hello, In the process of using it, I successfully render Gerber files on windows, but when porting to the Ubuntu system, all top layer inversion will appear when combined rendering, and there is no problem with single
