mirror of
git://projects.qi-hardware.com/eda-tools.git
synced 2024-11-23 11:13:44 +02:00
sch2fig/: implement "diff" driver (WIP)
This commit is contained in:
parent
f0f2303fc3
commit
c5064a8dca
@ -13,9 +13,9 @@
|
|||||||
NAME = sch2fig
|
NAME = sch2fig
|
||||||
OBJS = main.o sch-parse.o sch-render.o lib-parse.o lib-render.o \
|
OBJS = main.o sch-parse.o sch-render.o lib-parse.o lib-render.o \
|
||||||
file.o \
|
file.o \
|
||||||
style.o fig.o record.o cairo.o gfx.o dwg.o text.o misc.o
|
style.o fig.o record.o cairo.o diff.o gfx.o dwg.o text.o misc.o
|
||||||
|
|
||||||
CFLAGS = -g -O -Wall -Wextra -Wno-unused-parameter -Wshadow \
|
CFLAGS = -g -Wall -Wextra -Wno-unused-parameter -Wshadow \
|
||||||
-Wmissing-prototypes -Wmissing-declarations \
|
-Wmissing-prototypes -Wmissing-declarations \
|
||||||
`pkg-config --cflags cairo`
|
`pkg-config --cflags cairo`
|
||||||
LIBS = -lm `pkg-config --libs cairo`
|
LIBS = -lm `pkg-config --libs cairo`
|
||||||
|
@ -19,3 +19,8 @@
|
|||||||
- on parse error, politely complain, don't terminate
|
- on parse error, politely complain, don't terminate
|
||||||
- implement destructors
|
- implement destructors
|
||||||
- check for memory leaks
|
- check for memory leaks
|
||||||
|
- record.c (bb_rot): implement bounding boxes for text
|
||||||
|
- nesting gfx in diff is a huge kludge, caused by global vars in gfx.c
|
||||||
|
- move path name guessing into file.c
|
||||||
|
- return indication of whether diff found any differences
|
||||||
|
- in diff, pass only options understood by cairo_png
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -395,6 +396,42 @@ static void cr_pdf_end(void *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t *cairo_img_end(void *ctx, int *w, int *h, int *stride)
|
||||||
|
{
|
||||||
|
struct cairo_ctx *cc = ctx;
|
||||||
|
uint32_t *data;
|
||||||
|
|
||||||
|
end_common(cc, w, h);
|
||||||
|
|
||||||
|
*stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, *w);
|
||||||
|
data = alloc_size(*stride * *h);
|
||||||
|
|
||||||
|
cc->s = cairo_image_surface_create_for_data((unsigned char *) data,
|
||||||
|
CAIRO_FORMAT_RGB24, *w, *h, *stride);
|
||||||
|
cc->cr = cairo_create(cc->s);
|
||||||
|
|
||||||
|
set_color(cc->cr, COLOR_WHITE);
|
||||||
|
cairo_paint(cc->cr);
|
||||||
|
|
||||||
|
cairo_select_font_face(cc->cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
|
||||||
|
CAIRO_FONT_WEIGHT_BOLD);
|
||||||
|
cairo_set_line_width(cc->cr, 2);
|
||||||
|
|
||||||
|
record_replay(&cc->record);
|
||||||
|
record_destroy(&cc->record);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cairo_img_write(void *ctx, const char *name)
|
||||||
|
{
|
||||||
|
struct cairo_ctx *cc = ctx;
|
||||||
|
|
||||||
|
cairo_surface_write_to_png(cc->s, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----- Operations -------------------------------------------------------- */
|
/* ----- Operations -------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,8 +11,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef CAIRO_H
|
#ifndef MY_CAIRO_H
|
||||||
#define CAIRO_H
|
#define MY_CAIRO_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
|
|
||||||
@ -20,4 +22,10 @@
|
|||||||
extern const struct gfx_ops cairo_png_ops;
|
extern const struct gfx_ops cairo_png_ops;
|
||||||
extern const struct gfx_ops cairo_pdf_ops;
|
extern const struct gfx_ops cairo_pdf_ops;
|
||||||
|
|
||||||
#endif /* !CAIRO_H */
|
#define cairo_img_ops cairo_png_ops /* just don't call cairo_img_ops.end */
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t *cairo_img_end(void *ctx, int *w, int *h, int *stride);
|
||||||
|
void cairo_img_write(void *ctx, const char *name);
|
||||||
|
|
||||||
|
#endif /* !MY_CAIRO_H */
|
||||||
|
280
sch2fig/diff.c
Normal file
280
sch2fig/diff.c
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
/*
|
||||||
|
* diff.c - Schematics difference
|
||||||
|
*
|
||||||
|
* Written 2016 by Werner Almesberger
|
||||||
|
* Copyright 2016 by Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "cairo.h"
|
||||||
|
#include "sch.h"
|
||||||
|
#include "lib.h"
|
||||||
|
#include "diff.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define DEFAULT_FRAME_RADIUS 30
|
||||||
|
|
||||||
|
|
||||||
|
struct area {
|
||||||
|
int xa, ya, xb, yb;
|
||||||
|
struct area *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct diff {
|
||||||
|
void *cr_ctx;
|
||||||
|
uint32_t *new_img;
|
||||||
|
int w, h, stride;
|
||||||
|
const char *output_name;
|
||||||
|
int frame_radius;
|
||||||
|
struct area *areas;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- Wrappers ---------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
static void diff_line(void *ctx, int sx, int sy, int ex, int ey,
|
||||||
|
int color, unsigned layer)
|
||||||
|
{
|
||||||
|
const struct diff *diff = ctx;
|
||||||
|
|
||||||
|
cairo_img_ops.line(diff->cr_ctx, sx, sy, ex, ey, color, layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void diff_poly(void *ctx,
|
||||||
|
int points, const int x[points], const int y[points],
|
||||||
|
int color, int fill_color, unsigned layer)
|
||||||
|
{
|
||||||
|
const struct diff *diff = ctx;
|
||||||
|
|
||||||
|
cairo_img_ops.poly(diff->cr_ctx, points, x, y,
|
||||||
|
color, fill_color, layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void diff_circ(void *ctx, int x, int y, int r,
|
||||||
|
int color, int fill_color, unsigned layer)
|
||||||
|
{
|
||||||
|
const struct diff *diff = ctx;
|
||||||
|
|
||||||
|
cairo_img_ops.circ(diff->cr_ctx, x, y, r, color, fill_color, layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void diff_arc(void *ctx, int x, int y, int r, int sa, int ea,
|
||||||
|
int color, int fill_color, unsigned layer)
|
||||||
|
{
|
||||||
|
const struct diff *diff = ctx;
|
||||||
|
|
||||||
|
cairo_img_ops.arc(diff->cr_ctx, x, y, r, sa, ea,
|
||||||
|
color, fill_color, layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void diff_text(void *ctx, int x, int y, const char *s, unsigned size,
|
||||||
|
enum text_align align, int rot, unsigned color, unsigned layer)
|
||||||
|
{
|
||||||
|
const struct diff *diff = ctx;
|
||||||
|
|
||||||
|
cairo_img_ops.text(diff->cr_ctx, x, y, s, size, align, rot,
|
||||||
|
color, layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned diff_text_width(void *ctx, const char *s, unsigned size)
|
||||||
|
{
|
||||||
|
const struct diff *diff = ctx;
|
||||||
|
|
||||||
|
return cairo_img_ops.text_width(diff->cr_ctx, s, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- Initialization and termination ------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
static void *diff_init(int argc, char *const *argv)
|
||||||
|
{
|
||||||
|
struct diff *diff;
|
||||||
|
char c;
|
||||||
|
int arg;
|
||||||
|
struct sch_ctx new_sch;
|
||||||
|
struct lib new_lib;
|
||||||
|
|
||||||
|
diff = alloc_type(struct diff);
|
||||||
|
diff->areas = NULL;
|
||||||
|
|
||||||
|
sch_init(&new_sch, 0);
|
||||||
|
lib_init(&new_lib);
|
||||||
|
|
||||||
|
diff->output_name = NULL;
|
||||||
|
diff->frame_radius = DEFAULT_FRAME_RADIUS;
|
||||||
|
while ((c = getopt(argc, argv, "o:s:")) != EOF)
|
||||||
|
switch (c) {
|
||||||
|
case 'o':
|
||||||
|
diff->output_name = optarg;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
/* for cairo_png */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(*argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc - optind < 1)
|
||||||
|
usage(*argv);
|
||||||
|
|
||||||
|
for (arg = optind; arg != argc - 1; arg++)
|
||||||
|
lib_parse(&new_lib, argv[arg]);
|
||||||
|
sch_parse(&new_sch, argv[argc - 1], &new_lib);
|
||||||
|
|
||||||
|
optind = 0;
|
||||||
|
gfx_init(&cairo_img_ops, argc, argv);
|
||||||
|
diff->cr_ctx = gfx_ctx;
|
||||||
|
sch_render(new_sch.sheets);
|
||||||
|
diff->new_img = cairo_img_end(gfx_ctx,
|
||||||
|
&diff->w, &diff->h, &diff->stride);
|
||||||
|
|
||||||
|
optind = 0;
|
||||||
|
diff->cr_ctx = cairo_img_ops.init(argc, argv);
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* steal from schhist/ppmdiff.c */
|
||||||
|
|
||||||
|
#define ONLY_OLD 0xff0000
|
||||||
|
#define ONLY_NEW 0x00d000
|
||||||
|
#define BOTH 0x707070
|
||||||
|
|
||||||
|
#define AREA_FILL 0xffffc8
|
||||||
|
|
||||||
|
|
||||||
|
static void mark_area(struct diff *diff, int x, int y)
|
||||||
|
{
|
||||||
|
struct area *area;
|
||||||
|
|
||||||
|
for (area = diff->areas; area; area = area->next)
|
||||||
|
if (x >= area->xa && x <= area->xb &&
|
||||||
|
y >= area->ya && y <= area->yb) {
|
||||||
|
if (area->xa > x - diff->frame_radius)
|
||||||
|
area->xa = x - diff->frame_radius;
|
||||||
|
if (area->xb < x + diff->frame_radius)
|
||||||
|
area->xb = x + diff->frame_radius;
|
||||||
|
if (area->ya > y - diff->frame_radius)
|
||||||
|
area->ya = y - diff->frame_radius;
|
||||||
|
if (area->yb < y + diff->frame_radius)
|
||||||
|
area->yb = y + diff->frame_radius;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
area = alloc_type(struct area);
|
||||||
|
|
||||||
|
area->xa = x - diff->frame_radius;
|
||||||
|
area->xb = x + diff->frame_radius;
|
||||||
|
area->ya = y - diff->frame_radius;
|
||||||
|
area->yb = y + diff->frame_radius;
|
||||||
|
|
||||||
|
area->next = diff->areas;
|
||||||
|
diff->areas = area;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define MASK 0xffffff
|
||||||
|
|
||||||
|
|
||||||
|
static void differences(struct diff *diff, uint32_t *a, const uint32_t *b)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
unsigned skip = diff->w * 4 - diff->stride;
|
||||||
|
|
||||||
|
for (y = 0; y != diff->h; y++) {
|
||||||
|
for (x = 0; x != diff->w; x++) {
|
||||||
|
if (!((*a ^ *b) & MASK)) {
|
||||||
|
*a = ((*a >> 3) & 0x1f1f1f) | 0xe0e0e0;
|
||||||
|
// *a = ((*a >> 2) & 0x3f3f3f) | 0xc0c0c0;
|
||||||
|
} else {
|
||||||
|
mark_area(diff, x, y);
|
||||||
|
//fprintf(stderr, "0x%06x 0x%06x", *a, *b);
|
||||||
|
*a = (*a & MASK) == MASK ? ONLY_NEW :
|
||||||
|
(*b & MASK) == MASK ? ONLY_OLD : BOTH;
|
||||||
|
//fprintf(stderr, "-> 0x%06x\n", *a);
|
||||||
|
}
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
a += skip;
|
||||||
|
b += skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void show_areas(struct diff *diff, uint32_t *a)
|
||||||
|
{
|
||||||
|
const struct area *area;
|
||||||
|
uint32_t *p;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
for (area = diff->areas; area; area = area->next)
|
||||||
|
for (y = area->ya; y != area->yb; y++) {
|
||||||
|
if (y < 0 || y >= diff->h)
|
||||||
|
continue;
|
||||||
|
p = a + y * (diff->stride >> 2);
|
||||||
|
for (x = area->xa; x != area->xb; x++) {
|
||||||
|
if (x >= 0 && x < diff->w &&
|
||||||
|
(p[x] & MASK) == MASK)
|
||||||
|
p[x] = AREA_FILL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void diff_end(void *ctx)
|
||||||
|
{
|
||||||
|
struct diff *diff = ctx;
|
||||||
|
uint32_t *old_img;
|
||||||
|
int w, h, stride;
|
||||||
|
|
||||||
|
old_img = cairo_img_end(diff->cr_ctx, &w, &h, &stride);
|
||||||
|
if (diff->w != w || diff->h != h) {
|
||||||
|
fprintf(stderr, "%d x %d vs. %d x %d image\n",
|
||||||
|
w, h, diff->w, diff->h);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
differences(diff, old_img, diff->new_img);
|
||||||
|
show_areas(diff, old_img);
|
||||||
|
|
||||||
|
if (diff->output_name)
|
||||||
|
cairo_img_write(diff->cr_ctx, diff->output_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- Operations -------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
const struct gfx_ops diff_ops = {
|
||||||
|
.name = "diff",
|
||||||
|
.line = diff_line,
|
||||||
|
.poly = diff_poly,
|
||||||
|
.circ = diff_circ,
|
||||||
|
.arc = diff_arc,
|
||||||
|
.text = diff_text,
|
||||||
|
.text_width = diff_text_width,
|
||||||
|
.init = diff_init,
|
||||||
|
.end = diff_end,
|
||||||
|
};
|
22
sch2fig/diff.h
Normal file
22
sch2fig/diff.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* diff.h - Schematics difference
|
||||||
|
*
|
||||||
|
* Written 2016 by Werner Almesberger
|
||||||
|
* Copyright 2016 by Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DIFF_H
|
||||||
|
#define DIFF_H
|
||||||
|
|
||||||
|
#include "gfx.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern const struct gfx_ops diff_ops;
|
||||||
|
|
||||||
|
#endif /* !DIFF_H */
|
@ -18,8 +18,9 @@
|
|||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
|
|
||||||
|
|
||||||
|
void *gfx_ctx;
|
||||||
|
|
||||||
static const struct gfx_ops *gfx_ops;
|
static const struct gfx_ops *gfx_ops;
|
||||||
static void *gfx_ctx;
|
|
||||||
|
|
||||||
|
|
||||||
void gfx_line(int sx, int sy, int ex, int ey, int color, unsigned layer)
|
void gfx_line(int sx, int sy, int ex, int ey, int color, unsigned layer)
|
||||||
@ -95,8 +96,8 @@ unsigned gfx_text_width(const char *s, unsigned size)
|
|||||||
|
|
||||||
void gfx_init(const struct gfx_ops *ops, int argc, char *const *argv)
|
void gfx_init(const struct gfx_ops *ops, int argc, char *const *argv)
|
||||||
{
|
{
|
||||||
gfx_ops = ops;
|
|
||||||
gfx_ctx = ops->init(argc, argv);
|
gfx_ctx = ops->init(argc, argv);
|
||||||
|
gfx_ops = ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +43,9 @@ struct gfx_ops {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern void *gfx_ctx;
|
||||||
|
|
||||||
|
|
||||||
/* wrappers */
|
/* wrappers */
|
||||||
|
|
||||||
void gfx_line(int sx, int sy, int ex, int ey, int color, unsigned layer);
|
void gfx_line(int sx, int sy, int ex, int ey, int color, unsigned layer);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "fig.h"
|
#include "fig.h"
|
||||||
#include "cairo.h"
|
#include "cairo.h"
|
||||||
|
#include "diff.h"
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "sch.h"
|
#include "sch.h"
|
||||||
@ -30,6 +31,7 @@ static struct gfx_ops const *ops_list[] = {
|
|||||||
&fig_ops,
|
&fig_ops,
|
||||||
&cairo_png_ops,
|
&cairo_png_ops,
|
||||||
&cairo_pdf_ops,
|
&cairo_pdf_ops,
|
||||||
|
&diff_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -43,6 +45,8 @@ void usage(const char *name)
|
|||||||
" png [-o output.png] [-s scale]\n"
|
" png [-o output.png] [-s scale]\n"
|
||||||
" Cairo PDF driver spec:\n"
|
" Cairo PDF driver spec:\n"
|
||||||
" pdf [-o output.pdf] [-s scale]\n"
|
" pdf [-o output.pdf] [-s scale]\n"
|
||||||
|
" Diff driver spec:\n"
|
||||||
|
" diff [-o output.pdf] [-s scale] [file.lib ...] file.sch\n"
|
||||||
, name);
|
, name);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user