ho_bitmap * ho_bitmap_dilation_n (const ho_bitmap * m, const unsigned char n) { ho_bitmap *m_out; int x, y; unsigned char sum; if (!m) return NULL; /* * allocate memory */ m_out = ho_bitmap_new (m->width, m->height); if (!m_out) return NULL; m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; /* * do dilation */ for (x = 1; x < m->width - 1; x++) for (y = 1; y < m->height - 1; y++) { /* * if white pixel */ if (!ho_bitmap_get (m, x, y)) { sum = ho_bitmap_get (m, x - 1, y - 1) + ho_bitmap_get (m, x - 1, y) + ho_bitmap_get (m, x - 1, y + 1) + ho_bitmap_get (m, x, y - 1) + ho_bitmap_get (m, x, y + 1) + ho_bitmap_get (m, x + 1, y - 1) + ho_bitmap_get (m, x + 1, y) + ho_bitmap_get (m, x + 1, y + 1); if (sum >= n) ho_bitmap_set (m_out, x, y); } else ho_bitmap_set (m_out, x, y); } return m_out; }
ho_bitmap * ho_bitmap_set_height_from_bottom (const ho_bitmap * m, const int height, const int top, const int bottom) { ho_bitmap *m_out; int x, y, locale_top, locale_bottom, locale_height; /* * allocate memory */ m_out = ho_bitmap_new (m->width, m->height); if (!m_out) return NULL; m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; /* * do max_height */ for (x = 0; x < m->width; x++) for (y = m->height - 1; y >= 0; y--) { /* * if black pixel */ if (ho_bitmap_get (m, x, y)) { y -= height; locale_height = height; locale_top = top; locale_bottom = bottom; if (y - top < 0) locale_top = y; if (y + height + bottom > m->height) { locale_bottom = 0; locale_height = m->height - y - 1; } ho_bitmap_draw_vline (m_out, x, y - locale_top, locale_height + locale_bottom); y = -1; } } return m_out; }
ho_bitmap * ho_bitmap_herode (const ho_bitmap * m, const int size) { ho_bitmap *m_out; int x, y; int k; int l, last; /* * allocate memory */ m_out = ho_bitmap_new (m->width, m->height); if (!m_out) return NULL; m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; /* * set all bitmap black */ memset ((void *) (m_out->data), 0xff, m_out->height * m_out->rowstride); for (y = 0; y < m->height; y++) { last = -size; for (x = 0; x < m->width; x++) { if (!ho_bitmap_get (m, x, y)) /* white pixel */ { ho_bitmap_unset (m_out, x, y); l = (int) x - last; if ((l > 1) && (l < size)) { if (last < 0) last = 0; for (k = last; k < x; k++) ho_bitmap_unset (m_out, k, y); } last = x; } } } return m_out; }
ho_bitmap * ho_bitmap_hlink (const ho_bitmap * m, const int size) { ho_bitmap *m_out; int x, y; int k; int l, last; /* * allocate memory */ m_out = ho_bitmap_new (m->width, m->height); if (!m_out) return NULL; m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; for (y = 0; y < m->height; y++) { last = -size; for (x = 0; x < m->width; x++) { if (ho_bitmap_get (m, x, y)) /* black pixel */ { ho_bitmap_set (m_out, x, y); l = (int) x - last; if ((l > 1) && (l < size)) { if (last < 0) last = 0; for (k = last; k < x; k++) ho_bitmap_set (m_out, k, y); } last = x; } } } return m_out; }
double ho_bitmap_get_fill (const ho_bitmap * m, const int x, const int y, const int width, const int height) { int current_x, current_y; int fill; if (!width || !height || x < 0 || y < 0 || (x + width) > m->width || (y + height) > m->height) return -1.0; fill = 0; for (current_y = y; current_y < y + height; current_y++) for (current_x = x; current_x < x + width; current_x++) fill += ho_bitmap_get (m, current_x, current_y); return (double) fill / (double) (width * height); }
ho_bitmap * ho_bitmap_clone_window (const ho_bitmap * m, const int x, const int y, const int width, const int height) { ho_bitmap *m_out; int x1, y1; /* * allocate memory */ m_out = ho_bitmap_new (width, height); if (!m_out) return NULL; /* * set origin of sub window */ m_out->x = m->x + x; m_out->y = m->y + y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; /* * copy data */ for (x1 = 0; x1 < width && x1 < m->width; x1++) for (y1 = 0; y1 < height && y1 < m->height; y1++) { if ((x + x1) > 0 && (y + y1) > 0 && ho_bitmap_get (m, x + x1, y + y1)) ho_bitmap_set (m_out, x1, y1); } return m_out; }
ho_bitmap * ho_bitmap_rotate (const ho_bitmap * m, const double angle) { ho_bitmap *m_out; int x, y; int xtag, ytag; double xtag_part, ytag_part; double angle_rads; double new_point; unsigned char neighbors[2][2]; double affine_matrix[2][2]; /* * allocate memory */ m_out = ho_bitmap_new (m->width, m->height); if (!m_out) return NULL; m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; /* get angle in radians */ angle_rads = angle *(2.0 * M_PI / 360); /* fill rotation matrix */ affine_matrix[0][0] = cos (angle_rads); affine_matrix[0][1] = sin (angle_rads); affine_matrix[1][0] = -affine_matrix[0][1]; affine_matrix[1][1] = affine_matrix[0][0]; /* * copy data */ for (x = 0; x < m->width; x++) for (y = 0; y < m->height; y++) { xtag_part = x * affine_matrix[0][0] + y * affine_matrix[0][1]; ytag_part = x * affine_matrix[1][0] + y * affine_matrix[1][1]; xtag = (int) xtag_part; ytag = (int) ytag_part; xtag_part = xtag_part - (double) xtag; ytag_part = ytag_part - (double) ytag; /* get neighbors */ if (xtag < 1 || ytag < 1 || xtag >= m->width || ytag >= m->height) { new_point = 0; } else { neighbors[0][0] = ho_bitmap_get (m, xtag - 1, ytag - 1); neighbors[0][1] = ho_bitmap_get (m, xtag - 1, ytag - 0); neighbors[1][0] = ho_bitmap_get (m, xtag - 0, ytag - 1); neighbors[1][1] = ho_bitmap_get (m, xtag - 0, ytag - 0); new_point = (double) neighbors[0][0] * (1.0 - xtag_part) * (1.0 - ytag_part) + (double) neighbors[0][1] * (1.0 - xtag_part) * ytag_part + (double) neighbors[1][0] * xtag_part * (1.0 - ytag_part) + (double) neighbors[1][1] * xtag_part * ytag_part; } /* get new point */ if (new_point > 0.5) ho_bitmap_set (m_out, x, y); } return m_out; }
ho_bitmap * ho_bitmap_filter_remove_dots (const ho_bitmap * m, const unsigned char erosion_n, const unsigned char dilation_n) { int x, y; unsigned char sum; ho_bitmap *m_temp; ho_bitmap *m_out; ho_objmap *m_obj; int index; int width, height; /* allocate memory */ m_out = ho_bitmap_new (m->width, m->height); if (!m_out) return NULL; m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; /* connect all the small dots */ m_temp = ho_bitmap_dilation (m); /* check the size of objects */ m_obj = ho_objmap_new_from_bitmap (m_temp); ho_bitmap_free (m_temp); for (x = 1; x < (m->width - 1); x++) for (y = 1; y < (m->height - 1); y++) { /* check the size of this pixel's object */ index = ho_objmap_get (m_obj, x, y); if (index) { width = (((m_obj->obj_list)->objects)[index - 1]).width; height = (((m_obj->obj_list)->objects)[index - 1]).height; } else { width = 0; height = 0; } /* in a big object do erosion */ if (width > m->width / 4 || height > m->height / 4) { if (ho_bitmap_get (m, x, y)) /* black pixel */ { sum = ho_bitmap_get (m, x - 1, y - 1) + ho_bitmap_get (m, x - 1, y) + ho_bitmap_get (m, x - 1, y + 1) + ho_bitmap_get (m, x, y - 1) + ho_bitmap_get (m, x, y + 1) + ho_bitmap_get (m, x + 1, y - 1) + ho_bitmap_get (m, x + 1, y) + ho_bitmap_get (m, x + 1, y + 1); /* n number of white pixels or more */ if ((8 - sum) < erosion_n) ho_bitmap_set (m_out, x, y); } } else /* if in a small object do dilation */ { if (!ho_bitmap_get (m, x, y)) /* white pixel */ { sum = ho_bitmap_get (m, x - 1, y - 1) + ho_bitmap_get (m, x - 1, y) + ho_bitmap_get (m, x - 1, y + 1) + ho_bitmap_get (m, x, y - 1) + ho_bitmap_get (m, x, y + 1) + ho_bitmap_get (m, x + 1, y - 1) + ho_bitmap_get (m, x + 1, y) + ho_bitmap_get (m, x + 1, y + 1); /* n number of black neighbors or more */ if (sum >= dilation_n) ho_bitmap_set (m_out, x, y); } else ho_bitmap_set (m_out, x, y); } } ho_objmap_free (m_obj); return m_out; }
int ho_recognize_nikud_dimentions (const ho_bitmap * m_text, const ho_bitmap * m_mask, double *height, double *width, double *top, double *bottom, double *top_left, double *top_mid, double *top_right, double *mid_left, double *mid_right, double *bottom_left, double *bottom_mid, double *bottom_right, double *dots_above, double *dots_below, double *dots_inside, double *objs_above, double *objs_below, double *objs_inside, double *main_obj_height, double *main_obj_width, double *top_dot_x, double *inside_dot_x, double *font_width_by_height) { int i, x, y; int obj_width, obj_height; int obj_x, obj_y; int obj_w, obj_h; int line_start, line_end, line_height; int sum, font_start_x, font_end_x, font_height, font_width; int font_start_y, font_end_y; ho_objmap *o_obj = NULL; unsigned char is_dot, is_obj; /* init values to zero */ *height = 0.0; *width = 0.0; *top = 0.0; *bottom = 0.0; *top_left = 0.0; *top_mid = 0.0; *top_right = 0.0; *mid_left = 0.0; *mid_right = 0.0; *bottom_left = 0.0; *bottom_mid = 0.0; *bottom_right = 0.0; *dots_above = 0.0; *dots_below = 0.0; *dots_inside = 0.0; *objs_above = 0.0; *objs_below = 0.0; *objs_inside = 0.0; *top_dot_x = 0.0; *inside_dot_x = 0.0; *font_width_by_height = 0.0; /* get line start and end */ x = m_mask->width / 2; for (y = 0; y < m_mask->height && !ho_bitmap_get (m_mask, x, y); y++) ; line_start = y - 1; for (; y < m_mask->height && ho_bitmap_get (m_mask, x, y); y++) ; line_end = y; line_height = line_end - line_start; if (line_height < 4 || m_text->width < 4) return TRUE; *font_width_by_height = (double) m_mask->width / (double) line_height; /* get all the objects of nikud */ o_obj = ho_objmap_new_from_bitmap (m_text); if (!o_obj) return TRUE; /* if no nikud just return */ if (ho_objmap_get_size (o_obj) == 0) { ho_objmap_free (o_obj); return FALSE; } /* count points and objects above/in/below font */ obj_x = 0; obj_y = 0; obj_w = 0; obj_h = 0; for (i = 0; i < ho_objmap_get_size (o_obj); i++) { /* is this object inside line ? */ y = ho_objmap_get_object (o_obj, i).y; x = ho_objmap_get_object (o_obj, i).x; obj_width = ho_objmap_get_object (o_obj, i).width; obj_height = ho_objmap_get_object (o_obj, i).height; is_dot = (obj_height < line_height / 4 && obj_height > line_height / 16 && obj_width < line_height / 4 && obj_width > line_height / 16); is_obj = (obj_height > line_height / 4 || obj_width > line_height / 4); if (is_dot) { /* count */ if ((y + obj_height / 2) < line_start) { (*dots_above) += 0.1; *top_dot_x = (double) x / (double) (m_text->width); } else if ((y + obj_height / 2) > line_end) { (*dots_below) += 0.1; } else { (*dots_inside) += 0.1; *inside_dot_x = (double) x / (double) (m_text->width); } } else if (is_obj) { /* count */ if ((y + obj_height / 2) < line_start) { (*objs_above) += 0.1; } else if ((y + obj_height / 2) > line_end) { (*objs_below) += 0.1; /* get metrics of bigest obj under font */ if (obj_width > *width) { obj_x = x; obj_y = y; obj_w = obj_width; obj_h = obj_height; } } else { (*objs_inside) += 0.1; } } } /* free obj map */ ho_objmap_free (o_obj); /* if nothing below font we are finished */ if (!(*objs_below) && !(*dots_below)) return FALSE; /* get nikud metrics */ *main_obj_height = 2.0 * (double) obj_h / (double) line_height; *main_obj_width = 2.0 * (double) obj_w / (double) line_height; if (obj_y && obj_h) { *top = 2.0 * (double) (obj_y - line_end) / (double) line_height; *bottom = 2.0 * (double) ((obj_y + obj_h) - line_end) / (double) line_height; } /* get nikud start and end */ sum = 0; for (y = line_end + 1; y < m_text->height && sum == 0; y++) for (sum = 0, x = 1; x < (m_text->width - 1); x++) sum += ho_bitmap_get (m_text, x, y); font_start_y = y - 1; sum = 0; for (y = m_text->height - 1; y > font_start_y && sum == 0; y--) for (sum = 0, x = 1; x < (m_text->width - 1); x++) sum += ho_bitmap_get (m_text, x, y); font_end_y = y + 1; font_height = font_end_y - font_start_y; if (!font_height) return TRUE; *height = 2.0 * (double) font_height / (double) line_height; sum = 0; for (x = 2; x < m_text->width && sum == 0; x++) for (sum = 0, y = line_end; y < (m_text->height - 1); y++) sum += ho_bitmap_get (m_text, x, y); font_start_x = x - 1; sum = 0; for (sum = 0, x = m_text->width - 2; x > (font_start_x + 1) && sum == 0; x--) for (sum = 0, y = line_end; y < (m_text->height - 1); y++) sum += ho_bitmap_get (m_text, x, y); font_end_x = x + 1; font_width = font_end_x - font_start_x; if (!font_width) return TRUE; *width = 2.0 * (double) font_width / (double) line_height; /* get nikud egdes */ for (y = font_start_y, x = font_start_x; x < font_end_x && y < (font_end_y) && !ho_bitmap_get (m_text, x, y); x++, y++) ; *top_left = (double) (x - font_start_x) / (double) (line_height / 4); if (*top_left > 1.0) *top_left = 1.0; for (y = font_end_y, x = font_start_x; x < font_end_x && y > (font_start_y) && !ho_bitmap_get (m_text, x, y); x++, y--) ; *bottom_left = (double) (x - font_start_x) / (double) (line_height / 4); if (*bottom_left > 1.0) *bottom_left = 1.0; for (y = font_start_y, x = font_end_x - 1; x > font_start_x && y < (font_end_y) && !ho_bitmap_get (m_text, x, y); x--, y++) ; *top_right = (double) (font_end_x - x) / (double) (line_height / 4); if (*top_right > 1.0) *top_right = 1.0; for (y = font_end_y, x = font_end_x - 1; x > font_start_x && y > font_start_y && !ho_bitmap_get (m_text, x, y); x--, y--) ; *bottom_right = (double) (font_end_x - x) / (double) (line_height / 4); if (*bottom_right > 1.0) *bottom_right = 1.0; for (y = font_start_y, x = font_start_x + font_width / 2; y < (font_start_y + font_height) && !ho_bitmap_get (m_text, x, y); y++) ; *top_mid = (double) (y - font_start_y) / (double) (line_height / 4); if (*top_mid > 1.0) *top_mid = 1.0; for (y = font_end_y, x = font_start_x + font_width / 2; y > (font_start_y + font_height) && !ho_bitmap_get (m_text, x, y); y--) ; *bottom_mid = (double) (font_end_y - y) / (double) (line_height / 4); if (*bottom_mid > 1.0) *bottom_mid = 1.0; for (y = font_start_y + font_height / 2, x = font_start_x; x < (font_end_x) && !ho_bitmap_get (m_text, x, y); x++) ; *mid_left = (double) (x - font_start_x) / (double) (line_height / 4); if (*mid_left > 1.0) *mid_left = 1.0; for (y = font_start_y + font_height / 2, x = font_end_x - 1; x > (font_start_x) && !ho_bitmap_get (m_text, x, y); x--) ; *mid_right = (double) (font_end_x - x) / (double) (line_height / 4); if (*mid_right > 1.0) *mid_right = 1.0; return FALSE; }