static int blits_intersect_or_touch(mdjvu_image_t image, int32 b1, int32 b2) { int32 x1 = mdjvu_image_get_blit_x(image, b1); int32 x2 = mdjvu_image_get_blit_x(image, b2); int32 y1 = mdjvu_image_get_blit_y(image, b1); int32 y2 = mdjvu_image_get_blit_y(image, b2); mdjvu_bitmap_t bitmap1 = mdjvu_image_get_blit_bitmap(image, b1); mdjvu_bitmap_t bitmap2 = mdjvu_image_get_blit_bitmap(image, b2); int32 w1 = mdjvu_bitmap_get_width(bitmap1); int32 w2 = mdjvu_bitmap_get_width(bitmap2); int32 h1 = mdjvu_bitmap_get_height(bitmap1); int32 h2 = mdjvu_bitmap_get_height(bitmap2); return segments_intersect_or_touch(x1, w1, x2, w2) && segments_intersect_or_touch(y1, h1, y2, h2); }
MDJVU_IMPLEMENT void mdjvu_sort_blits(mdjvu_image_t img) { /* We're going to sort only blits with `is_a_letter' flag set. */ int32 char_blit_count = 0; int32 blit_count, i, j, maxtopchange, ccno; BlitPassport *bps; int32 *bottoms, *passport_of_blit; if (!mdjvu_image_has_not_a_letter_flags(img)) mdjvu_calculate_not_a_letter_flags(img); /* Count letter blits */ blit_count = mdjvu_image_get_blit_count(img); for (i = 0; i < blit_count; i++) { mdjvu_bitmap_t bmp = mdjvu_image_get_blit_bitmap(img, i); if (!mdjvu_image_get_not_a_letter_flag(img, bmp)) char_blit_count++; } if (char_blit_count < 2) return; /* Allocate `bps' and `bottoms' arrays */ bps = (BlitPassport *) malloc(char_blit_count * sizeof(BlitPassport)); bottoms = (int32 *) malloc(char_blit_count * sizeof(int32)); /* Fill in `bps' with character blit passports */ j = 0; for (i = 0; i < blit_count; i++) { mdjvu_bitmap_t bmp = mdjvu_image_get_blit_bitmap(img, i); if (!mdjvu_image_get_not_a_letter_flag(img, bmp)) { int32 x = bps[j].left = mdjvu_image_get_blit_x(img, i); int32 y = bps[j].top = mdjvu_image_get_blit_y(img, i);; bps[j].right = x + mdjvu_bitmap_get_width(bmp) - 1; bps[j].bottom = y + mdjvu_bitmap_get_height(bmp) - 1; bps[j].original_index = i; j++; } } /* Sort the BlitPassports list in top-to-bottom order. */ qsort(bps, char_blit_count, sizeof(BlitPassport), &compare_top_edges_downward); /* Subdivide the ccarray list roughly into text lines [LYB] */ /* Determine maximal top deviation */ maxtopchange = mdjvu_image_get_width(img) / 40; if (maxtopchange < 32) maxtopchange = 32; /* Loop until processing all ccs */ ccno = 0; while (ccno < char_blit_count) /* ccno will be increasing constantly */ { /* Gather first line approximation */ int32 sublist_top = bps[ccno].top; int32 sublist_bottom = bps[ccno].bottom; int32 nccno; /* nccno will be at least ccno + 1, * or otherwise we're hung. */ for (nccno = ccno; nccno < char_blit_count; nccno++) { int32 bottom; if (bps[nccno].top > sublist_bottom) break; if (bps[nccno].top > sublist_top + maxtopchange) break; bottom = bps[nccno].bottom; bottoms[nccno - ccno] = bottom; if (bottom > sublist_bottom) sublist_bottom = bottom; } /* If more than one candidate cc for the line */ if (nccno > ccno + 1) { /* Compute median bottom */ int32 bottom; qsort(bottoms, nccno - ccno, sizeof(int32), &compare_integers_reversed); bottom = bottoms[ (nccno - ccno - 1) / 2 ]; /* Compose final line */ for (nccno = ccno; nccno < char_blit_count; nccno++) if (bps[nccno].top > bottom) break; /* Sort final line */ qsort(bps + ccno, nccno - ccno, sizeof(BlitPassport), &compare_left_edges_rightward); } /* Next line */ ccno = nccno; } /* Permute the blits according to `bps' */ passport_of_blit = (int32 *) malloc(blit_count * sizeof(int32)); for (i = 0; i < blit_count; i++) passport_of_blit[i] = -1; for (i = 0; i < char_blit_count; i++) passport_of_blit[bps[i].original_index] = i; /* We'll maintain that bps[i].original_index points to the same blit */ for (i = 0; i < char_blit_count; i++) { int32 blit_to_put_here = bps[i].original_index; mdjvu_image_exchange_blits(img, blit_to_put_here, i); if (passport_of_blit[i] != -1) bps[passport_of_blit[i]].original_index = blit_to_put_here; passport_of_blit[blit_to_put_here] = passport_of_blit[i]; } free(passport_of_blit); free(bps); free(bottoms); }