/************************************************************************** * * marklist.c -- Functions managing the list of marks * Copyright (C) 1994 Stuart Inglis * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: marklist.c 3745 2003-02-20 21:20:24Z mdewsnip $ * **************************************************************************/ #include "sysfuncs.h" #include "marklist.h" #include "pbmtools.h" #include "utils.h" void marktype_dump (marktype d) { fprintf (stderr, "symnum: %d\n", d.symnum); fprintf (stderr, "xpos: %d, ypos: %d\n", d.xpos, d.ypos); fprintf (stderr, "w: %d, h: %d\n", d.w, d.h); fprintf (stderr, "xcen: %d, ycen: %d\n", d.xcen, d.ycen); write_library_mark (stderr, d); } /* copy, including make a copy of the bitmap */ marktype marktype_copy (marktype d) { marktype d2; int i, j; d2 = d; d2.bitmap = pbm_allocarray (d2.w, d2.h); for (i = 0; i < d2.w; i++) for (j = 0; j < d2.h; j++) pbm_putpixel (d2.bitmap, i, j, pbm_getpixel (d.bitmap, i, j)); return d2; } float marktype_density (marktype d) { return d.set / (float) (d.w * d.h); } void marktype_calc_centroid (marktype * b) { int r, c; int count = 0; int xtot = 0, ytot = 0; for (r = 0; r < b->h; r++) for (c = 0; c < b->w; c++) if (pbm_getpixel (b->bitmap, c, r)) { count++; xtot += c; ytot += r; } if (count) { xtot /= count; ytot /= count; } b->xcen = xtot; b->ycen = ytot; } static void marktype_area (marktype * d) { int x, y; int set = 0; for (y = 0; y < d->h; y++) for (x = 0; x < d->w; x++) if (pbm_getpixel (d->bitmap, x, y)) set++; d->set = set; } static void marktype_h_runs (marktype * d) { int x, y; int inrun = 0, num = 0; int foundblack = 0; for (y = 0; y < d->h; y++) { inrun = 0; foundblack = 0; for (x = 0; x < d->w; x++) { if ((!foundblack) && (pbm_getpixel (d->bitmap, x, y))) foundblack = 1; if ((foundblack) && (pbm_getpixel (d->bitmap, x, y) == 0)) inrun = 1; if ((inrun) && (pbm_getpixel (d->bitmap, x, y))) { num++; inrun = 0; foundblack = 0; } } } d->h_runs = num; } static void marktype_v_runs (marktype * d) { int x, y; int inrun = 0, num = 0; int foundblack = 0; for (x = 0; x < d->w; x++) { inrun = 0; foundblack = 0; for (y = 0; y < d->h; y++) { if ((!foundblack) && (pbm_getpixel (d->bitmap, x, y))) foundblack = 1; if ((foundblack) && (pbm_getpixel (d->bitmap, x, y) == 0)) inrun = 1; if ((inrun) && (pbm_getpixel (d->bitmap, x, y))) { num++; inrun = 0; foundblack = 0; } } } d->v_runs = num; } /* assume we already have the centroid! */ static void marktype_prog_cent (marktype * d) { int x, y; int xtot = 0, ytot = 0; int num = 0; xtot = ytot = num = 0; for (x = 0; x < d->xcen; x++) for (y = 0; y < d->ycen; y++) if (pbm_getpixel (d->bitmap, x, y)) { xtot += x; ytot += y; num++; } if (num == 0) { d->xcen1 = -1; d->ycen1 = -1; } else { d->xcen1 = xtot / num; d->ycen1 = ytot / num; } xtot = ytot = num = 0; for (x = d->xcen; x < d->w; x++) for (y = 0; y < d->ycen; y++) if (pbm_getpixel (d->bitmap, x, y)) { xtot += x; ytot += y; num++; } if (num == 0) { d->xcen2 = -1; d->ycen2 = -1; } else { d->xcen2 = xtot / num; d->ycen2 = ytot / num; } xtot = ytot = num = 0; for (x = 0; x < d->xcen; x++) for (y = d->ycen; y < d->h; y++) if (pbm_getpixel (d->bitmap, x, y)) { xtot += x; ytot += y; num++; } if (num == 0) { d->xcen3 = -1; d->ycen3 = -1; } else { d->xcen3 = xtot / num; d->ycen3 = ytot / num; } xtot = ytot = num = 0; for (x = d->xcen; x < d->w; x++) for (y = d->ycen; y < d->h; y++) if (pbm_getpixel (d->bitmap, x, y)) { xtot += x; ytot += y; num++; } if (num == 0) { d->xcen4 = -1; d->ycen4 = -1; } else { d->xcen4 = xtot / num; d->ycen4 = ytot / num; } } /* call this to get all features */ void marktype_calc_features (marktype * d, char str[]) { if (strlen (str)) strcpy (d->name, str); marktype_calc_centroid (d); marktype_area (d); marktype_prog_cent (d); marktype_h_runs (d); marktype_v_runs (d); } void marktype_adj_bound (marktype * m) { int x, y, w, h; int xpos, ypos; int top = 0, left = 0, right = 0, bot = 0; marktype temp; w = m->w; h = m->h; xpos = m->xpos; ypos = m->ypos; for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (pbm_getpixel (m->bitmap, x, y)) { top = y; x = w; y = h; } for (y = h - 1; y >= 0; y--) for (x = 0; x < w; x++) if (pbm_getpixel (m->bitmap, x, y)) { bot = y; x = w; y = -1; } for (x = 0; x < w; x++) for (y = 0; y < h; y++) if (pbm_getpixel (m->bitmap, x, y)) { left = x; x = w; y = h; } for (x = w - 1; x >= 0; x--) for (y = 0; y < h; y++) if (pbm_getpixel (m->bitmap, x, y)) { right = x; x = -1; y = h; } temp.w = right - left + 1; temp.h = bot - top + 1; temp.xpos = xpos + left; temp.ypos = ypos + top; temp.bitmap = pbm_allocarray (temp.w, temp.h); for (x = 0; x < temp.w; x++) for (y = 0; y < temp.h; y++) pbm_putpixel (temp.bitmap, x, y, pbm_getpixel (m->bitmap, x + left, y + top)); pbm_freearray (&(m->bitmap), h); marktype_calc_features (&temp, "?"); *m = temp; } /* returns a newly created mark reprenting the average of the marklist */ void marklist_average (marklistptr list, marktype * avgmark) { int w = 0, h = 0; int t = INT_MAX, b = 0, l = INT_MAX, r = 0, matched = 0; marktype d, temp; marklistptr step; static int a[100][100]; int x, y; if (list == NULL) error_msg ("marklist_average", "Can't average 'nothing'!", ""); for (step = list; step; step = step->next) { matched++; temp = step->data; w = max (w, temp.w); h = max (h, temp.h); r = max (r, temp.xcen); l = min (l, temp.xcen); b = max (b, temp.ycen); t = min (t, temp.ycen); } w = w + (r - l); h = h + (b - t); if ((w >= 100) || (h >= 100)) matched = 0; if (matched > 1) { int x_off, y_off; for (x = 0; x < w; x++) for (y = 0; y < h; y++) a[x][y] = 0; for (step = list; step; step = step->next) { x_off = r - step->data.xcen; y_off = b - step->data.ycen; for (x = 0; x < step->data.w; x++) for (y = 0; y < step->data.h; y++) if (pbm_getpixel (step->data.bitmap, x, y)) a[x + x_off][y + y_off]++; } d.w = w; d.h = h; d.bitmap = pbm_allocarray (w, h); for (x = 0; x < w; x++) for (y = 0; y < h; y++) if (a[x][y] > max (1, (matched / 2))) /* > gives better CR than >= */ pbm_putpixel (d.bitmap, x, y, 1); marktype_adj_bound (&d); strcpy (d.name, "?"); marktype_calc_centroid (&d); } else d = marktype_copy (list->data); *avgmark = d; } void marklist_setnull (marklistptr * list) { *list = NULL; } marklistptr marklist_add (marklistptr * list, marktype m) { marklistptr p; if (*list == NULL) { *list = (marklistptr) malloc (sizeof (marklisttype)); if ((*list) == NULL) error_msg ("marklist_add", "OUT of Memory in marklist_add", ""); p = *list; } else { p = *list; while (p->next != NULL) p = p->next; p->next = (marklistptr) malloc (sizeof (marklisttype)); if (p->next == NULL) error_msg ("marklist_add", "OUT of Memory in marklist_add", ""); p = p->next; } p->data = m; p->next = NULL; return p; } marklistptr marklist_addcopy (marklistptr * list, marktype m) { marktype d; d = marktype_copy (m); return marklist_add (list, d); } int marklist_length (marklistptr list) { int count = 0; while (list) { count++; list = list->next; } return count; } void marklist_dump (marklistptr list) { int count = 0; marktype d; while (list) { d = list->data; marktype_dump (d); count++; list = list->next; } } /* pos starts from 0, to up marklist_length-1 */ marklistptr marklist_getat (marklistptr list, int pos, marktype * d) { int count = 0; while (list) { if (count == pos) { *d = list->data; return list; } count++; list = list->next; } fprintf (stderr, "marklist_getat(): access off ends of list: pos %d\n", pos); return NULL; } void marklist_free (marklistptr * list) { marklistptr n; while ((*list) != NULL) { n = (*list)->next; pbm_freearray (&((*list)->data.bitmap), (*list)->data.h); free ((*list)); (*list) = n; } } int marklist_removeat (marklistptr * list, int pos) { marklistptr c, n, p = NULL; int count = 0; if ((pos == 0) && (*list)) { /* if removing the 1st element */ *list = (*list)->next; return 1; } else { c = *list; while (c) { if (count == pos) { /* two cases, no previous, >=1 previous */ if (p == NULL) /* no previous */ { n = c->next; pbm_freearray (&c->data.bitmap, c->data.h); free (c); c = n; return 1; } else /* >=1 previous */ { n = c->next; pbm_freearray (&c->data.bitmap, c->data.h); free (c); p->next = n; return 1; } } count++; p = c; c = c->next; } } fprintf (stderr, "marklist_removeat(): access off ends of list: pos %d\n", pos); return 0; /* nothing was removed */ } marklistptr marklist_next (marklistptr list) { return list->next; } /* only writes out ascii form */ void write_library_mark (FILE * fp, marktype d) { int r, c, rows, cols; int xtot = d.xcen, ytot = d.ycen; rows = d.h; cols = d.w; fprintf (fp, "Mark: %d\n", d.symnum); fprintf (fp, "Char: %s\n", d.name); fprintf (fp, "Cols: %d Rows: %d\n", d.w, d.h); for (r = 0; r < d.h; r++) { for (c = 0; c < d.w; c++) if ((r == ytot) && (c == xtot)) putc (pbm_getpixel (d.bitmap, c, r) ? 'C' : '!', fp); else putc (pbm_getpixel (d.bitmap, c, r) ? 'X' : '.', fp); putc ('\n', fp); } } /* only reads in ascii library */ int read_library_mark (FILE * fp, marktype * d) { int r, c, rows, cols, numread, ch1 = 'C'; char str1[100], str2[100]; numread = fscanf (fp, "%s %d\n", str1, &(d->symnum)); if ((numread != 2) || (strcmp (str1, "Mark:") != 0)) return 0; fscanf (fp, "%s %s\n", str1, (d->name)); fscanf (fp, "%s %d %s %d\n", str1, &(d->w), str2, &(d->h)); cols = d->w; rows = d->h; d->bitmap = pbm_allocarray (cols, rows); for (r = 0; r < rows; r++) { for (c = 0; c < cols; c++) { ch1 = getc (fp); if ((ch1 == 'X') || (ch1 == 'C')) pbm_putpixel (d->bitmap, c, r, 1); else pbm_putpixel (d->bitmap, c, r, 0); } ch1 = getc (fp); } marktype_calc_features (d, "?"); return 1; } int read_library (char libraryname[], marklistptr * library) { int err, count; FILE *lib; marktype d; marklistptr step; lib = fopen (libraryname, "rb"); if (lib == NULL) error_msg ("read_library()", "Trouble opening library file", ""); *library = NULL; count = 0; while (!isEOF (lib)) { err = read_library_mark (lib, &d); if (!err) error_msg ("read_library()", "unknown format of the library file.", ""); d.symnum = count; count++; if ((*library) == NULL) step = marklist_add (library, d); else step = marklist_add (&step, d); } count = marklist_length (*library); fclose (lib); return count; } /********************************************************************** 'elem' routines for coding offsets the elem datatype contains the 3 params for arithmetic coding, stored as a no-duplicates order linked list. ************************************************************************/ void elem_add (elemlist * list, int num) { elemptr temp, nn; int p, f; list->tot++; if (list->head == NULL) { list->head = (elemptr) malloc (sizeof (elem)); if ((list->head) == NULL) error_msg ("", "ekk", ""); temp = list->head; temp->next = NULL; temp->num = num; temp->pos = 0; temp->freq = 1; } else { /* add to list */ temp = list->head; p = 0; f = 0; while ((num > temp->num) && (temp->next != NULL)) { p = temp->pos; f = temp->freq; temp = temp->next; } if (temp->num == num) temp->freq++; else { /* insert it */ nn = (elemptr) malloc (sizeof (elem)); if (nn == NULL) error_msg ("", "ekk", ""); if (num < temp->num) { nn->num = temp->num; nn->pos = temp->pos; nn->freq = temp->freq; nn->next = temp->next; temp->num = num; temp->pos = p + f; temp->freq = 1; temp->next = nn; } else { nn->next = temp->next; temp->next = nn; nn->pos = temp->pos + temp->freq; nn->num = num; nn->freq = 1; temp = nn; } } } /* update frequencies */ temp = temp->next; if (temp) do { temp->pos++; temp = temp->next; } while (temp); } void elem_free (elemlist * list) { elemptr n, p; p = list->head; while (p != NULL) { n = p->next; free (p); p = n; } list->head = NULL; } int elem_find (elemlist * list, int n, int *p, int *f, int *t) { elemptr temp; temp = list->head; while (temp) { if (temp->num == n) { *p = temp->pos; *f = temp->freq + temp->pos; *t = list->tot; return 1; } temp = temp->next; } return 0; } int elem_getrange (elemlist * list, int range, int *num) { elemptr temp; temp = list->head; while (temp) { if ((range >= temp->pos) && (range < (temp->pos + temp->freq))) { *num = temp->num; return 1; } temp = temp->next; } return 0; }