← Back to team overview

kicad-developers team mailing list archive

Re: Import png, jpeg or svg or dxf ?

 

--- In kicad-devel@xxxxxxxxxxxxxxx, Manveru <manveru@...> wrote:

> I think some people expect too much from EDA tool, for logos on PCB simple
> vector entities on description layer are enough - so having modules which
> could draw on description layers will allow to prepare logos for companies
> or engineers who want them.

OK, here's the promised hack for anyone interested... please notice the complete lack of sophistication and the brain damaging inner for in the scan conversion... but, hey, it works, at least on my test cases (the xfree86bw logo and our company logo). The image must be bilevel/grayscale png, black on white (the black will be traced).

====== CUT HERE ======
/* png2emp.c
Quick-and-dirty hack to convert a monochrome PNG in a .emp to be
imported in pcbnew.

It scan converts the image rendering streaks of black pixels as 
graphic lines in the silk layer.

libpng is required for the obvious reason :D:D

Typical compilation:
 
gcc -o png2emp png2emp.c -lpng12 -lz

To use:

./png2emp logo.png LOGO 100
    
Creates the module LOGO in a file named LOGO.emp, using the image
at a resolution of 10mils per pixel.

As usual, no warranty yada yada yada
*/              
#include <stdlib.h>
#include <stdio.h>
#include <png.h>
             
/* Detect horizontal runs of black (value 0) and convert them to lines */
void scan_convert(char *filename, char *modulename,
unsigned w, unsigned h, unsigned char **image, int scale)
{              
int x1,x2,y;
char fname[1024];
strcpy(fname, modulename);
strcat(fname, ".emp");
FILE *fout = fopen(fname, "w");
if (fout == NULL) {
perror("Output file open error");
} else {
int penwidth = scale * 1.5;
/* I'm too lazy for giving a new timestamp... it is ignored anyway
when importing from .emp */
fprintf(fout,
"PCBNEW-LibModule-V1\n"
"$INDEX\n"
"%s\n"
"$EndINDEX\n"
"$MODULE %s\n"
"Po 0 0 0 15 4A393BEC 00000000 ~~\n"
"Li %s\n"
"Sc 00000000\n"
"AR\n"
"Op 0 0 0\n"
"T0 0 0 250 250 0 25 N I 21 N\"%s\"\n"
"T1 0 0 250 250 0 25 N I 21 N\"%s\"\n",
modulename, modulename, modulename, modulename, modulename);
for (y=0; y<h; y++) {
for (x1=0; x1<w; x1++) {
if (image[y][x1] == 0x00) {
for (x2=x1;
(x2<w) && (image[y][x2] == 0x00);
x2++)
;
/* NOTE about the +1 below: I'm not sure everything works
with a zero length line! */
fprintf(fout, "DS %d %d %d %d %d 21\n",
x1*scale, y*scale, x2*scale+1, y*scale, penwidth);
x1 = x2;
}
}
}
fprintf(fout,
"$EndMODULE %s\n"
"$EndLIBRARY\n",modulename);
fclose(fout);
}
}
             
/* from the libpng example.c */
void convert_png(char *file_name, char *modulename, int scale)
{
png_structp png_ptr;
png_infop info_ptr;
FILE *fp;
             
fprintf(stderr, "Opening image %s\n", file_name);
if ((fp = fopen(file_name, "rb")) == NULL) {
perror("Open failed");
return;
}
             
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters. We also supply the
* the compiler header file version, so that we know if the application
* was compiled with a compatible version of the library. REQUIRED
*/
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
             
if (png_ptr == NULL) {
fclose(fp);
return;
}
             
/* Allocate/initialize the memory for image information. REQUIRED. */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(fp);
png_destroy_read_struct(&png_ptr, NULL, NULL);
return;
}
             
/* Set error handling if you are using the setjmp/longjmp method (this is
* the normal method of doing things with libpng). REQUIRED unless you
* set up your own error handlers in the png_create_read_struct() earlier.
*/
             
if (setjmp(png_jmpbuf(png_ptr))) {
/* Free all of the memory associated with the png_ptr and info_ptr */
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
fprintf(stderr, "PNG decoding failed!\n");
/* If we get here, we had a problem reading the file */
return;
}
/*
* If you have enough memory to read in the entire image at once,
* and you need to specify only transforms that can be controlled
* with one of the PNG_TRANSFORM_* bits (this presently excludes
* dithering, filling, setting background, and doing gamma
* adjustment), then you can read the entire image (including
* pixels) into the info structure with this call:
*/
png_init_io(png_ptr, fp);
png_read_png(png_ptr, info_ptr,
PNG_TRANSFORM_EXPAND|
PNG_TRANSFORM_STRIP_16|
PNG_TRANSFORM_STRIP_ALPHA|
PNG_TRANSFORM_PACKING,
NULL);
/* At this point you have read the entire image */
int bpp,cmode,channels;
png_uint_32 w,h;
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bpp, &cmode, NULL, NULL, NULL);
channels = png_get_channels(png_ptr, info_ptr);
fprintf(stderr, "%ux%u image, %d bpp, %d channels, mode %d\n",
w, h, bpp, channels, cmode);
if (bpp == 8 && channels == 1) {
unsigned char **image = png_get_rows(png_ptr, info_ptr);
scan_convert(file_name, modulename, w, h, image, scale);
} else {
fprintf(stderr, "Only single channel 8bpp PNG are supported\n");
}
             
/* clean up after the read, and free any memory allocated - REQUIRED */
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
}
             
int main(int argc, char *argv[])
{
if (argc == 4) {
convert_png(argv[1],argv[2],atoi(argv[3]));
} else {
fprintf(stderr, "Usage: %s pngfile modulename scale\n", argv[0]);
}
return 0;
}







Follow ups

References