pcb-tools icon indicating copy to clipboard operation
pcb-tools copied to clipboard

png bottom image flipped

Open aster94 opened this issue 6 years ago • 7 comments

hello,

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

cairo_example cairo_bottom

As you can see the silkscreen and the drill files should be inversed. Uploading the same files on OSHPark brings to correct images

Gerber-test.zip

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'))

aster94 avatar Dec 21 '19 18:12 aster94

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

MarinMikael avatar Dec 22 '19 06:12 MarinMikael

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

aster94 avatar Dec 22 '19 22:12 aster94

ok that's a little better: only the drill file is inverted

front bottom

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))

aster94 avatar Dec 23 '19 11:12 aster94

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.

MarinMikael avatar Dec 24 '19 05:12 MarinMikael

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

test-pcb

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)

aster94 avatar Dec 25 '19 17:12 aster94

:)

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.

MarinMikael avatar Dec 26 '19 09:12 MarinMikael

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

file gto2 微信图片_20200721170545

xiaoqiangnobug avatar Jul 21 '20 09:07 xiaoqiangnobug