diff options
26 files changed, 2008 insertions, 1981 deletions
diff --git a/converter/other/pamtosvg/curve.h b/converter/other/pamtosvg/curve.h index db3cc682..2f010d45 100644 --- a/converter/other/pamtosvg/curve.h +++ b/converter/other/pamtosvg/curve.h @@ -77,14 +77,16 @@ extern curve_type copy_most_of_curve (curve_type c); /* Free the memory C uses. */ extern void free_curve (curve_type c); +/* Like `append_pixel', for a point in real coordinates. */ +void +append_point(curve_type const curve, + float_coord const coord); + /* Append the point P to the end of C's list. */ void append_pixel(curve_type const c, pm_pixelcoord const p); -/* Like `append_pixel', for a point in real coordinates. */ -extern void append_point (curve_type c, float_coord p); - /* Write some or all, respectively, of the curve C in human-readable form to the log file, if logging is enabled. */ extern void log_curve (curve_type c, bool print_t); diff --git a/converter/other/pamtosvg/fit.c b/converter/other/pamtosvg/fit.c index bcda033f..2fa64500 100644 --- a/converter/other/pamtosvg/fit.c +++ b/converter/other/pamtosvg/fit.c @@ -54,21 +54,6 @@ typedef struct index_list #define INDEX_LIST_LENGTH(i_l) ((i_l).length) #define GET_LAST_INDEX(i_l) ((i_l).data[INDEX_LIST_LENGTH (i_l) - 1]) -static void append_index (index_list_type *, unsigned); -static void free_index_list (index_list_type *); -static index_list_type new_index_list (void); -static void remove_adjacent_corners (index_list_type *, unsigned, bool, - at_exception_type * exception); -static void filter (curve_type, fitting_opts_type *); -static void find_vectors - (unsigned, pixel_outline_type, vector_type *, vector_type *, unsigned); -static float find_error (curve_type, spline_type, unsigned *, - at_exception_type * exception); -static vector_type find_half_tangent (curve_type, bool start, unsigned *, unsigned); -static void find_tangent (curve_type, bool, bool, unsigned); -static void remove_knee_points (curve_type, bool); -static void set_initial_parameter_values (curve_type); -static float distance (float_coord, float_coord); static pm_pixelcoord @@ -86,6 +71,50 @@ real_to_int_coord(float_coord const real_coord) { } +/* Lists of array indices (well, that is what we use it for). */ + +static index_list_type +new_index_list (void) +{ + index_list_type index_list; + + index_list.data = NULL; + INDEX_LIST_LENGTH (index_list) = 0; + + return index_list; +} + +static void +free_index_list (index_list_type *index_list) +{ + if (INDEX_LIST_LENGTH (*index_list) > 0) + { + free (index_list->data); + index_list->data = NULL; + INDEX_LIST_LENGTH (*index_list) = 0; + } +} + +static void +append_index (index_list_type *list, unsigned new_index) +{ + INDEX_LIST_LENGTH (*list)++; + REALLOCARRAY_NOFAIL(list->data, INDEX_LIST_LENGTH(*list)); + list->data[INDEX_LIST_LENGTH (*list) - 1] = new_index; +} + + +/* Return the Euclidean distance between P1 and P2. */ + +static float +distance (float_coord p1, float_coord p2) +{ + float x = p1.x - p2.x, y = p1.y - p2.y, z = p1.z - p2.z; + return (float) sqrt (SQR(x) + SQR(y) + SQR(z)); +} + + + static void appendCorner(index_list_type * const cornerListP, unsigned int const pixelSeq, @@ -102,6 +131,45 @@ appendCorner(index_list_type * const cornerListP, static void +find_vectors(unsigned int const test_index, + pixel_outline_type const outline, + vector_type * const in, + vector_type * const out, + unsigned int const corner_surround) { +/*---------------------------------------------------------------------------- + Return the difference vectors coming in and going out of the outline + OUTLINE at the point whose index is TEST_INDEX. In Phoenix, + Schneider looks at a single point on either side of the point we're + considering. That works for him because his points are not touching. + But our points *are* touching, and so we have to look at + `corner_surround' points on either side, to get a better picture of + the outline's shape. +-----------------------------------------------------------------------------*/ + int i; + unsigned n_done; + pm_pixelcoord const candidate = O_COORDINATE(outline, test_index); + + in->dx = in->dy = in->dz = 0.0; + out->dx = out->dy = out->dz = 0.0; + + /* Add up the differences from p of the `corner_surround' points + before p. + */ + for (i = O_PREV(outline, test_index), n_done = 0; + n_done < corner_surround; + i = O_PREV(outline, i), ++n_done) + *in = Vadd(*in, IPsubtract(O_COORDINATE(outline, i), candidate)); + + /* And the points after p. */ + for (i = O_NEXT (outline, test_index), n_done = 0; + n_done < corner_surround; + i = O_NEXT(outline, i), ++n_done) + *out = Vadd(*out, IPsubtract(O_COORDINATE(outline, i), candidate)); +} + + + +static void lookAheadForBetterCorner(pixel_outline_type const outline, unsigned int const basePixelSeq, float const baseCornerAngle, @@ -210,6 +278,287 @@ establishCornerSearchLimits(pixel_outline_type const outline, static void +remove_adjacent_corners(index_list_type * const list, + unsigned int const last_index, + bool const remove_adj_corners, + at_exception_type * const exception) { +/*---------------------------------------------------------------------------- + Remove adjacent points from the index list LIST. We do this by first + sorting the list and then running through it. Since these lists are + quite short, a straight selection sort (e.g., p.139 of the Art of + Computer Programming, vol.3) is good enough. LAST_INDEX is the index + of the last pixel on the outline, i.e., the next one is the first + pixel. We need this for checking the adjacency of the last corner. + + We need to do this because the adjacent corners turn into + two-pixel-long curves, which can only be fit by straight lines. +-----------------------------------------------------------------------------*/ + unsigned int j; + unsigned int last; + index_list_type new_list = new_index_list (); + + for (j = INDEX_LIST_LENGTH (*list) - 1; j > 0; j--) + { + unsigned search; + unsigned temp; + /* Find maximal element below `j'. */ + unsigned max_index = j; + + for (search = 0; search < j; search++) + if (GET_INDEX (*list, search) > GET_INDEX (*list, max_index)) + max_index = search; + + if (max_index != j) + { + temp = GET_INDEX (*list, j); + GET_INDEX (*list, j) = GET_INDEX (*list, max_index); + GET_INDEX (*list, max_index) = temp; + + /* xx -- really have to sort? */ + LOG ("needed exchange"); + at_exception_warning(exception, "needed exchange"); + } + } + + /* The list is sorted. Now look for adjacent entries. Each time + through the loop we insert the current entry and, if appropriate, + the next entry. */ + for (j = 0; j < INDEX_LIST_LENGTH (*list) - 1; j++) + { + unsigned current = GET_INDEX (*list, j); + unsigned next = GET_INDEX (*list, j + 1); + + /* We should never have inserted the same element twice. */ + /* assert (current != next); */ + + if ((remove_adj_corners) && ((next == current + 1) || (next == current))) + j++; + + append_index (&new_list, current); + } + + /* Don't append the last element if it is 1) adjacent to the previous + one; or 2) adjacent to the very first one. */ + last = GET_LAST_INDEX (*list); + if (INDEX_LIST_LENGTH (new_list) == 0 + || !(last == GET_LAST_INDEX (new_list) + 1 + || (last == last_index && GET_INDEX (*list, 0) == 0))) + append_index (&new_list, last); + + free_index_list (list); + *list = new_list; +} + +/* A ``knee'' is a point which forms a ``right angle'' with its + predecessor and successor. See the documentation (the `Removing + knees' section) for an example and more details. + + The argument CLOCKWISE tells us which direction we're moving. (We + can't figure that information out from just the single segment with + which we are given to work.) + + We should never find two consecutive knees. + + Since the first and last points are corners (unless the curve is + cyclic), it doesn't make sense to remove those. */ + +/* This evaluates to true if the vector V is zero in one direction and + nonzero in the other. */ +#define ONLY_ONE_ZERO(v) \ + (((v).dx == 0.0 && (v).dy != 0.0) || ((v).dy == 0.0 && (v).dx != 0.0)) + +/* There are four possible cases for knees, one for each of the four + corners of a rectangle; and then the cases differ depending on which + direction we are going around the curve. The tests are listed here + in the order of upper left, upper right, lower right, lower left. + Perhaps there is some simple pattern to the + clockwise/counterclockwise differences, but I don't see one. */ +#define CLOCKWISE_KNEE(prev_delta, next_delta) \ + ((prev_delta.dx == -1.0 && next_delta.dy == 1.0) \ + || (prev_delta.dy == 1.0 && next_delta.dx == 1.0) \ + || (prev_delta.dx == 1.0 && next_delta.dy == -1.0) \ + || (prev_delta.dy == -1.0 && next_delta.dx == -1.0)) + +#define COUNTERCLOCKWISE_KNEE(prev_delta, next_delta) \ + ((prev_delta.dy == 1.0 && next_delta.dx == -1.0) \ + || (prev_delta.dx == 1.0 && next_delta.dy == 1.0) \ + || (prev_delta.dy == -1.0 && next_delta.dx == 1.0) \ + || (prev_delta.dx == -1.0 && next_delta.dy == -1.0)) + + + +static void +remove_knee_points(curve_type const curve, + bool const clockwise) { + + unsigned const offset = (CURVE_CYCLIC(curve) == true) ? 0 : 1; + curve_type const trimmed_curve = copy_most_of_curve(curve); + + pm_pixelcoord previous; + unsigned i; + + if (!CURVE_CYCLIC(curve)) + append_pixel(trimmed_curve, + real_to_int_coord(CURVE_POINT(curve, 0))); + + previous = real_to_int_coord(CURVE_POINT(curve, + CURVE_PREV(curve, offset))); + + for (i = offset; i < CURVE_LENGTH (curve) - offset; ++i) { + pm_pixelcoord const current = + real_to_int_coord(CURVE_POINT(curve, i)); + pm_pixelcoord const next = + real_to_int_coord(CURVE_POINT(curve, CURVE_NEXT(curve, i))); + vector_type const prev_delta = IPsubtract(previous, current); + vector_type const next_delta = IPsubtract(next, current); + + if (ONLY_ONE_ZERO(prev_delta) && ONLY_ONE_ZERO(next_delta) + && ((clockwise && CLOCKWISE_KNEE(prev_delta, next_delta)) + || (!clockwise + && COUNTERCLOCKWISE_KNEE(prev_delta, next_delta)))) + LOG2(" (%d,%d)", current.col, current.row); + else { + previous = current; + append_pixel(trimmed_curve, current); + } + } + + if (!CURVE_CYCLIC(curve)) + append_pixel(trimmed_curve, + real_to_int_coord(LAST_CURVE_POINT(curve))); + + if (CURVE_LENGTH(trimmed_curve) == CURVE_LENGTH(curve)) + LOG(" (none)"); + + LOG(".\n"); + + free_curve(curve); + *curve = *trimmed_curve; + free(trimmed_curve); /* free_curve? --- Masatake */ +} + + + +/* Smooth the curve by adding in neighboring points. Do this + `filter_iterations' times. But don't change the corners. */ + +static void +filter(curve_type const curve, + fitting_opts_type * const fitting_opts) { + + unsigned iteration, this_point; + unsigned offset = (CURVE_CYCLIC (curve) == true) ? 0 : 1; + float_coord prev_new_point; + + /* We must have at least three points---the previous one, the current + one, and the next one. But if we don't have at least five, we will + probably collapse the curve down onto a single point, which means + we won't be able to fit it with a spline. + */ + if (CURVE_LENGTH (curve) < 5) { + LOG1 ("Length is %u, not enough to filter.\n", CURVE_LENGTH (curve)); + return; + } + + prev_new_point.x = FLT_MAX; + prev_new_point.y = FLT_MAX; + prev_new_point.z = FLT_MAX; + + for (iteration = 0; + iteration < fitting_opts->filter_iterations; + ++iteration) { + curve_type newcurve = copy_most_of_curve (curve); + bool collapsed = false; + + /* Keep the first point on the curve. */ + if (offset) + append_point (newcurve, CURVE_POINT (curve, 0)); + + for (this_point = offset; + this_point < CURVE_LENGTH (curve) - offset; + ++this_point) { + vector_type in, out, sum; + float_coord new_point; + + /* Calculate the vectors in and out, computed by looking + at n points on either side of this_point. Experimental + it was found that 2 is optimal. + */ + + signed int prev, prevprev; /* have to be signed */ + unsigned int next, nextnext; + float_coord candidate = CURVE_POINT (curve, this_point); + + prev = CURVE_PREV (curve, this_point); + prevprev = CURVE_PREV (curve, prev); + next = CURVE_NEXT (curve, this_point); + nextnext = CURVE_NEXT (curve, next); + + /* Add up the differences from p of the `surround' points + before p. + */ + in.dx = in.dy = in.dz = 0.0; + + in = Vadd (in, Psubtract (CURVE_POINT (curve, prev), candidate)); + if (prevprev >= 0) + in = Vadd(in, + Psubtract(CURVE_POINT (curve, prevprev), candidate)); + + /* And the points after p. Don't use more points after p than we + ended up with before it. + */ + out.dx = out.dy = out.dz = 0.0; + + out = Vadd (out, Psubtract (CURVE_POINT (curve, next), candidate)); + if (nextnext < CURVE_LENGTH (curve)) + out = Vadd(out, + Psubtract(CURVE_POINT (curve, nextnext), + candidate)); + + /* Start with the old point. */ + new_point = candidate; + sum = Vadd (in, out); + /* We added 2*n+2 points, so we have to divide the sum by 2*n+2 */ + new_point.x += sum.dx / 6; + new_point.y += sum.dy / 6; + new_point.z += sum.dz / 6; + if (fabs (prev_new_point.x - new_point.x) < 0.3 + && fabs (prev_new_point.y - new_point.y) < 0.3 + && fabs (prev_new_point.z - new_point.z) < 0.3) { + collapsed = true; + break; + } + + + /* Put the newly computed point into a separate curve, so it + doesn't affect future computation (on this iteration). + */ + append_point (newcurve, prev_new_point = new_point); + } + + if (collapsed) + free_curve (newcurve); + else { + /* Just as with the first point, we have to keep the last + point. + */ + if (offset) + append_point (newcurve, LAST_CURVE_POINT (curve)); + + /* Set the original curve to the newly filtered one, and go + again. + */ + free_curve (curve); + *curve = *newcurve; + } + free (newcurve); + } + log_curve (curve, false); +} + + + +static void removeAdjacent(index_list_type * const cornerListP, pixel_outline_type const outline, fitting_opts_type * const fittingOptsP, @@ -951,6 +1300,210 @@ logSplineFit(spline_type const spline) { +static vector_type +find_half_tangent(curve_type const c, + bool const to_start_point, + unsigned int * const n_points, + unsigned int const tangent_surround) { +/*---------------------------------------------------------------------------- + Find the change in y and change in x for `tangent_surround' (a global) + points along CURVE. Increment N_POINTS by the number of points we + actually look at. +-----------------------------------------------------------------------------*/ + unsigned int p; + int factor = to_start_point ? 1 : -1; + unsigned tangent_index = to_start_point ? 0 : c->length - 1; + float_coord tangent_point = CURVE_POINT (c, tangent_index); + vector_type tangent = { 0.0, 0.0 }; + unsigned int surround; + + if ((surround = CURVE_LENGTH(c) / 2) > tangent_surround) + surround = tangent_surround; + + for (p = 1; p <= surround; ++p) { + int const this_index = p * factor + tangent_index; + float_coord this_point; + + if (this_index < 0 || this_index >= (int) c->length) + break; + + this_point = CURVE_POINT(c, p * factor + tangent_index); + + /* Perhaps we should weight the tangent from `this_point' by some + factor dependent on the distance from the tangent point. + */ + tangent = Vadd (tangent, + Vmult_scalar(Psubtract(this_point, tangent_point), + (float) factor)); + ++*n_points; + } + + return tangent; +} + + + +static void +find_tangent(curve_type const curve, + bool const to_start_point, + bool const cross_curve, + unsigned int const tangent_surround_arg) { +/*---------------------------------------------------------------------------- + Find an approximation to the tangent to an endpoint of CURVE (to the + first point if TO_START_POINT is true, else the last). If + CROSS_CURVE is true, consider points on the adjacent curve to CURVE. + + It is important to compute an accurate approximation, because the + control points that we eventually decide upon to fit the curve will + be placed on the half-lines defined by the tangents and + endpoints...and we never recompute the tangent after this. +-----------------------------------------------------------------------------*/ + vector_type ** curve_tangent; + vector_type tangent; + unsigned n_points; + + LOG1(" tangent to %s: ", (to_start_point == true) ? "start" : "end"); + + n_points = 0; /* initial value */ + + curve_tangent = to_start_point ? + &(CURVE_START_TANGENT(curve)) : &(CURVE_END_TANGENT(curve)); + + if (*curve_tangent == NULL) { + unsigned int tangent_surround; + + tangent_surround = tangent_surround_arg; /* initial value */ + MALLOCVAR_NOFAIL(*curve_tangent); + do { + tangent = find_half_tangent(curve, to_start_point, &n_points, + tangent_surround); + + if (cross_curve || CURVE_CYCLIC(curve)) { + curve_type const adjacent_curve = to_start_point ? + PREVIOUS_CURVE(curve) : NEXT_CURVE(curve); + vector_type const tangent2 = !to_start_point ? + find_half_tangent(adjacent_curve, true, &n_points, + tangent_surround) : + find_half_tangent(adjacent_curve, true, &n_points, + tangent_surround); + + LOG3("(adjacent curve half tangent (%.3f,%.3f,%.3f)) ", + tangent2.dx, tangent2.dy, tangent2.dz); + tangent = Vadd (tangent, tangent2); + } + --tangent_surround; + } while (tangent.dx == 0.0 && tangent.dy == 0.0); + + assert(n_points > 0); + **curve_tangent = Vmult_scalar (tangent, (float)(1.0 / n_points)); + if (CURVE_CYCLIC(curve) && CURVE_START_TANGENT(curve)) + *CURVE_START_TANGENT(curve) = **curve_tangent; + if (CURVE_CYCLIC(curve) && CURVE_END_TANGENT(curve)) + *CURVE_END_TANGENT(curve) = **curve_tangent; + } else + LOG("(already computed) "); + + LOG3("(%.3f,%.3f,%.3f).\n", (*curve_tangent)->dx, + (*curve_tangent)->dy, (*curve_tangent)->dz); +} + + + +static float +find_error(curve_type const curve, + spline_type const spline, + unsigned int * const worst_point, + at_exception_type * const exception) { +/*---------------------------------------------------------------------------- + When this routine is called, we have computed a spline representation + for the digitized curve. The question is, how good is it? If the + fit is very good indeed, we might have an error of zero on each + point, and then WORST_POINT becomes irrelevant. But normally, we + return the error at the worst point, and the index of that point in + WORST_POINT. The error computation itself is the Euclidean distance + from the original curve CURVE to the fitted spline SPLINE. +-----------------------------------------------------------------------------*/ + unsigned int this_point; + float total_error; + float worst_error; + + total_error = 0.0; /* initial value */ + worst_error = FLT_MIN; /* initial value */ + + *worst_point = CURVE_LENGTH(curve) + 1; /* A sentinel value. */ + + for (this_point = 0; this_point < CURVE_LENGTH(curve); ++this_point) { + float_coord const curve_point = CURVE_POINT(curve, this_point); + float const t = CURVE_T(curve, this_point); + float_coord const spline_point = evaluate_spline(spline, t); + float const this_error = distance(curve_point, spline_point); + if (this_error >= worst_error) { + *worst_point = this_point; + worst_error = this_error; + } + total_error += this_error; + } + + if (*worst_point == CURVE_LENGTH(curve) + 1) { + /* Didn't have any ``worst point''; the error should be zero. */ + if (epsilon_equal(total_error, 0.0)) + LOG (" Every point fit perfectly.\n"); + else { + LOG("No worst point found; something is wrong"); + at_exception_warning(exception, + "No worst point found; something is wrong"); + } + } else { + if (epsilon_equal(total_error, 0.0)) + LOG (" Every point fit perfectly.\n"); + else { + LOG5(" Worst error (at (%.3f,%.3f,%.3f), point #%u) was %.3f.\n", + CURVE_POINT(curve, *worst_point).x, + CURVE_POINT(curve, *worst_point).y, + CURVE_POINT(curve, *worst_point).z, + *worst_point, worst_error); + LOG1(" Total error was %.3f.\n", total_error); + LOG2(" Average error (over %u points) was %.3f.\n", + CURVE_LENGTH(curve), total_error / CURVE_LENGTH(curve)); + } + } + return worst_error; +} + + + +static void +set_initial_parameter_values(curve_type const curve) { +/*---------------------------------------------------------------------------- + Find reasonable values for t for each point on CURVE. The method is + called chord-length parameterization, which is described in Plass & + Stone. The basic idea is just to use the distance from one point to + the next as the t value, normalized to produce values that increase + from zero for the first point to one for the last point. +-----------------------------------------------------------------------------*/ + unsigned int p; + + LOG("\nAssigning initial t values:\n "); + + CURVE_T(curve, 0) = 0.0; + + for (p = 1; p < CURVE_LENGTH (curve); ++p) { + float_coord const point = CURVE_POINT(curve, p); + float_coord const previous_p = CURVE_POINT(curve, p - 1); + float const d = distance (point, previous_p); + CURVE_T (curve, p) = CURVE_T (curve, p - 1) + d; + } + + assert(LAST_CURVE_T (curve) != 0.0); + + for (p = 1; p < CURVE_LENGTH(curve); ++p) + CURVE_T(curve, p) = CURVE_T(curve, p) / LAST_CURVE_T(curve); + + log_entire_curve(curve); +} + + + static spline_list_type * fit_with_least_squares(curve_type const curve, const fitting_opts_type * const fitting_opts, @@ -1377,547 +1930,3 @@ fit_outlines_to_splines(pixel_outline_list_type const pixelOutlineList, - -static void -find_vectors(unsigned int const test_index, - pixel_outline_type const outline, - vector_type * const in, - vector_type * const out, - unsigned int const corner_surround) { -/*---------------------------------------------------------------------------- - Return the difference vectors coming in and going out of the outline - OUTLINE at the point whose index is TEST_INDEX. In Phoenix, - Schneider looks at a single point on either side of the point we're - considering. That works for him because his points are not touching. - But our points *are* touching, and so we have to look at - `corner_surround' points on either side, to get a better picture of - the outline's shape. ------------------------------------------------------------------------------*/ - int i; - unsigned n_done; - pm_pixelcoord const candidate = O_COORDINATE(outline, test_index); - - in->dx = in->dy = in->dz = 0.0; - out->dx = out->dy = out->dz = 0.0; - - /* Add up the differences from p of the `corner_surround' points - before p. - */ - for (i = O_PREV(outline, test_index), n_done = 0; - n_done < corner_surround; - i = O_PREV(outline, i), ++n_done) - *in = Vadd(*in, IPsubtract(O_COORDINATE(outline, i), candidate)); - - /* And the points after p. */ - for (i = O_NEXT (outline, test_index), n_done = 0; - n_done < corner_surround; - i = O_NEXT(outline, i), ++n_done) - *out = Vadd(*out, IPsubtract(O_COORDINATE(outline, i), candidate)); -} - - - -/* Remove adjacent points from the index list LIST. We do this by first - sorting the list and then running through it. Since these lists are - quite short, a straight selection sort (e.g., p.139 of the Art of - Computer Programming, vol.3) is good enough. LAST_INDEX is the index - of the last pixel on the outline, i.e., the next one is the first - pixel. We need this for checking the adjacency of the last corner. - - We need to do this because the adjacent corners turn into - two-pixel-long curves, which can only be fit by straight lines. */ - -static void -remove_adjacent_corners (index_list_type *list, unsigned last_index, - bool remove_adj_corners, - at_exception_type * exception) - -{ - unsigned j; - unsigned last; - index_list_type new_list = new_index_list (); - - for (j = INDEX_LIST_LENGTH (*list) - 1; j > 0; j--) - { - unsigned search; - unsigned temp; - /* Find maximal element below `j'. */ - unsigned max_index = j; - - for (search = 0; search < j; search++) - if (GET_INDEX (*list, search) > GET_INDEX (*list, max_index)) - max_index = search; - - if (max_index != j) - { - temp = GET_INDEX (*list, j); - GET_INDEX (*list, j) = GET_INDEX (*list, max_index); - GET_INDEX (*list, max_index) = temp; - - /* xx -- really have to sort? */ - LOG ("needed exchange"); - at_exception_warning(exception, "needed exchange"); - } - } - - /* The list is sorted. Now look for adjacent entries. Each time - through the loop we insert the current entry and, if appropriate, - the next entry. */ - for (j = 0; j < INDEX_LIST_LENGTH (*list) - 1; j++) - { - unsigned current = GET_INDEX (*list, j); - unsigned next = GET_INDEX (*list, j + 1); - - /* We should never have inserted the same element twice. */ - /* assert (current != next); */ - - if ((remove_adj_corners) && ((next == current + 1) || (next == current))) - j++; - - append_index (&new_list, current); - } - - /* Don't append the last element if it is 1) adjacent to the previous - one; or 2) adjacent to the very first one. */ - last = GET_LAST_INDEX (*list); - if (INDEX_LIST_LENGTH (new_list) == 0 - || !(last == GET_LAST_INDEX (new_list) + 1 - || (last == last_index && GET_INDEX (*list, 0) == 0))) - append_index (&new_list, last); - - free_index_list (list); - *list = new_list; -} - -/* A ``knee'' is a point which forms a ``right angle'' with its - predecessor and successor. See the documentation (the `Removing - knees' section) for an example and more details. - - The argument CLOCKWISE tells us which direction we're moving. (We - can't figure that information out from just the single segment with - which we are given to work.) - - We should never find two consecutive knees. - - Since the first and last points are corners (unless the curve is - cyclic), it doesn't make sense to remove those. */ - -/* This evaluates to true if the vector V is zero in one direction and - nonzero in the other. */ -#define ONLY_ONE_ZERO(v) \ - (((v).dx == 0.0 && (v).dy != 0.0) || ((v).dy == 0.0 && (v).dx != 0.0)) - -/* There are four possible cases for knees, one for each of the four - corners of a rectangle; and then the cases differ depending on which - direction we are going around the curve. The tests are listed here - in the order of upper left, upper right, lower right, lower left. - Perhaps there is some simple pattern to the - clockwise/counterclockwise differences, but I don't see one. */ -#define CLOCKWISE_KNEE(prev_delta, next_delta) \ - ((prev_delta.dx == -1.0 && next_delta.dy == 1.0) \ - || (prev_delta.dy == 1.0 && next_delta.dx == 1.0) \ - || (prev_delta.dx == 1.0 && next_delta.dy == -1.0) \ - || (prev_delta.dy == -1.0 && next_delta.dx == -1.0)) - -#define COUNTERCLOCKWISE_KNEE(prev_delta, next_delta) \ - ((prev_delta.dy == 1.0 && next_delta.dx == -1.0) \ - || (prev_delta.dx == 1.0 && next_delta.dy == 1.0) \ - || (prev_delta.dy == -1.0 && next_delta.dx == 1.0) \ - || (prev_delta.dx == -1.0 && next_delta.dy == -1.0)) - - - -static void -remove_knee_points(curve_type const curve, - bool const clockwise) { - - unsigned const offset = (CURVE_CYCLIC(curve) == true) ? 0 : 1; - curve_type const trimmed_curve = copy_most_of_curve(curve); - - pm_pixelcoord previous; - unsigned i; - - if (!CURVE_CYCLIC(curve)) - append_pixel(trimmed_curve, - real_to_int_coord(CURVE_POINT(curve, 0))); - - previous = real_to_int_coord(CURVE_POINT(curve, - CURVE_PREV(curve, offset))); - - for (i = offset; i < CURVE_LENGTH (curve) - offset; ++i) { - pm_pixelcoord const current = - real_to_int_coord(CURVE_POINT(curve, i)); - pm_pixelcoord const next = - real_to_int_coord(CURVE_POINT(curve, CURVE_NEXT(curve, i))); - vector_type const prev_delta = IPsubtract(previous, current); - vector_type const next_delta = IPsubtract(next, current); - - if (ONLY_ONE_ZERO(prev_delta) && ONLY_ONE_ZERO(next_delta) - && ((clockwise && CLOCKWISE_KNEE(prev_delta, next_delta)) - || (!clockwise - && COUNTERCLOCKWISE_KNEE(prev_delta, next_delta)))) - LOG2(" (%d,%d)", current.col, current.row); - else { - previous = current; - append_pixel(trimmed_curve, current); - } - } - - if (!CURVE_CYCLIC(curve)) - append_pixel(trimmed_curve, - real_to_int_coord(LAST_CURVE_POINT(curve))); - - if (CURVE_LENGTH(trimmed_curve) == CURVE_LENGTH(curve)) - LOG(" (none)"); - - LOG(".\n"); - - free_curve(curve); - *curve = *trimmed_curve; - free(trimmed_curve); /* free_curve? --- Masatake */ -} - - - -/* Smooth the curve by adding in neighboring points. Do this - `filter_iterations' times. But don't change the corners. */ - -static void -filter (curve_type curve, fitting_opts_type *fitting_opts) -{ - unsigned iteration, this_point; - unsigned offset = (CURVE_CYCLIC (curve) == true) ? 0 : 1; - float_coord prev_new_point; - - /* We must have at least three points---the previous one, the current - one, and the next one. But if we don't have at least five, we will - probably collapse the curve down onto a single point, which means - we won't be able to fit it with a spline. */ - if (CURVE_LENGTH (curve) < 5) - { - LOG1 ("Length is %u, not enough to filter.\n", CURVE_LENGTH (curve)); - return; - } - - prev_new_point.x = FLT_MAX; - prev_new_point.y = FLT_MAX; - prev_new_point.z = FLT_MAX; - - for (iteration = 0; iteration < fitting_opts->filter_iterations; - iteration++) - { - curve_type newcurve = copy_most_of_curve (curve); - bool collapsed = false; - - /* Keep the first point on the curve. */ - if (offset) - append_point (newcurve, CURVE_POINT (curve, 0)); - - for (this_point = offset; this_point < CURVE_LENGTH (curve) - offset; - this_point++) - { - vector_type in, out, sum; - float_coord new_point; - - /* Calculate the vectors in and out, computed by looking at n points - on either side of this_point. Experimental it was found that 2 is - optimal. */ - - signed int prev, prevprev; /* have to be signed */ - unsigned int next, nextnext; - float_coord candidate = CURVE_POINT (curve, this_point); - - prev = CURVE_PREV (curve, this_point); - prevprev = CURVE_PREV (curve, prev); - next = CURVE_NEXT (curve, this_point); - nextnext = CURVE_NEXT (curve, next); - - /* Add up the differences from p of the `surround' points - before p. */ - in.dx = in.dy = in.dz = 0.0; - - in = Vadd (in, Psubtract (CURVE_POINT (curve, prev), candidate)); - if (prevprev >= 0) - in = Vadd (in, Psubtract (CURVE_POINT (curve, prevprev), candidate)); - - /* And the points after p. Don't use more points after p than we - ended up with before it. */ - out.dx = out.dy = out.dz = 0.0; - - out = Vadd (out, Psubtract (CURVE_POINT (curve, next), candidate)); - if (nextnext < CURVE_LENGTH (curve)) - out = Vadd (out, Psubtract (CURVE_POINT (curve, nextnext), candidate)); - - /* Start with the old point. */ - new_point = candidate; - sum = Vadd (in, out); - /* We added 2*n+2 points, so we have to divide the sum by 2*n+2 */ - new_point.x += sum.dx / 6; - new_point.y += sum.dy / 6; - new_point.z += sum.dz / 6; - if (fabs (prev_new_point.x - new_point.x) < 0.3 - && fabs (prev_new_point.y - new_point.y) < 0.3 - && fabs (prev_new_point.z - new_point.z) < 0.3) - { - collapsed = true; - break; - } - - - /* Put the newly computed point into a separate curve, so it - doesn't affect future computation (on this iteration). */ - append_point (newcurve, prev_new_point = new_point); - } - - if (collapsed) - free_curve (newcurve); - else - { - /* Just as with the first point, we have to keep the last point. */ - if (offset) - append_point (newcurve, LAST_CURVE_POINT (curve)); - - /* Set the original curve to the newly filtered one, and go again. */ - free_curve (curve); - *curve = *newcurve; - } - free (newcurve); - } - - log_curve (curve, false); -} - - - -/* Find reasonable values for t for each point on CURVE. The method is - called chord-length parameterization, which is described in Plass & - Stone. The basic idea is just to use the distance from one point to - the next as the t value, normalized to produce values that increase - from zero for the first point to one for the last point. */ - -static void -set_initial_parameter_values (curve_type curve) -{ - unsigned p; - - LOG ("\nAssigning initial t values:\n "); - - CURVE_T (curve, 0) = 0.0; - - for (p = 1; p < CURVE_LENGTH (curve); p++) - { - float_coord point = CURVE_POINT (curve, p), - previous_p = CURVE_POINT (curve, p - 1); - float d = distance (point, previous_p); - CURVE_T (curve, p) = CURVE_T (curve, p - 1) + d; - } - - assert (LAST_CURVE_T (curve) != 0.0); - - for (p = 1; p < CURVE_LENGTH (curve); p++) - CURVE_T (curve, p) = CURVE_T (curve, p) / LAST_CURVE_T (curve); - - log_entire_curve (curve); -} - -/* Find an approximation to the tangent to an endpoint of CURVE (to the - first point if TO_START_POINT is true, else the last). If - CROSS_CURVE is true, consider points on the adjacent curve to CURVE. - - It is important to compute an accurate approximation, because the - control points that we eventually decide upon to fit the curve will - be placed on the half-lines defined by the tangents and - endpoints...and we never recompute the tangent after this. */ - -static void -find_tangent (curve_type curve, bool to_start_point, bool cross_curve, - unsigned tangent_surround) -{ - vector_type tangent; - vector_type **curve_tangent = (to_start_point == true) ? &(CURVE_START_TANGENT (curve)) - : &(CURVE_END_TANGENT (curve)); - unsigned n_points = 0; - - LOG1 (" tangent to %s: ", (to_start_point == true) ? "start" : "end"); - - if (*curve_tangent == NULL) - { - MALLOCVAR_NOFAIL(*curve_tangent); - do - { - tangent = find_half_tangent (curve, to_start_point, &n_points, - tangent_surround); - - if ((cross_curve == true) || (CURVE_CYCLIC (curve) == true)) - { - curve_type adjacent_curve - = (to_start_point == true) ? PREVIOUS_CURVE (curve) : NEXT_CURVE (curve); - vector_type tangent2 - = (to_start_point == false) ? find_half_tangent (adjacent_curve, true, &n_points, - tangent_surround) : find_half_tangent (adjacent_curve, true, &n_points, - tangent_surround); - - LOG3 ("(adjacent curve half tangent (%.3f,%.3f,%.3f)) ", - tangent2.dx, tangent2.dy, tangent2.dz); - tangent = Vadd (tangent, tangent2); - } - tangent_surround--; - - } - while (tangent.dx == 0.0 && tangent.dy == 0.0); - - assert (n_points > 0); - **curve_tangent = Vmult_scalar (tangent, (float)(1.0 / n_points)); - if ((CURVE_CYCLIC (curve) == true) && CURVE_START_TANGENT (curve)) - *CURVE_START_TANGENT (curve) = **curve_tangent; - if ((CURVE_CYCLIC (curve) == true) && CURVE_END_TANGENT (curve)) - *CURVE_END_TANGENT (curve) = **curve_tangent; - } - else - LOG ("(already computed) "); - - LOG3 ("(%.3f,%.3f,%.3f).\n", (*curve_tangent)->dx, (*curve_tangent)->dy, (*curve_tangent)->dz); -} - -/* Find the change in y and change in x for `tangent_surround' (a global) - points along CURVE. Increment N_POINTS by the number of points we - actually look at. */ - -static vector_type -find_half_tangent (curve_type c, bool to_start_point, unsigned *n_points, - unsigned tangent_surround) -{ - unsigned p; - int factor = to_start_point ? 1 : -1; - unsigned tangent_index = to_start_point ? 0 : c->length - 1; - float_coord tangent_point = CURVE_POINT (c, tangent_index); - vector_type tangent = { 0.0, 0.0 }; - unsigned int surround; - - if ((surround = CURVE_LENGTH (c) / 2) > tangent_surround) - surround = tangent_surround; - - for (p = 1; p <= surround; p++) - { - int this_index = p * factor + tangent_index; - float_coord this_point; - - if (this_index < 0 || this_index >= (int) c->length) - break; - - this_point = CURVE_POINT (c, p * factor + tangent_index); - - /* Perhaps we should weight the tangent from `this_point' by some - factor dependent on the distance from the tangent point. */ - tangent = Vadd (tangent, - Vmult_scalar (Psubtract (this_point, tangent_point), - (float) factor)); - (*n_points)++; - } - - return tangent; -} - -/* When this routine is called, we have computed a spline representation - for the digitized curve. The question is, how good is it? If the - fit is very good indeed, we might have an error of zero on each - point, and then WORST_POINT becomes irrelevant. But normally, we - return the error at the worst point, and the index of that point in - WORST_POINT. The error computation itself is the Euclidean distance - from the original curve CURVE to the fitted spline SPLINE. */ - -static float -find_error (curve_type curve, spline_type spline, unsigned *worst_point, - at_exception_type * exception) -{ - unsigned this_point; - float total_error = 0.0; - float worst_error = FLT_MIN; - - *worst_point = CURVE_LENGTH (curve) + 1; /* A sentinel value. */ - - for (this_point = 0; this_point < CURVE_LENGTH (curve); this_point++) - { - float_coord curve_point = CURVE_POINT (curve, this_point); - float t = CURVE_T (curve, this_point); - float_coord spline_point = evaluate_spline (spline, t); - float this_error = distance (curve_point, spline_point); - if (this_error >= worst_error) - { - *worst_point = this_point; - worst_error = this_error; - } - total_error += this_error; - } - - if (*worst_point == CURVE_LENGTH (curve) + 1) - { /* Didn't have any ``worst point''; the error should be zero. */ - if (epsilon_equal (total_error, 0.0)) - LOG (" Every point fit perfectly.\n"); - else - { - LOG("No worst point found; something is wrong"); - at_exception_warning(exception, "No worst point found; something is wrong"); - } - } - else - { - if (epsilon_equal (total_error, 0.0)) - LOG (" Every point fit perfectly.\n"); - else - { - LOG5 (" Worst error (at (%.3f,%.3f,%.3f), point #%u) was %.3f.\n", - CURVE_POINT (curve, *worst_point).x, - CURVE_POINT (curve, *worst_point).y, - CURVE_POINT (curve, *worst_point).z, *worst_point, worst_error); - LOG1 (" Total error was %.3f.\n", total_error); - LOG2 (" Average error (over %u points) was %.3f.\n", - CURVE_LENGTH (curve), total_error / CURVE_LENGTH (curve)); - } - } - - return worst_error; -} - - -/* Lists of array indices (well, that is what we use it for). */ - -static index_list_type -new_index_list (void) -{ - index_list_type index_list; - - index_list.data = NULL; - INDEX_LIST_LENGTH (index_list) = 0; - - return index_list; -} - -static void -free_index_list (index_list_type *index_list) -{ - if (INDEX_LIST_LENGTH (*index_list) > 0) - { - free (index_list->data); - index_list->data = NULL; - INDEX_LIST_LENGTH (*index_list) = 0; - } -} - -static void -append_index (index_list_type *list, unsigned new_index) -{ - INDEX_LIST_LENGTH (*list)++; - REALLOCARRAY_NOFAIL(list->data, INDEX_LIST_LENGTH(*list)); - list->data[INDEX_LIST_LENGTH (*list) - 1] = new_index; -} - - -/* Return the Euclidean distance between P1 and P2. */ - -static float -distance (float_coord p1, float_coord p2) -{ - float x = p1.x - p2.x, y = p1.y - p2.y, z = p1.z - p2.z; - return (float) sqrt (SQR(x) + SQR(y) + SQR(z)); -} diff --git a/converter/other/pnmtojpeg.c b/converter/other/pnmtojpeg.c index a0262331..5a4c5511 100644 --- a/converter/other/pnmtojpeg.c +++ b/converter/other/pnmtojpeg.c @@ -330,23 +330,6 @@ parseCommandLine(const int argc, char ** argv, } -static void -compute_rescaling_array(JSAMPLE ** const rescale_p, const pixval maxval, - const struct jpeg_compress_struct cinfo); -static void -convert_scanlines(struct jpeg_compress_struct *cinfo_p, FILE *input_file, - const pixval maxval, const int input_fmt, - JSAMPLE xlate_table[]); - -static boolean read_quant_tables (j_compress_ptr cinfo, char * filename, - int scale_factor, boolean force_baseline); - -static boolean read_scan_script (j_compress_ptr cinfo, char * filename); - -static boolean set_quant_slots (j_compress_ptr cinfo, char *arg); - -static boolean set_sample_factors (j_compress_ptr cinfo, char *arg); - static void report_compressor(const struct jpeg_compress_struct cinfo) { @@ -423,6 +406,349 @@ setup_jpeg_density(struct jpeg_compress_struct * const cinfoP, +/*---------------------------------------------------------------------------- + The functions below here are essentially the file rdswitch.c from + the JPEG library. They perform the functions specifed by the following + pnmtojpeg options: + + -qtables file Read quantization tables from text file + -scans file Read scan script from text file + -qslots N[,N,...] Set component quantization table selectors + -sample HxV[,HxV,...] Set component sampling factors +-----------------------------------------------------------------------------*/ + +static int +text_getc (FILE * file) +/* Read next char, skipping over any comments (# to end of line) */ +/* A comment/newline sequence is returned as a newline */ +{ + register int ch; + + ch = getc(file); + if (ch == '#') { + do { + ch = getc(file); + } while (ch != '\n' && ch != EOF); + } + return ch; +} + + +static boolean +read_text_integer (FILE * file, long * result, int * termchar) +/* Read an unsigned decimal integer from a file, store it in result */ +/* Reads one trailing character after the integer; returns it in termchar */ +{ + register int ch; + register long val; + + /* Skip any leading whitespace, detect EOF */ + do { + ch = text_getc(file); + if (ch == EOF) { + *termchar = ch; + return FALSE; + } + } while (isspace(ch)); + + if (! isdigit(ch)) { + *termchar = ch; + return FALSE; + } + + val = ch - '0'; + while ((ch = text_getc(file)) != EOF) { + if (! isdigit(ch)) + break; + val *= 10; + val += ch - '0'; + } + *result = val; + *termchar = ch; + return TRUE; +} + + +static boolean +read_scan_integer (FILE * file, long * result, int * termchar) +/* Variant of read_text_integer that always looks for a non-space termchar; + * this simplifies parsing of punctuation in scan scripts. + */ +{ + register int ch; + + if (! read_text_integer(file, result, termchar)) + return FALSE; + ch = *termchar; + while (ch != EOF && isspace(ch)) + ch = text_getc(file); + if (isdigit(ch)) { /* oops, put it back */ + if (ungetc(ch, file) == EOF) + return FALSE; + ch = ' '; + } else { + /* Any separators other than ';' and ':' are ignored; + * this allows user to insert commas, etc, if desired. + */ + if (ch != EOF && ch != ';' && ch != ':') + ch = ' '; + } + *termchar = ch; + return TRUE; +} + + + +static boolean +read_scan_script(j_compress_ptr const cinfo, + const char * const filename) { +/*---------------------------------------------------------------------------- + Read a scan script from the specified text file. + Each entry in the file defines one scan to be emitted. + Entries are separated by semicolons ';'. + An entry contains one to four component indexes, + optionally followed by a colon ':' and four progressive-JPEG parameters. + The component indexes denote which component(s) are to be transmitted + in the current scan. The first component has index 0. + Sequential JPEG is used if the progressive-JPEG parameters are omitted. + The file is free format text: any whitespace may appear between numbers + and the ':' and ';' punctuation marks. Also, other punctuation (such + as commas or dashes) can be placed between numbers if desired. + Comments preceded by '#' may be included in the file. + Note: we do very little validity checking here; + jcmaster.c will validate the script parameters. +-----------------------------------------------------------------------------*/ + FILE * fp; + unsigned int nscans; + unsigned int ncomps; + int termchar; + long val; +#define MAX_SCANS 100 /* quite arbitrary limit */ + jpeg_scan_info scans[MAX_SCANS]; + + fp = fopen(filename, "r"); + if (fp == NULL) { + pm_message("Can't open scan definition file %s", filename); + return FALSE; + } + nscans = 0; + + while (read_scan_integer(fp, &val, &termchar)) { + ++nscans; /* We got another scan */ + if (nscans > MAX_SCANS) { + pm_message("Too many scans defined in file %s", filename); + fclose(fp); + return FALSE; + } + scans[nscans-1].component_index[0] = (int) val; + ncomps = 1; + while (termchar == ' ') { + if (ncomps >= MAX_COMPS_IN_SCAN) { + pm_message("Too many components in one scan in file %s", + filename); + fclose(fp); + return FALSE; + } + if (! read_scan_integer(fp, &val, &termchar)) + goto bogus; + scans[nscans-1].component_index[ncomps] = (int) val; + ++ncomps; + } + scans[nscans-1].comps_in_scan = ncomps; + if (termchar == ':') { + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scans[nscans-1].Ss = (int) val; + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scans[nscans-1].Se = (int) val; + if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') + goto bogus; + scans[nscans-1].Ah = (int) val; + if (! read_scan_integer(fp, &val, &termchar)) + goto bogus; + scans[nscans-1].Al = (int) val; + } else { + /* set non-progressive parameters */ + scans[nscans-1].Ss = 0; + scans[nscans-1].Se = DCTSIZE2-1; + scans[nscans-1].Ah = 0; + scans[nscans-1].Al = 0; + } + if (termchar != ';' && termchar != EOF) { + bogus: + pm_message("Invalid scan entry format in file %s", filename); + fclose(fp); + return FALSE; + } + } + + if (termchar != EOF) { + pm_message("Non-numeric data in file %s", filename); + fclose(fp); + return FALSE; + } + + if (nscans > 0) { + /* Stash completed scan list in cinfo structure. NOTE: in + this program, JPOOL_IMAGE is the right lifetime for this + data, but if you want to compress multiple images you'd + want JPOOL_PERMANENT. + */ + const unsigned int scan_info_size = nscans * sizeof(jpeg_scan_info); + jpeg_scan_info * const scan_info = + (jpeg_scan_info *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + scan_info_size); + memcpy(scan_info, scans, scan_info_size); + cinfo->scan_info = scan_info; + cinfo->num_scans = nscans; + } + + fclose(fp); + return TRUE; +} + + + +static boolean +read_quant_tables (j_compress_ptr cinfo, char * filename, + int scale_factor, boolean force_baseline) +/* Read a set of quantization tables from the specified file. + * The file is plain ASCII text: decimal numbers with whitespace between. + * Comments preceded by '#' may be included in the file. + * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values. + * The tables are implicitly numbered 0,1,etc. + * NOTE: does not affect the qslots mapping, which will default to selecting + * table 0 for luminance (or primary) components, 1 for chrominance components. + * You must use -qslots if you want a different component->table mapping. + */ +{ + FILE * fp; + int tblno, i, termchar; + long val; + unsigned int table[DCTSIZE2]; + + if ((fp = fopen(filename, "rb")) == NULL) { + pm_message("Can't open table file %s", filename); + return FALSE; + } + tblno = 0; + + while (read_text_integer(fp, &val, &termchar)) { + /* read 1st element of table */ + if (tblno >= NUM_QUANT_TBLS) { + pm_message("Too many tables in file %s", filename); + fclose(fp); + return FALSE; + } + table[0] = (unsigned int) val; + for (i = 1; i < DCTSIZE2; i++) { + if (! read_text_integer(fp, &val, &termchar)) { + pm_message("Invalid table data in file %s", filename); + fclose(fp); + return FALSE; + } + table[i] = (unsigned int) val; + } + jpeg_add_quant_table(cinfo, tblno, table, scale_factor, + force_baseline); + tblno++; + } + + if (termchar != EOF) { + pm_message("Non-numeric data in file %s", filename); + fclose(fp); + return FALSE; + } + + fclose(fp); + return TRUE; +} + + + +static boolean +set_quant_slots (j_compress_ptr cinfo, char *arg) +/* Process a quantization-table-selectors parameter string, of the form + * N[,N,...] + * If there are more components than parameters, the last value is replicated. + */ +{ + int val = 0; /* default table # */ + int ci; + char ch; + + for (ci = 0; ci < MAX_COMPONENTS; ci++) { + if (*arg) { + ch = ','; /* if not set by sscanf, will be ',' */ + if (sscanf(arg, "%d%c", &val, &ch) < 1) + return FALSE; + if (ch != ',') /* syntax check */ + return FALSE; + if (val < 0 || val >= NUM_QUANT_TBLS) { + pm_message("Invalid quantization table number: %d. " + "JPEG quantization tables are numbered 0..%d", + val, NUM_QUANT_TBLS - 1); + return FALSE; + } + cinfo->comp_info[ci].quant_tbl_no = val; + while (*arg && *arg++ != ',') + /* advance to next segment of arg string */ + ; + } else { + /* reached end of parameter, set remaining components to last tbl*/ + cinfo->comp_info[ci].quant_tbl_no = val; + } + } + return TRUE; +} + + +static boolean +set_sample_factors (j_compress_ptr cinfo, char *arg) +/* Process a sample-factors parameter string, of the form + * HxV[,HxV,...] + * If there are more components than parameters, "1x1" is assumed for the rest. + */ +{ + int ci, val1, val2; + char ch1, ch2; + + for (ci = 0; ci < MAX_COMPONENTS; ci++) { + if (*arg) { + ch2 = ','; /* if not set by sscanf, will be ',' */ + if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3) + return FALSE; + if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */ + return FALSE; + if (val1 <= 0 || val1 > 4) { + pm_message("Invalid sampling factor: %d. " + "JPEG sampling factors must be 1..4", val1); + return FALSE; + } + if (val2 <= 0 || val2 > 4) { + pm_message("Invalid sampling factor: %d. " + "JPEG sampling factors must be 1..4", val2); + return FALSE; + } + cinfo->comp_info[ci].h_samp_factor = val1; + cinfo->comp_info[ci].v_samp_factor = val2; + while (*arg && *arg++ != ',') + /* advance to next segment of arg string */ + ; + } else { + /* reached end of parameter, set remaining components + to 1x1 sampling */ + cinfo->comp_info[ci].h_samp_factor = 1; + cinfo->comp_info[ci].v_samp_factor = 1; + } + } + return TRUE; +} + + + static void setup_jpeg(struct jpeg_compress_struct * const cinfoP, struct jpeg_error_mgr * const jerrP, @@ -692,348 +1018,16 @@ convert_scanlines(struct jpeg_compress_struct * const cinfo_p, } -/*---------------------------------------------------------------------------- - The functions below here are essentially the file rdswitch.c from - the JPEG library. They perform the functions specifed by the following - pnmtojpeg options: - - -qtables file Read quantization tables from text file - -scans file Read scan script from text file - -qslots N[,N,...] Set component quantization table selectors - -sample HxV[,HxV,...] Set component sampling factors ------------------------------------------------------------------------------*/ - -static int -text_getc (FILE * file) -/* Read next char, skipping over any comments (# to end of line) */ -/* A comment/newline sequence is returned as a newline */ -{ - register int ch; - - ch = getc(file); - if (ch == '#') { - do { - ch = getc(file); - } while (ch != '\n' && ch != EOF); - } - return ch; -} - - -static boolean -read_text_integer (FILE * file, long * result, int * termchar) -/* Read an unsigned decimal integer from a file, store it in result */ -/* Reads one trailing character after the integer; returns it in termchar */ -{ - register int ch; - register long val; - - /* Skip any leading whitespace, detect EOF */ - do { - ch = text_getc(file); - if (ch == EOF) { - *termchar = ch; - return FALSE; - } - } while (isspace(ch)); - - if (! isdigit(ch)) { - *termchar = ch; - return FALSE; - } - - val = ch - '0'; - while ((ch = text_getc(file)) != EOF) { - if (! isdigit(ch)) - break; - val *= 10; - val += ch - '0'; - } - *result = val; - *termchar = ch; - return TRUE; -} - - -static boolean -read_quant_tables (j_compress_ptr cinfo, char * filename, - int scale_factor, boolean force_baseline) -/* Read a set of quantization tables from the specified file. - * The file is plain ASCII text: decimal numbers with whitespace between. - * Comments preceded by '#' may be included in the file. - * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values. - * The tables are implicitly numbered 0,1,etc. - * NOTE: does not affect the qslots mapping, which will default to selecting - * table 0 for luminance (or primary) components, 1 for chrominance components. - * You must use -qslots if you want a different component->table mapping. - */ -{ - FILE * fp; - int tblno, i, termchar; - long val; - unsigned int table[DCTSIZE2]; - - if ((fp = fopen(filename, "rb")) == NULL) { - pm_message("Can't open table file %s", filename); - return FALSE; - } - tblno = 0; - - while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */ - if (tblno >= NUM_QUANT_TBLS) { - pm_message("Too many tables in file %s", filename); - fclose(fp); - return FALSE; - } - table[0] = (unsigned int) val; - for (i = 1; i < DCTSIZE2; i++) { - if (! read_text_integer(fp, &val, &termchar)) { - pm_message("Invalid table data in file %s", filename); - fclose(fp); - return FALSE; - } - table[i] = (unsigned int) val; - } - jpeg_add_quant_table(cinfo, tblno, table, scale_factor, - force_baseline); - tblno++; - } - - if (termchar != EOF) { - pm_message("Non-numeric data in file %s", filename); - fclose(fp); - return FALSE; - } - - fclose(fp); - return TRUE; -} - - -static boolean -read_scan_integer (FILE * file, long * result, int * termchar) -/* Variant of read_text_integer that always looks for a non-space termchar; - * this simplifies parsing of punctuation in scan scripts. - */ -{ - register int ch; - - if (! read_text_integer(file, result, termchar)) - return FALSE; - ch = *termchar; - while (ch != EOF && isspace(ch)) - ch = text_getc(file); - if (isdigit(ch)) { /* oops, put it back */ - if (ungetc(ch, file) == EOF) - return FALSE; - ch = ' '; - } else { - /* Any separators other than ';' and ':' are ignored; - * this allows user to insert commas, etc, if desired. - */ - if (ch != EOF && ch != ';' && ch != ':') - ch = ' '; - } - *termchar = ch; - return TRUE; -} - - -boolean -read_scan_script (j_compress_ptr cinfo, char * filename) -/* Read a scan script from the specified text file. - * Each entry in the file defines one scan to be emitted. - * Entries are separated by semicolons ';'. - * An entry contains one to four component indexes, - * optionally followed by a colon ':' and four progressive-JPEG parameters. - * The component indexes denote which component(s) are to be transmitted - * in the current scan. The first component has index 0. - * Sequential JPEG is used if the progressive-JPEG parameters are omitted. - * The file is free format text: any whitespace may appear between numbers - * and the ':' and ';' punctuation marks. Also, other punctuation (such - * as commas or dashes) can be placed between numbers if desired. - * Comments preceded by '#' may be included in the file. - * Note: we do very little validity checking here; - * jcmaster.c will validate the script parameters. - */ -{ - FILE * fp; - int nscans, ncomps, termchar; - long val; -#define MAX_SCANS 100 /* quite arbitrary limit */ - jpeg_scan_info scans[MAX_SCANS]; - - if ((fp = fopen(filename, "r")) == NULL) { - pm_message("Can't open scan definition file %s", filename); - return FALSE; - } - nscans = 0; - - while (read_scan_integer(fp, &val, &termchar)) { - nscans++; /* We got another scan */ - if (nscans > MAX_SCANS) { - pm_message("Too many scans defined in file %s", filename); - fclose(fp); - return FALSE; - } - scans[nscans-1].component_index[0] = (int) val; - ncomps = 1; - while (termchar == ' ') { - if (ncomps >= MAX_COMPS_IN_SCAN) { - pm_message("Too many components in one scan in file %s", - filename); - fclose(fp); - return FALSE; - } - if (! read_scan_integer(fp, &val, &termchar)) - goto bogus; - scans[nscans-1].component_index[ncomps] = (int) val; - ncomps++; - } - scans[nscans-1].comps_in_scan = ncomps; - if (termchar == ':') { - if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') - goto bogus; - scans[nscans-1].Ss = (int) val; - if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') - goto bogus; - scans[nscans-1].Se = (int) val; - if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ') - goto bogus; - scans[nscans-1].Ah = (int) val; - if (! read_scan_integer(fp, &val, &termchar)) - goto bogus; - scans[nscans-1].Al = (int) val; - } else { - /* set non-progressive parameters */ - scans[nscans-1].Ss = 0; - scans[nscans-1].Se = DCTSIZE2-1; - scans[nscans-1].Ah = 0; - scans[nscans-1].Al = 0; - } - if (termchar != ';' && termchar != EOF) { - bogus: - pm_message("Invalid scan entry format in file %s", filename); - fclose(fp); - return FALSE; - } - } - - if (termchar != EOF) { - pm_message("Non-numeric data in file %s", filename); - fclose(fp); - return FALSE; - } - - if (nscans > 0) { - /* Stash completed scan list in cinfo structure. NOTE: in - * this program, JPOOL_IMAGE is the right lifetime for this - * data, but if you want to compress multiple images you'd - * want JPOOL_PERMANENT. - */ - const unsigned int scan_info_size = nscans * sizeof(jpeg_scan_info); - jpeg_scan_info * const scan_info = - (jpeg_scan_info *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - scan_info_size); - memcpy(scan_info, scans, scan_info_size); - cinfo->scan_info = scan_info; - cinfo->num_scans = nscans; - } - - fclose(fp); - return TRUE; -} - - -static boolean -set_quant_slots (j_compress_ptr cinfo, char *arg) -/* Process a quantization-table-selectors parameter string, of the form - * N[,N,...] - * If there are more components than parameters, the last value is replicated. - */ -{ - int val = 0; /* default table # */ - int ci; - char ch; - - for (ci = 0; ci < MAX_COMPONENTS; ci++) { - if (*arg) { - ch = ','; /* if not set by sscanf, will be ',' */ - if (sscanf(arg, "%d%c", &val, &ch) < 1) - return FALSE; - if (ch != ',') /* syntax check */ - return FALSE; - if (val < 0 || val >= NUM_QUANT_TBLS) { - pm_message("Invalid quantization table number: %d. " - "JPEG quantization tables are numbered 0..%d", - val, NUM_QUANT_TBLS - 1); - return FALSE; - } - cinfo->comp_info[ci].quant_tbl_no = val; - while (*arg && *arg++ != ',') - /* advance to next segment of arg string */ - ; - } else { - /* reached end of parameter, set remaining components to last tbl*/ - cinfo->comp_info[ci].quant_tbl_no = val; - } - } - return TRUE; -} - - -static boolean -set_sample_factors (j_compress_ptr cinfo, char *arg) -/* Process a sample-factors parameter string, of the form - * HxV[,HxV,...] - * If there are more components than parameters, "1x1" is assumed for the rest. - */ -{ - int ci, val1, val2; - char ch1, ch2; - - for (ci = 0; ci < MAX_COMPONENTS; ci++) { - if (*arg) { - ch2 = ','; /* if not set by sscanf, will be ',' */ - if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3) - return FALSE; - if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */ - return FALSE; - if (val1 <= 0 || val1 > 4) { - pm_message("Invalid sampling factor: %d. " - "JPEG sampling factors must be 1..4", val1); - return FALSE; - } - if (val2 <= 0 || val2 > 4) { - pm_message("Invalid sampling factor: %d. " - "JPEG sampling factors must be 1..4", val2); - return FALSE; - } - cinfo->comp_info[ci].h_samp_factor = val1; - cinfo->comp_info[ci].v_samp_factor = val2; - while (*arg && *arg++ != ',') - /* advance to next segment of arg string */ - ; - } else { - /* reached end of parameter, set remaining components - to 1x1 sampling */ - cinfo->comp_info[ci].h_samp_factor = 1; - cinfo->comp_info[ci].v_samp_factor = 1; - } - } - return TRUE; -} - int -main(int argc, char ** argv) { +main(int argc, + char ** argv) { struct cmdlineInfo cmdline; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; - FILE *input_file; + FILE * input_file; FILE * output_file; int height; /* height of the input image in rows, as specified by its header */ diff --git a/converter/ppm/ppmtompeg/Makefile b/converter/ppm/ppmtompeg/Makefile index 6db72ea9..e5ad6c58 100644 --- a/converter/ppm/ppmtompeg/Makefile +++ b/converter/ppm/ppmtompeg/Makefile @@ -39,7 +39,15 @@ endif # MP_BASE_OBJS = mfwddct.o postdct.o huff.o bitio.o mheaders.o -MP_ENCODE_OBJS = iframe.o pframe.o bframe.o psearch.o bsearch.o block.o +MP_ENCODE_OBJS = \ + frames.o \ + iframe.o \ + pframe.o \ + bframe.o \ + psearch.o \ + bsearch.o \ + block.o + MP_OTHER_OBJS = mpeg.o subsample.o param.o rgbtoycc.o \ readframe.o combine.o jrevdct.o frame.o fsize.o frametype.o \ specifics.o rate.o opts.o input.o gethostname.o diff --git a/converter/ppm/ppmtompeg/bframe.c b/converter/ppm/ppmtompeg/bframe.c index 5dfb76d3..1dbc1846 100644 --- a/converter/ppm/ppmtompeg/bframe.c +++ b/converter/ppm/ppmtompeg/bframe.c @@ -84,7 +84,6 @@ static struct bframeStats { *====================*/ extern Block **dct, **dctr, **dctb; -extern dct_data_type **dct_data; #define NO_MOTION 0 #define MOTION 1 #define SKIP 2 /* used in useMotion in dct_data */ diff --git a/converter/ppm/ppmtompeg/bsearch.c b/converter/ppm/ppmtompeg/bsearch.c index 142987f5..70edfef6 100644 --- a/converter/ppm/ppmtompeg/bsearch.c +++ b/converter/ppm/ppmtompeg/bsearch.c @@ -77,6 +77,7 @@ #include "frames.h" #include "motion_search.h" #include "fsize.h" +#include "block.h" /*==================* diff --git a/converter/ppm/ppmtompeg/frames.c b/converter/ppm/ppmtompeg/frames.c new file mode 100644 index 00000000..a0764890 --- /dev/null +++ b/converter/ppm/ppmtompeg/frames.c @@ -0,0 +1,58 @@ +#include "mallocvar.h" +#include "fsize.h" + +#include "frames.h" + + +Block **dct=NULL, **dctr=NULL, **dctb=NULL; +dct_data_type **dct_data; /* used in p/bframe.c */ + + +/*===========================================================================* + * + * AllocDctBlocks + * + * allocate memory for dct blocks + * + * RETURNS: nothing + * + * SIDE EFFECTS: creates dct, dctr, dctb + * + *===========================================================================*/ +void +AllocDctBlocks(void) { + + int dctx, dcty; + int i; + + dctx = Fsize_x / DCTSIZE; + dcty = Fsize_y / DCTSIZE; + + MALLOCARRAY(dct, dcty); + ERRCHK(dct, "malloc"); + for (i = 0; i < dcty; ++i) { + dct[i] = (Block *) malloc(sizeof(Block) * dctx); + ERRCHK(dct[i], "malloc"); + } + + MALLOCARRAY(dct_data, dcty); + ERRCHK(dct_data, "malloc"); + for (i = 0; i < dcty; ++i) { + MALLOCARRAY(dct_data[i], dctx); + ERRCHK(dct[i], "malloc"); + } + + MALLOCARRAY(dctr, dcty/2); + ERRCHK(dctr, "malloc"); + MALLOCARRAY(dctb, dcty/2); + ERRCHK(dctb, "malloc"); + for (i = 0; i < dcty/2; ++i) { + MALLOCARRAY(dctr[i], dctx/2); + ERRCHK(dctr[i], "malloc"); + MALLOCARRAY(dctb[i], dctx/2); + ERRCHK(dctb[i], "malloc"); + } +} + + + diff --git a/converter/ppm/ppmtompeg/headers/bitio.h b/converter/ppm/ppmtompeg/headers/bitio.h index 89e61fbb..a24c21cd 100644 --- a/converter/ppm/ppmtompeg/headers/bitio.h +++ b/converter/ppm/ppmtompeg/headers/bitio.h @@ -60,9 +60,7 @@ #define BIT_IO_INCLUDED -/*==============* - * HEADER FILES * - *==============*/ +#include <stdio.h> #include "general.h" #include "ansi.h" diff --git a/converter/ppm/ppmtompeg/headers/block.h b/converter/ppm/ppmtompeg/headers/block.h index 46050492..22d306a1 100644 --- a/converter/ppm/ppmtompeg/headers/block.h +++ b/converter/ppm/ppmtompeg/headers/block.h @@ -1,3 +1,46 @@ +#ifndef BLOCK_H_INCLUDED + +#include "frame.h" +#include "mtypes.h" + +/* DIFFERENCE FUNCTIONS */ + +int32 +LumBlockMAD(const LumBlock * const currentBlockP, + const LumBlock * const motionBlockP, + int32 const bestSoFar); + +int32 +LumBlockMSE(const LumBlock * const currentBlockP, + const LumBlock * const motionBlockP, + int32 const bestSoFar); + +int32 +LumMotionError(const LumBlock * const currentBlockP, + MpegFrame * const prev, + int const by, + int const bx, + vector const m, + int32 const bestSoFar); + +int32 +LumAddMotionError(const LumBlock * const currentBlockP, + const LumBlock * const blockSoFarP, + MpegFrame * const prev, + int const by, + int const bx, + vector const m, + int32 const bestSoFar); + +int32 +LumMotionErrorSubSampled(const LumBlock * const currentBlockP, + MpegFrame * const prevFrame, + int const by, + int const bx, + vector const m, + int const startY, + int const startX); + void ComputeDiffDCTs(MpegFrame * const current, MpegFrame * const prev, @@ -51,3 +94,4 @@ AddBMotionBlock(Block block, void BlockifyFrame(MpegFrame * const frameP); +#endif diff --git a/converter/ppm/ppmtompeg/headers/frame.h b/converter/ppm/ppmtompeg/headers/frame.h index 1003ee15..acd74419 100644 --- a/converter/ppm/ppmtompeg/headers/frame.h +++ b/converter/ppm/ppmtompeg/headers/frame.h @@ -130,18 +130,4 @@ Frame_Resize(MpegFrame * const omf, int const outsize_x, int const outsize_y); - -extern void Frame_Free _ANSI_ARGS_((MpegFrame *frame)); -extern void Frame_Exit _ANSI_ARGS_((void)); -extern void Frame_AllocPPM _ANSI_ARGS_((MpegFrame * frame)); -extern void Frame_AllocYCC _ANSI_ARGS_((MpegFrame * mf)); -extern void Frame_AllocDecoded _ANSI_ARGS_((MpegFrame *frame, - boolean makeReference)); -extern void Frame_AllocHalf _ANSI_ARGS_((MpegFrame *frame)); -extern void Frame_AllocBlocks _ANSI_ARGS_((MpegFrame *mf)); -extern void Frame_Resize _ANSI_ARGS_((MpegFrame *omf, MpegFrame *mf, - int insize_x, int insize_y, - int outsize_x, int outsize_y)); - - -#endif /* FRAME_INCLUDED */ +#endif diff --git a/converter/ppm/ppmtompeg/headers/frames.h b/converter/ppm/ppmtompeg/headers/frames.h index 3fefaea7..8661645b 100644 --- a/converter/ppm/ppmtompeg/headers/frames.h +++ b/converter/ppm/ppmtompeg/headers/frames.h @@ -15,6 +15,7 @@ #include "ansi.h" #include "mtypes.h" #include "mheaders.h" +#include "iframe.h" #include "frame.h" @@ -85,11 +86,13 @@ typedef struct dct_data_tye_struct { int fmotionX, fmotionY, bmotionX, bmotionY; } dct_data_type; -void EncodeYDC _ANSI_ARGS_((int32 dc_term, int32 *pred_term, BitBucket *bb)); -void -EncodeCDC(int32 const dc_term, - int32 * const pred_term, - BitBucket * const bb); + +/*==================* + * GLOBAL VARIABLES * + *==================*/ + +extern Block **dct, **dctr, **dctb; +extern dct_data_type **dct_data; /*========* @@ -100,63 +103,6 @@ EncodeCDC(int32 const dc_term, #define int_ceil_div(a,b,c) ((b*(c = a/b) < a) ? (c+1) : c) #define int_floor_div(a,b,c) ((b*(c = a/b) > a) ? (c-1) : c) -/* assumes many things: - * block indices are (y,x) - * variables y_dc_pred, cr_dc_pred, and cb_dc_pred - * flat block fb exists - */ -#define GEN_I_BLOCK(frameType, frame, bb, mbAI, qscale) { \ - boolean overflow, overflowChange=FALSE; \ - int overflowValue = 0; \ - do { \ - overflow = Mpost_QuantZigBlock(dct[y][x], fb[0], \ - qscale, TRUE)==MPOST_OVERFLOW; \ - overflow |= Mpost_QuantZigBlock(dct[y][x+1], fb[1], \ - qscale, TRUE)==MPOST_OVERFLOW; \ - overflow |= Mpost_QuantZigBlock(dct[y+1][x], fb[2], \ - qscale, TRUE)==MPOST_OVERFLOW; \ - overflow |= Mpost_QuantZigBlock(dct[y+1][x+1], fb[3], \ - qscale, TRUE)==MPOST_OVERFLOW; \ - overflow |= Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], \ - fb[4], qscale, TRUE)==MPOST_OVERFLOW; \ - overflow |= Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], \ - fb[5], qscale, TRUE)==MPOST_OVERFLOW; \ - if ((overflow) && (qscale!=31)) { \ - overflowChange = TRUE; overflowValue++; \ - qscale++; \ - } else overflow = FALSE; \ - } while (overflow); \ - Mhead_GenMBHeader(bb, \ - frameType /* pict_code_type */, mbAI /* addr_incr */, \ - qscale /* q_scale */, \ - 0 /* forw_f_code */, 0 /* back_f_code */, \ - 0 /* horiz_forw_r */, 0 /* vert_forw_r */, \ - 0 /* horiz_back_r */, 0 /* vert_back_r */, \ - 0 /* motion_forw */, 0 /* m_horiz_forw */, \ - 0 /* m_vert_forw */, 0 /* motion_back */, \ - 0 /* m_horiz_back */, 0 /* m_vert_back */, \ - 0 /* mb_pattern */, TRUE /* mb_intra */); \ - \ - /* Y blocks */ \ - EncodeYDC(fb[0][0], &y_dc_pred, bb); \ - Mpost_RLEHuffIBlock(fb[0], bb); \ - EncodeYDC(fb[1][0], &y_dc_pred, bb); \ - Mpost_RLEHuffIBlock(fb[1], bb); \ - EncodeYDC(fb[2][0], &y_dc_pred, bb); \ - Mpost_RLEHuffIBlock(fb[2], bb); \ - EncodeYDC(fb[3][0], &y_dc_pred, bb); \ - Mpost_RLEHuffIBlock(fb[3], bb); \ - \ - /* CB block */ \ - EncodeCDC(fb[4][0], &cb_dc_pred, bb); \ - Mpost_RLEHuffIBlock(fb[4], bb); \ - \ - /* CR block */ \ - EncodeCDC(fb[5][0], &cr_dc_pred, bb); \ - Mpost_RLEHuffIBlock(fb[5], bb); \ - if (overflowChange) qscale -= overflowValue; \ - } - #define BLOCK_TO_FRAME_COORD(bx1, bx2, x1, x2) { \ x1 = (bx1)*DCTSIZE; \ x2 = (bx2)*DCTSIZE; \ @@ -253,6 +199,9 @@ encodeMotionVector(int const x, *===============================*/ void +AllocDctBlocks(void); + +void ComputeBMotionLumBlock(MpegFrame * const prev, MpegFrame * const next, int const by, @@ -270,8 +219,6 @@ BMotionSearch(const LumBlock * const currentBlockP, motion * const motionP, int const oldMode); -void GenIFrame (BitBucket * const bb, - MpegFrame * const mf); void GenPFrame (BitBucket * const bb, MpegFrame * const current, MpegFrame * const prev); @@ -279,11 +226,6 @@ void GenBFrame (BitBucket * const bb, MpegFrame * const curr, MpegFrame * const prev, MpegFrame * const next); -void AllocDctBlocks _ANSI_ARGS_((void )); - - -float -IFrameTotalTime(void); float PFrameTotalTime(void); @@ -292,11 +234,6 @@ float BFrameTotalTime(void); void -ShowIFrameSummary(unsigned int const inputFrameBits, - unsigned int const totalBits, - FILE * const fpointer); - -void ShowPFrameSummary(unsigned int const inputFrameBits, unsigned int const totalBits, FILE * const fpointer); @@ -306,87 +243,6 @@ ShowBFrameSummary(unsigned int const inputFrameBits, unsigned int const totalBits, FILE * const fpointer); -/* DIFFERENCE FUNCTIONS */ - -int32 -LumBlockMAD(const LumBlock * const currentBlockP, - const LumBlock * const motionBlockP, - int32 const bestSoFar); - -int32 -LumBlockMSE(const LumBlock * const currentBlockP, - const LumBlock * const motionBlockP, - int32 const bestSoFar); - -int32 -LumMotionError(const LumBlock * const currentBlockP, - MpegFrame * const prev, - int const by, - int const bx, - vector const m, - int32 const bestSoFar); - -int32 -LumAddMotionError(const LumBlock * const currentBlockP, - const LumBlock * const blockSoFarP, - MpegFrame * const prev, - int const by, - int const bx, - vector const m, - int32 const bestSoFar); - -int32 -LumMotionErrorA(const LumBlock * const currentBlockP, - MpegFrame * const prevFrame, - int const by, - int const bx, - vector const m, - int32 const bestSoFar); - -int32 -LumMotionErrorB(const LumBlock * const currentP, - MpegFrame * const prevFrame, - int const by, - int const bx, - vector const m, - int32 const bestSoFar); - -int32 -LumMotionErrorC(const LumBlock * const currentP, - MpegFrame * const prevFrame, - int const by, - int const bx, - vector const m, - int32 const bestSoFar); - -int32 -LumMotionErrorD(const LumBlock * const currentP, - MpegFrame * const prevFrame, - int const by, - int const bx, - vector const m, - int32 const bestSoFar); - -int32 -LumMotionErrorSubSampled(const LumBlock * const currentBlockP, - MpegFrame * const prevFrame, - int const by, - int const bx, - vector const m, - int const startY, - int const startX); - -void -BlockComputeSNR(MpegFrame * const current, - float * const snr, - float * const psnr); - -int32 -time_elapsed(void); - -void -AllocDctBlocks(void); - /*==================* * GLOBAL VARIABLES * *==================*/ @@ -412,7 +268,7 @@ extern int fCodeI,fCodeP,fCodeB; extern boolean forceEncodeLast; extern int TIME_RATE; -#endif /* FRAMES_INCLUDED */ +#endif /* diff --git a/converter/ppm/ppmtompeg/headers/iframe.h b/converter/ppm/ppmtompeg/headers/iframe.h new file mode 100644 index 00000000..c4f77c74 --- /dev/null +++ b/converter/ppm/ppmtompeg/headers/iframe.h @@ -0,0 +1,118 @@ +#ifndef IFRAME_H_INCLUDED +#define IFRAME_H_INCLUDED + +#include "frame.h" + +void +SetFCode(void); + +void +SetSlicesPerFrame(int const number); + +void +SetBlocksPerSlice(void); + +void +SetIQScale(int const qI); + +int +GetIQScale(void); + +void +GenIFrame(BitBucket * const bb, + MpegFrame * const current); + +void +ResetIFrameStats(void); + +float +IFrameTotalTime(void); + + +void +ShowIFrameSummary(unsigned int const inputFrameBits, + unsigned int const totalBits, + FILE * const fpointer); + +void +EncodeYDC(int32 const dc_term, + int32 * const pred_term, + BitBucket * const bb); + +void +EncodeCDC(int32 const dc_term, + int32 * const pred_term, + BitBucket * const bb); + +void +BlockComputeSNR(MpegFrame * const current, + float * const snr, + float * const psnr); + +void +WriteDecodedFrame(MpegFrame * const frame); + +void +PrintItoIBitRate(int const numBits, + int const frameNum); + +int32 time_elapsed(void); + +/* assumes many things: + * block indices are (y,x) + * variables y_dc_pred, cr_dc_pred, and cb_dc_pred + * flat block fb exists + */ +#define GEN_I_BLOCK(frameType, frame, bb, mbAI, qscale) { \ + boolean overflow, overflowChange=FALSE; \ + int overflowValue = 0; \ + do { \ + overflow = Mpost_QuantZigBlock(dct[y][x], fb[0], \ + qscale, TRUE)==MPOST_OVERFLOW; \ + overflow |= Mpost_QuantZigBlock(dct[y][x+1], fb[1], \ + qscale, TRUE)==MPOST_OVERFLOW; \ + overflow |= Mpost_QuantZigBlock(dct[y+1][x], fb[2], \ + qscale, TRUE)==MPOST_OVERFLOW; \ + overflow |= Mpost_QuantZigBlock(dct[y+1][x+1], fb[3], \ + qscale, TRUE)==MPOST_OVERFLOW; \ + overflow |= Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], \ + fb[4], qscale, TRUE)==MPOST_OVERFLOW; \ + overflow |= Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], \ + fb[5], qscale, TRUE)==MPOST_OVERFLOW; \ + if ((overflow) && (qscale!=31)) { \ + overflowChange = TRUE; overflowValue++; \ + qscale++; \ + } else overflow = FALSE; \ + } while (overflow); \ + Mhead_GenMBHeader(bb, \ + frameType /* pict_code_type */, mbAI /* addr_incr */, \ + qscale /* q_scale */, \ + 0 /* forw_f_code */, 0 /* back_f_code */, \ + 0 /* horiz_forw_r */, 0 /* vert_forw_r */, \ + 0 /* horiz_back_r */, 0 /* vert_back_r */, \ + 0 /* motion_forw */, 0 /* m_horiz_forw */, \ + 0 /* m_vert_forw */, 0 /* motion_back */, \ + 0 /* m_horiz_back */, 0 /* m_vert_back */, \ + 0 /* mb_pattern */, TRUE /* mb_intra */); \ + \ + /* Y blocks */ \ + EncodeYDC(fb[0][0], &y_dc_pred, bb); \ + Mpost_RLEHuffIBlock(fb[0], bb); \ + EncodeYDC(fb[1][0], &y_dc_pred, bb); \ + Mpost_RLEHuffIBlock(fb[1], bb); \ + EncodeYDC(fb[2][0], &y_dc_pred, bb); \ + Mpost_RLEHuffIBlock(fb[2], bb); \ + EncodeYDC(fb[3][0], &y_dc_pred, bb); \ + Mpost_RLEHuffIBlock(fb[3], bb); \ + \ + /* CB block */ \ + EncodeCDC(fb[4][0], &cb_dc_pred, bb); \ + Mpost_RLEHuffIBlock(fb[4], bb); \ + \ + /* CR block */ \ + EncodeCDC(fb[5][0], &cr_dc_pred, bb); \ + Mpost_RLEHuffIBlock(fb[5], bb); \ + if (overflowChange) qscale -= overflowValue; \ + } + +#endif diff --git a/converter/ppm/ppmtompeg/headers/motion_search.h b/converter/ppm/ppmtompeg/headers/motion_search.h index ab83cbca..62f3abab 100644 --- a/converter/ppm/ppmtompeg/headers/motion_search.h +++ b/converter/ppm/ppmtompeg/headers/motion_search.h @@ -100,6 +100,9 @@ PMotionSearch(const LumBlock * const currentBlockP, int const bx, vector * const motionP); +void +MotionSearchPreComputation(MpegFrame * const frameP); + /*==================* * GLOBAL VARIABLES * *==================*/ diff --git a/converter/ppm/ppmtompeg/headers/mpeg.h b/converter/ppm/ppmtompeg/headers/mpeg.h index d739dede..18e6c7e1 100644 --- a/converter/ppm/ppmtompeg/headers/mpeg.h +++ b/converter/ppm/ppmtompeg/headers/mpeg.h @@ -90,7 +90,6 @@ void ReadDecodedRefFrame(MpegFrame * const frameP, unsigned int const frameNumber); -extern void WriteDecodedFrame _ANSI_ARGS_((MpegFrame *frame)); extern void SetBitRateFileName _ANSI_ARGS_((char *fileName)); extern void SetFrameRate _ANSI_ARGS_((void)); diff --git a/converter/ppm/ppmtompeg/headers/mproto.h b/converter/ppm/ppmtompeg/headers/mproto.h index c3b0f4b3..d8fefd84 100644 --- a/converter/ppm/ppmtompeg/headers/mproto.h +++ b/converter/ppm/ppmtompeg/headers/mproto.h @@ -74,7 +74,6 @@ #include "bitio.h" -#define DCTSIZE2 DCTSIZE*DCTSIZE typedef short DCTELEM; typedef DCTELEM DCTBLOCK[DCTSIZE2]; @@ -111,9 +110,6 @@ void ReadEYUV _ANSI_ARGS_((MpegFrame * mf, FILE *fpointer, int width, boolean ReadPPM _ANSI_ARGS_((MpegFrame *mf, FILE *fpointer)); void PPMtoYCC _ANSI_ARGS_((MpegFrame * mf)); -void MotionSearchPreComputation _ANSI_ARGS_((MpegFrame *frame)); -boolean PMotionSearch _ANSI_ARGS_((LumBlock currentBlock, MpegFrame *prev, - int by, int bx, int *motionY, int *motionX)); void ComputeHalfPixelData _ANSI_ARGS_((MpegFrame *frame)); void mp_validate_size _ANSI_ARGS_((int *x, int *y)); void AllocYCC _ANSI_ARGS_((MpegFrame * mf)); @@ -126,7 +122,3 @@ void j_rev_dct _ANSI_ARGS_((DCTBLOCK data )); void j_rev_dct_sparse _ANSI_ARGS_((DCTBLOCK data , int pos )); void j_rev_dct _ANSI_ARGS_((DCTBLOCK data )); -/* block.c */ -void BlockToData _ANSI_ARGS_((uint8 **data, Block block, int by, int bx)); -void AddMotionBlock _ANSI_ARGS_((Block block, uint8 **prev, int by, int bx, - int my, int mx)); diff --git a/converter/ppm/ppmtompeg/headers/parallel.h b/converter/ppm/ppmtompeg/headers/parallel.h index e18d3f46..cf27ce66 100644 --- a/converter/ppm/ppmtompeg/headers/parallel.h +++ b/converter/ppm/ppmtompeg/headers/parallel.h @@ -87,7 +87,7 @@ void NoteFrameDone(int frameStart, int frameEnd); void -SetIOConvert(boolean separate); +SetIOConvert(bool const separate); void SetRemoteShell(const char * const shell); diff --git a/converter/ppm/ppmtompeg/headers/prototypes.h b/converter/ppm/ppmtompeg/headers/prototypes.h index d729aafa..b421af35 100644 --- a/converter/ppm/ppmtompeg/headers/prototypes.h +++ b/converter/ppm/ppmtompeg/headers/prototypes.h @@ -44,20 +44,15 @@ void ResetBFrameStats _ANSI_ARGS_((void)); void ResetPFrameStats _ANSI_ARGS_((void)); void SetSearchRange (int const pixelsP, int const pixelsB); -void ResetIFrameStats _ANSI_ARGS_((void)); void SetPixelSearch(const char * const searchType); -void SetIQScale _ANSI_ARGS_((int qI)); void SetPQScale _ANSI_ARGS_((int qP)); void SetBQScale _ANSI_ARGS_((int qB)); -float EstimateSecondsPerIFrame _ANSI_ARGS_((void)); float EstimateSecondsPerPFrame _ANSI_ARGS_((void)); float EstimateSecondsPerBFrame _ANSI_ARGS_((void)); void SetGOPSize _ANSI_ARGS_((int size)); void SetStatFileName(const char * const fileName); -void SetSlicesPerFrame _ANSI_ARGS_((int number)); -void SetBlocksPerSlice _ANSI_ARGS_((void)); void DCTFrame _ANSI_ARGS_((MpegFrame * mf)); @@ -69,8 +64,6 @@ void MotionSearchPreComputation _ANSI_ARGS_((MpegFrame *frame)); void ComputeHalfPixelData _ANSI_ARGS_((MpegFrame *frame)); void mp_validate_size _ANSI_ARGS_((int *x, int *y)); -extern void SetFCode _ANSI_ARGS_((void)); - /* psearch.c */ void ShowPMVHistogram _ANSI_ARGS_((FILE *fpointer)); diff --git a/converter/ppm/ppmtompeg/headers/subsample.h b/converter/ppm/ppmtompeg/headers/subsample.h new file mode 100644 index 00000000..deedf251 --- /dev/null +++ b/converter/ppm/ppmtompeg/headers/subsample.h @@ -0,0 +1,39 @@ +#ifndef SUBSAMPLE_H_INCLUDED +#define SUBSAMPLE_H_INCLUDED + +#include "frame.h" +#include "mtypes.h" + +int32 +LumMotionErrorA(const LumBlock * const currentBlockP, + MpegFrame * const prevFrame, + int const by, + int const bx, + vector const m, + int32 const bestSoFar); + +int32 +LumMotionErrorB(const LumBlock * const currentP, + MpegFrame * const prevFrame, + int const by, + int const bx, + vector const m, + int32 const bestSoFar); + +int32 +LumMotionErrorC(const LumBlock * const currentP, + MpegFrame * const prevFrame, + int const by, + int const bx, + vector const m, + int32 const bestSoFar); + +int32 +LumMotionErrorD(const LumBlock * const currentP, + MpegFrame * const prevFrame, + int const by, + int const bx, + vector const m, + int32 const bestSoFar); + +#endif diff --git a/converter/ppm/ppmtompeg/iframe.c b/converter/ppm/ppmtompeg/iframe.c index cb6d4683..c6735505 100644 --- a/converter/ppm/ppmtompeg/iframe.c +++ b/converter/ppm/ppmtompeg/iframe.c @@ -11,10 +11,9 @@ * GetIQScale * * ResetIFrameStats * * ShowIFrameSummary * - * EstimateSecondsPerIFrame * * EncodeYDC * * EncodeCDC * - * time_elapsed * + * time_elapsed * * * *===========================================================================*/ @@ -67,6 +66,8 @@ #include "specifics.h" #include "opts.h" +#include "iframe.h" + /*==================* * STATIC VARIABLES * *==================*/ @@ -128,24 +129,11 @@ int fCodeI, fCodeP, fCodeB; boolean printSNR = FALSE; boolean printMSE = FALSE; boolean decodeRefFrames = FALSE; -Block **dct=NULL, **dctr=NULL, **dctb=NULL; -dct_data_type **dct_data; /* used in p/bframe.c */ int TIME_RATE; -/*=====================* - * EXPORTED PROCEDURES * - *=====================*/ -extern void PrintItoIBitRate _ANSI_ARGS_((int numBits, int frameNum)); - -/*===============================* - * INTERNAL PROCEDURE prototypes * - *===============================*/ -void AllocDctBlocks(void ); -int SetFCodeHelper (int sr); -void CalcDistortion (MpegFrame *current, int y, int x); -int +static int SetFCodeHelper(int const SR) { int range,fCode; @@ -296,6 +284,68 @@ GetIQScale(void) { +static void +CalcDistortion(MpegFrame * const current, + int const y, + int const x) { + + int qscale, distort=0; + Block decblk; + FlatBlock fblk; + int datarate = 0; + + for (qscale = 1; qscale < 32; qscale ++) { + distort = 0; + datarate = 0; + Mpost_QuantZigBlock(dct[y][x], fblk, qscale, TRUE); + Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); + if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); + mpeg_jrevdct((int16 *)decblk); + distort += mse(current->y_blocks[y][x], decblk); + + Mpost_QuantZigBlock(dct[y][x+1], fblk, qscale, TRUE); + Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); + if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); + mpeg_jrevdct((int16 *)decblk); + distort += mse(current->y_blocks[y][x+1], decblk); + + Mpost_QuantZigBlock(dct[y+1][x], fblk, qscale, TRUE); + Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); + if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); + mpeg_jrevdct((int16 *)decblk); + distort += mse(current->y_blocks[y+1][x], decblk); + + Mpost_QuantZigBlock(dct[y+1][x+1], fblk, qscale, TRUE); + Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); + if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); + mpeg_jrevdct((int16 *)decblk); + distort += mse(current->y_blocks[y+1][x+1], decblk); + + Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], fblk, qscale, TRUE); + Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); + if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); + mpeg_jrevdct((int16 *)decblk); + distort += mse(current->cb_blocks[y>>1][x>>1], decblk); + + Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], fblk, qscale, TRUE); + Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); + if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); + mpeg_jrevdct((int16 *)decblk); + distort += mse(current->cr_blocks[y >> 1][x >> 1], decblk); + + if (!collect_distortion_detailed) { + fprintf(distortion_fp, "\t%d\n", distort); + } else if (collect_distortion_detailed == 1) { + fprintf(distortion_fp, "\t%d\t%d\n", distort, datarate); + } else { + fprintf(fp_table_rate[qscale-1], "%d\n", datarate); + fprintf(fp_table_dist[qscale-1], "%d\n", distort); + } + } +} + + + /*===========================================================================* * * GenIFrame @@ -618,24 +668,6 @@ ShowIFrameSummary(unsigned int const inputFrameBits, /*===========================================================================* * - * EstimateSecondsPerIFrame - * - * estimates the number of seconds required per I-frame - * - * RETURNS: seconds (floating point value) - * - * SIDE EFFECTS: none - * - *===========================================================================*/ -float -EstimateSecondsPerIFrame() -{ - return (float)totalTime/((float)TIME_RATE*(float)numFrames); -} - - -/*===========================================================================* - * * EncodeYDC * * Encode the DC portion of a DCT of a luminance block @@ -926,53 +958,6 @@ PrintItoIBitRate(int const numBits, -/*===========================================================================* - * - * AllocDctBlocks - * - * allocate memory for dct blocks - * - * RETURNS: nothing - * - * SIDE EFFECTS: creates dct, dctr, dctb - * - *===========================================================================*/ -void -AllocDctBlocks(void) { - int dctx, dcty; - int i; - - dctx = Fsize_x / DCTSIZE; - dcty = Fsize_y / DCTSIZE; - - dct = (Block **) malloc(sizeof(Block *) * dcty); - ERRCHK(dct, "malloc"); - for (i = 0; i < dcty; i++) { - dct[i] = (Block *) malloc(sizeof(Block) * dctx); - ERRCHK(dct[i], "malloc"); - } - - dct_data = (dct_data_type **) malloc(sizeof(dct_data_type *) * dcty); - ERRCHK(dct_data, "malloc"); - for (i = 0; i < dcty; i++) { - dct_data[i] = (dct_data_type *) malloc(sizeof(dct_data_type) * dctx); - ERRCHK(dct[i], "malloc"); - } - - dctr = (Block **) malloc(sizeof(Block *) * (dcty >> 1)); - dctb = (Block **) malloc(sizeof(Block *) * (dcty >> 1)); - ERRCHK(dctr, "malloc"); - ERRCHK(dctb, "malloc"); - for (i = 0; i < (dcty >> 1); i++) { - dctr[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1)); - dctb[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1)); - ERRCHK(dctr[i], "malloc"); - ERRCHK(dctb[i], "malloc"); - } -} - - - /*======================================================================* * * time_elapsed @@ -997,66 +982,4 @@ int32 time_elapsed(void) { -void -CalcDistortion(MpegFrame * const current, - int const y, - int const x) { - - int qscale, distort=0; - Block decblk; - FlatBlock fblk; - int datarate = 0; - - for (qscale = 1; qscale < 32; qscale ++) { - distort = 0; - datarate = 0; - Mpost_QuantZigBlock(dct[y][x], fblk, qscale, TRUE); - Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); - if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); - mpeg_jrevdct((int16 *)decblk); - distort += mse(current->y_blocks[y][x], decblk); - - Mpost_QuantZigBlock(dct[y][x+1], fblk, qscale, TRUE); - Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); - if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); - mpeg_jrevdct((int16 *)decblk); - distort += mse(current->y_blocks[y][x+1], decblk); - - Mpost_QuantZigBlock(dct[y+1][x], fblk, qscale, TRUE); - Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); - if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); - mpeg_jrevdct((int16 *)decblk); - distort += mse(current->y_blocks[y+1][x], decblk); - - Mpost_QuantZigBlock(dct[y+1][x+1], fblk, qscale, TRUE); - Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); - if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); - mpeg_jrevdct((int16 *)decblk); - distort += mse(current->y_blocks[y+1][x+1], decblk); - - Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], fblk, qscale, TRUE); - Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); - if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); - mpeg_jrevdct((int16 *)decblk); - distort += mse(current->cb_blocks[y>>1][x>>1], decblk); - - Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], fblk, qscale, TRUE); - Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); - if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); - mpeg_jrevdct((int16 *)decblk); - distort += mse(current->cr_blocks[y >> 1][x >> 1], decblk); - - if (!collect_distortion_detailed) { - fprintf(distortion_fp, "\t%d\n", distort); - } else if (collect_distortion_detailed == 1) { - fprintf(distortion_fp, "\t%d\t%d\n", distort, datarate); - } else { - fprintf(fp_table_rate[qscale-1], "%d\n", datarate); - fprintf(fp_table_dist[qscale-1], "%d\n", distort); - } - } -} - - - diff --git a/converter/ppm/ppmtompeg/mheaders.c b/converter/ppm/ppmtompeg/mheaders.c index 2a5f2c63..4cfe49ac 100644 --- a/converter/ppm/ppmtompeg/mheaders.c +++ b/converter/ppm/ppmtompeg/mheaders.c @@ -278,24 +278,350 @@ const double VidRateNum[9]={1.0, 23.976, 24.0, 25.0, 29.97, 30.0, 50.0 ,59.94, 60.0}; -/*===============================* - * INTERNAL PROCEDURE prototypes * - *===============================*/ - -static void GenMBAddrIncr _ANSI_ARGS_((BitBucket *bb, uint32 addr_incr)); -static void GenPictHead _ANSI_ARGS_((BitBucket *bb, uint32 temp_ref, - uint32 code_type, uint32 vbv_delay, - int32 full_pel_forw_flag, uint32 forw_f_code, - int32 full_pel_back_flag, uint32 back_f_code, - uint8 *extra_info, uint32 extra_info_size, - uint8 *ext_data, uint32 ext_data_size, - uint8 *user_data, uint32 user_data_size)); -static void GenMBType _ANSI_ARGS_((BitBucket *bb, uint32 pict_code_type, - uint32 mb_quant, uint32 motion_forw, uint32 motion_back, - uint32 mb_pattern, uint32 mb_intra)); -static void GenMotionCode _ANSI_ARGS_((BitBucket *bb, int32 vector)); -static void GenBlockPattern _ANSI_ARGS_((BitBucket *bb, - uint32 mb_pattern)); +/*=====================* + * INTERNAL PROCEDURES * + *=====================*/ + +/*===========================================================================* + * + * GenMBType + * + * generate macroblock type with given attributes + * append result to the specified bitstream + * + * RETURNS: nothing + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +static void +GenMBType(bbPtr, pict_code_type, mb_quant, motion_forw, motion_back, + mb_pattern, mb_intra) + BitBucket *bbPtr; + uint32 pict_code_type; + uint32 mb_quant; + uint32 motion_forw; + uint32 motion_back; + uint32 mb_pattern; + uint32 mb_intra; +{ + int code; + + switch (pict_code_type) { + case 1: + if ((motion_forw != 0) || (motion_back != 0) || (mb_pattern != 0) || (mb_intra != 1)) { + perror("Illegal parameters for macroblock type."); + exit(-1); + } + if (mb_quant) { + Bitio_Write(bbPtr, 0x1, 2); + } else { + Bitio_Write(bbPtr, 0x1, 1); + } + break; + + case 2: + code = 0; + if (mb_quant) { + code += 16; + } + if (motion_forw) { + code += 8; + } + if (motion_back) { + code += 4; + } + if (mb_pattern) { + code += 2; + } + if (mb_intra) { + code += 1; + } + + switch (code) { + case 1: + Bitio_Write(bbPtr, 0x3, 5); + break; + case 2: + Bitio_Write(bbPtr, 0x1, 2); + break; + case 8: + Bitio_Write(bbPtr, 0x1, 3); + break; + case 10: + Bitio_Write(bbPtr, 0x1, 1); + break; + case 17: + Bitio_Write(bbPtr, 0x1, 6); + break; + case 18: + Bitio_Write(bbPtr, 0x1, 5); + break; + case 26: + Bitio_Write(bbPtr, 0x2, 5); + break; + default: + perror("Illegal parameters for macroblock type."); + exit(-1); + break; + } + break; + + case 3: + code = 0; + if (mb_quant) { + code += 16; + } + if (motion_forw) { + code += 8; + } + if (motion_back) { + code += 4; + } + if (mb_pattern) { + code += 2; + } + if (mb_intra) { + code += 1; + } + + switch (code) { + case 12: + Bitio_Write(bbPtr, 0x2, 2); + break; + case 14: + Bitio_Write(bbPtr, 0x3, 2); + break; + case 4: + Bitio_Write(bbPtr, 0x2, 3); + break; + case 6: + Bitio_Write(bbPtr, 0x3, 3); + break; + case 8: + Bitio_Write(bbPtr, 0x2, 4); + break; + case 10: + Bitio_Write(bbPtr, 0x3, 4); + break; + case 1: + Bitio_Write(bbPtr, 0x3, 5); + break; + case 30: + Bitio_Write(bbPtr, 0x2, 5); + break; + case 26: + Bitio_Write(bbPtr, 0x3, 6); + break; + case 22: + Bitio_Write(bbPtr, 0x2, 6); + break; + case 17: + Bitio_Write(bbPtr, 0x1, 6); + break; + default: + perror("Illegal parameters for macroblock type."); + exit(-1); + break; + } + break; + } +} + + +/*===========================================================================* + * + * GenMotionCode + * + * generate motion vector output with given value + * append result to the specified bitstream + * + * RETURNS: nothing + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +static void +GenMotionCode(BitBucket * const bbPtr, + int32 const vector) { + + uint32 code, num; + + if ((vector < -16) || (vector > 16)) { + perror("Motion vector out of range."); + fprintf(stderr, "Motion vector out of range: vector = %d\n", vector); + exit(-1); + } + code = mbMotionVectorTable[vector + 16][0]; + num = mbMotionVectorTable[vector + 16][1]; + + Bitio_Write(bbPtr, code, num); +} + + +/*===========================================================================* + * + * GenBlockPattern + * + * generate macroblock pattern output + * append result to the specified bitstream + * + * RETURNS: nothing + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +static void +GenBlockPattern(bbPtr, mb_pattern) + BitBucket *bbPtr; + uint32 mb_pattern; +{ + uint32 code, num; + + code = mbPatTable[mb_pattern][0]; + num = mbPatTable[mb_pattern][1]; + + Bitio_Write(bbPtr, code, num); +} + + +/*===========================================================================* + * + * GenMBAddrIncr + * + * generate macroblock address increment output + * append result to the specified bitstream + * + * RETURNS: nothing + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +static void +GenMBAddrIncr(bbPtr, addr_incr) + BitBucket *bbPtr; + uint32 addr_incr; +{ + uint32 code; + uint32 num; + + code = mbAddrIncrTable[addr_incr][0]; + num = mbAddrIncrTable[addr_incr][1]; + + Bitio_Write(bbPtr, code, num); +} + + +/*===========================================================================* + * + * GenPictHead + * + * generate picture header with given attributes + * append result to the specified bitstream + * + * RETURNS: nothing + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +static void +GenPictHead(bbPtr, temp_ref, code_type, vbv_delay, full_pel_forw_flag, + forw_f_code, full_pel_back_flag, back_f_code, extra_info, + extra_info_size, ext_data, ext_data_size, user_data, + user_data_size) + BitBucket *bbPtr; + uint32 temp_ref; + uint32 code_type; + uint32 vbv_delay; + int32 full_pel_forw_flag; + uint32 forw_f_code; + int32 full_pel_back_flag; + uint32 back_f_code; + uint8 *extra_info; + uint32 extra_info_size; + uint8 *ext_data; + uint32 ext_data_size; + uint8 *user_data; + uint32 user_data_size; +{ + /* Write picture start code. */ + Bitio_Write(bbPtr, PICT_START_CODE, 32); + + /* Temp reference. */ + Bitio_Write(bbPtr, temp_ref, 10); + + /* Code_type. */ + if (code_type == 0) + code_type = 1; + + Bitio_Write(bbPtr, code_type, 3); + + /* vbv_delay. */ + vbv_delay = 0xffff; /* see page 36 (section 2.4.3.4) */ + Bitio_Write(bbPtr, vbv_delay, 16); + + if ((code_type == 2) || (code_type == 3)) { + + /* Full pel forw flag. */ + + if (full_pel_forw_flag) + Bitio_Write(bbPtr, 0x01, 1); + else + Bitio_Write(bbPtr, 0x00, 1); + + /* Forw f code. */ + + Bitio_Write(bbPtr, forw_f_code, 3); + } + if (code_type == 3) { + + /* Full pel back flag. */ + + if (full_pel_back_flag) + Bitio_Write(bbPtr, 0x01, 1); + else + Bitio_Write(bbPtr, 0x00, 1); + + /* Back f code. */ + + Bitio_Write(bbPtr, back_f_code, 3); + } + /* Extra bit picture info. */ + + if (extra_info != NULL) { + unsigned int i; + for (i = 0; i < extra_info_size; ++i) { + Bitio_Write(bbPtr, 0x01, 1); + Bitio_Write(bbPtr, extra_info[i], 8); + } + } + Bitio_Write(bbPtr, 0x00, 1); + + /* next start code */ + Bitio_BytePad(bbPtr); + + /* Write ext data if present. */ + + if (ext_data != NULL) { + unsigned int i; + + Bitio_Write(bbPtr, EXT_START_CODE, 32); + + for (i = 0; i < ext_data_size; ++i) + Bitio_Write(bbPtr, ext_data[i], 8); + Bitio_BytePad(bbPtr); + } + /* Write user data if present. */ + if (user_data != NULL) { + unsigned int i; + Bitio_Write(bbPtr, USER_START_CODE, 32); + + for (i = 0; i < user_data_size; ++i) + Bitio_Write(bbPtr, user_data[i], 8); + + Bitio_BytePad(bbPtr); + } +} /*=====================* @@ -767,7 +1093,8 @@ if ( addr_incr != 1 ) } /* Generate mb type code. */ - GenMBType(bbPtr, pict_code_type, mb_quant, motion_forw, motion_back, mb_pattern, mb_intra); + GenMBType(bbPtr, pict_code_type, mb_quant, + motion_forw, motion_back, mb_pattern, mb_intra); /* MB quant. */ if (mb_quant) { @@ -831,353 +1158,6 @@ if ( addr_incr != 1 ) } -/*=====================* - * INTERNAL PROCEDURES * - *=====================*/ - -/*===========================================================================* - * - * GenMBType - * - * generate macroblock type with given attributes - * append result to the specified bitstream - * - * RETURNS: nothing - * - * SIDE EFFECTS: none - * - *===========================================================================*/ -static void -GenMBType(bbPtr, pict_code_type, mb_quant, motion_forw, motion_back, - mb_pattern, mb_intra) - BitBucket *bbPtr; - uint32 pict_code_type; - uint32 mb_quant; - uint32 motion_forw; - uint32 motion_back; - uint32 mb_pattern; - uint32 mb_intra; -{ - int code; - - switch (pict_code_type) { - case 1: - if ((motion_forw != 0) || (motion_back != 0) || (mb_pattern != 0) || (mb_intra != 1)) { - perror("Illegal parameters for macroblock type."); - exit(-1); - } - if (mb_quant) { - Bitio_Write(bbPtr, 0x1, 2); - } else { - Bitio_Write(bbPtr, 0x1, 1); - } - break; - - case 2: - code = 0; - if (mb_quant) { - code += 16; - } - if (motion_forw) { - code += 8; - } - if (motion_back) { - code += 4; - } - if (mb_pattern) { - code += 2; - } - if (mb_intra) { - code += 1; - } - - switch (code) { - case 1: - Bitio_Write(bbPtr, 0x3, 5); - break; - case 2: - Bitio_Write(bbPtr, 0x1, 2); - break; - case 8: - Bitio_Write(bbPtr, 0x1, 3); - break; - case 10: - Bitio_Write(bbPtr, 0x1, 1); - break; - case 17: - Bitio_Write(bbPtr, 0x1, 6); - break; - case 18: - Bitio_Write(bbPtr, 0x1, 5); - break; - case 26: - Bitio_Write(bbPtr, 0x2, 5); - break; - default: - perror("Illegal parameters for macroblock type."); - exit(-1); - break; - } - break; - - case 3: - code = 0; - if (mb_quant) { - code += 16; - } - if (motion_forw) { - code += 8; - } - if (motion_back) { - code += 4; - } - if (mb_pattern) { - code += 2; - } - if (mb_intra) { - code += 1; - } - - switch (code) { - case 12: - Bitio_Write(bbPtr, 0x2, 2); - break; - case 14: - Bitio_Write(bbPtr, 0x3, 2); - break; - case 4: - Bitio_Write(bbPtr, 0x2, 3); - break; - case 6: - Bitio_Write(bbPtr, 0x3, 3); - break; - case 8: - Bitio_Write(bbPtr, 0x2, 4); - break; - case 10: - Bitio_Write(bbPtr, 0x3, 4); - break; - case 1: - Bitio_Write(bbPtr, 0x3, 5); - break; - case 30: - Bitio_Write(bbPtr, 0x2, 5); - break; - case 26: - Bitio_Write(bbPtr, 0x3, 6); - break; - case 22: - Bitio_Write(bbPtr, 0x2, 6); - break; - case 17: - Bitio_Write(bbPtr, 0x1, 6); - break; - default: - perror("Illegal parameters for macroblock type."); - exit(-1); - break; - } - break; - } -} - - -/*===========================================================================* - * - * GenMotionCode - * - * generate motion vector output with given value - * append result to the specified bitstream - * - * RETURNS: nothing - * - * SIDE EFFECTS: none - * - *===========================================================================*/ -static void -GenMotionCode(BitBucket * const bbPtr, - int32 const vector) { - - uint32 code, num; - - if ((vector < -16) || (vector > 16)) { - perror("Motion vector out of range."); - fprintf(stderr, "Motion vector out of range: vector = %d\n", vector); - exit(-1); - } - code = mbMotionVectorTable[vector + 16][0]; - num = mbMotionVectorTable[vector + 16][1]; - - Bitio_Write(bbPtr, code, num); -} - - -/*===========================================================================* - * - * GenBlockPattern - * - * generate macroblock pattern output - * append result to the specified bitstream - * - * RETURNS: nothing - * - * SIDE EFFECTS: none - * - *===========================================================================*/ -static void -GenBlockPattern(bbPtr, mb_pattern) - BitBucket *bbPtr; - uint32 mb_pattern; -{ - uint32 code, num; - - code = mbPatTable[mb_pattern][0]; - num = mbPatTable[mb_pattern][1]; - - Bitio_Write(bbPtr, code, num); -} - - -/*===========================================================================* - * - * GenMBAddrIncr - * - * generate macroblock address increment output - * append result to the specified bitstream - * - * RETURNS: nothing - * - * SIDE EFFECTS: none - * - *===========================================================================*/ -static void -GenMBAddrIncr(bbPtr, addr_incr) - BitBucket *bbPtr; - uint32 addr_incr; -{ - uint32 code; - uint32 num; - - code = mbAddrIncrTable[addr_incr][0]; - num = mbAddrIncrTable[addr_incr][1]; - - Bitio_Write(bbPtr, code, num); -} - - -/*===========================================================================* - * - * GenPictHead - * - * generate picture header with given attributes - * append result to the specified bitstream - * - * RETURNS: nothing - * - * SIDE EFFECTS: none - * - *===========================================================================*/ -static void -GenPictHead(bbPtr, temp_ref, code_type, vbv_delay, full_pel_forw_flag, - forw_f_code, full_pel_back_flag, back_f_code, extra_info, - extra_info_size, ext_data, ext_data_size, user_data, - user_data_size) - BitBucket *bbPtr; - uint32 temp_ref; - uint32 code_type; - uint32 vbv_delay; - int32 full_pel_forw_flag; - uint32 forw_f_code; - int32 full_pel_back_flag; - uint32 back_f_code; - uint8 *extra_info; - uint32 extra_info_size; - uint8 *ext_data; - uint32 ext_data_size; - uint8 *user_data; - uint32 user_data_size; -{ - int i; - - /* Write picture start code. */ - Bitio_Write(bbPtr, PICT_START_CODE, 32); - - /* Temp reference. */ - Bitio_Write(bbPtr, temp_ref, 10); - - /* Code_type. */ - if (code_type == 0) { - code_type = 1; - } - Bitio_Write(bbPtr, code_type, 3); - - /* vbv_delay. */ - vbv_delay = 0xffff; /* see page 36 (section 2.4.3.4) */ - Bitio_Write(bbPtr, vbv_delay, 16); - - if ((code_type == 2) || (code_type == 3)) { - - /* Full pel forw flag. */ - - if (full_pel_forw_flag) { - Bitio_Write(bbPtr, 0x01, 1); - } else { - Bitio_Write(bbPtr, 0x00, 1); - } - - /* Forw f code. */ - - Bitio_Write(bbPtr, forw_f_code, 3); - } - if (code_type == 3) { - - /* Full pel back flag. */ - - if (full_pel_back_flag) { - Bitio_Write(bbPtr, 0x01, 1); - } else { - Bitio_Write(bbPtr, 0x00, 1); - } - - /* Back f code. */ - - Bitio_Write(bbPtr, back_f_code, 3); - } - /* Extra bit picture info. */ - - if (extra_info != NULL) { - for (i = 0; i < extra_info_size; i++) { - Bitio_Write(bbPtr, 0x01, 1); - Bitio_Write(bbPtr, extra_info[i], 8); - } - } - Bitio_Write(bbPtr, 0x00, 1); - - /* next start code */ - Bitio_BytePad(bbPtr); - - /* Write ext data if present. */ - - if (ext_data != NULL) { - Bitio_Write(bbPtr, EXT_START_CODE, 32); - - for (i = 0; i < ext_data_size; i++) { - Bitio_Write(bbPtr, ext_data[i], 8); - } - Bitio_BytePad(bbPtr); - } - /* Write user data if present. */ - if (user_data != NULL) { - Bitio_Write(bbPtr, USER_START_CODE, 32); - - for (i = 0; i < user_data_size; i++) { - Bitio_Write(bbPtr, user_data[i], 8); - } - Bitio_BytePad(bbPtr); - } -} - - #ifdef UNUSED_PROCEDURES /* GenMBEnd only used for `D` pictures. Shouldn't really ever be called. */ diff --git a/converter/ppm/ppmtompeg/pframe.c b/converter/ppm/ppmtompeg/pframe.c index e72fe5d6..de91e32c 100644 --- a/converter/ppm/ppmtompeg/pframe.c +++ b/converter/ppm/ppmtompeg/pframe.c @@ -60,8 +60,6 @@ static int32 totalTime = 0; static int qscaleP; static float totalSNR = 0.0; static float totalPSNR = 0.0; -extern Block **dct, **dctr, **dctb; -extern dct_data_type **dct_data; /*=====================* * INTERNAL PROCEDURES * diff --git a/converter/ppm/ppmtompeg/psearch.c b/converter/ppm/ppmtompeg/psearch.c index aea1a29b..83c62d04 100644 --- a/converter/ppm/ppmtompeg/psearch.c +++ b/converter/ppm/ppmtompeg/psearch.c @@ -16,6 +16,8 @@ #include "prototypes.h" #include "fsize.h" #include "param.h" +#include "subsample.h" +#include "block.h" /*==================* diff --git a/converter/ppm/ppmtompeg/subsample.c b/converter/ppm/ppmtompeg/subsample.c index 5ec71814..69401a1d 100644 --- a/converter/ppm/ppmtompeg/subsample.c +++ b/converter/ppm/ppmtompeg/subsample.c @@ -43,6 +43,7 @@ #include "bitio.h" #include "prototypes.h" +#include "subsample.h" static void diff --git a/converter/ppm/sldtoppm.c b/converter/ppm/sldtoppm.c index 7da6d592..e0760448 100644 --- a/converter/ppm/sldtoppm.c +++ b/converter/ppm/sldtoppm.c @@ -66,15 +66,9 @@ struct svector { struct spoint t; /* To point */ }; -static int extend ARGS((smallint ch)); -static int sli ARGS((void)); -static int slib ARGS((void)); -static void vscale ARGS((int *px, int *py)); -static void slider ARGS((void (*slvec) ARGS((struct svector *vec, int color)), - void (*slflood) ARGS((struct spolygon *poly, int color)) )); -static void slidefind ARGS((char *sname, int dironly, int ucasen)); -static void draw ARGS((struct svector *vec, int color)); -static void flood ARGS((struct spolygon *poly, int color)); +typedef void (slvecfn)(struct svector * vec, int color); +typedef void (slfloodfn)(struct spolygon * poly, int color); + static int ixdots, iydots; /* Screen size in dots */ static FILE *slfile; /* Slide file descriptor */ @@ -104,21 +98,26 @@ static int adjust = FALSE; /* Adjust to correct aspect ratio ? */ static struct slhead slfrof; /* Slide file header */ static long xfac, yfac; /* Aspect ratio scale factors */ -static int sdrawkcab; /* Slide drawing kinematic conversion of - ass-backwards data flag */ +static int sdrawkcab; + /* Slide drawing kinematic conversion of ass-backwards data flag */ + + /* EXTEND -- Turn a smallint into an int with sign extension, whether - or not that happens automatically. */ + or not that happens automatically. +*/ -static int extend(smallint ch) -{ +static int +extend(smallint ch) { return ((int) ((ch & 0x80) ? (ch | ~0xFF) : ch)); } + + /* SLI -- Input word from slide file */ -static int sli() -{ +static int +sli(void) { short wd; if (fread(&wd, sizeof wd, 1, slfile) != 1) { @@ -131,10 +130,12 @@ static int sli() return wd; } + + /* SLIB -- Input byte from slide file */ -static int slib() -{ +static int +slib(void) { smallint ch = 0; if (fread(&ch, sizeof ch, 1, slfile) != 1) { @@ -143,25 +144,171 @@ static int slib() return extend(ch); } + + /* VSCALE -- scale screen coordinates for mismatched display. */ -static void vscale(px, py) - int *px, *py; -{ +static void +vscale(int * const px, + int * const py) { + *px = (((unsigned) *px) * xfac) >> 16; *py = (((unsigned) *py) * yfac) >> 16; } + + +/* SLIDEFIND -- Find a slide in a library or, if DIRONLY is + nonzero, print a directory listing of the library. + If UCASEN is nonzero, the requested slide name is + converted to upper case. */ + +static void +slidefind(const char * const sname, + bool const dironly, + bool const ucasen) { + + char uname[32]; + unsigned char libent[36]; + long pos; + + if (dironly) + pm_message("Slides in library:"); + else { + int i; + const char * ip; + + ip = sname; /* initial value */ + + for (i = 0; i < 31; i++) { + char ch = *ip++; + if (ch == EOS) + break; + if (ucasen && ISLOWER(ch)) + ch = TOUPPER(ch); + uname[i] = ch; + } + uname[i] = EOS; + } + + /* Read slide library header and verify. */ + + if ((fread(libent, 32, 1, slfile) != 1) || + (!STREQ((char *)libent, "AutoCAD Slide Library 1.0\015\012\32"))) { + pm_error("not an AutoCAD slide library file."); + } + pos = 32; + + /* Search for a slide with the requested name. */ + + while (TRUE) { + if ((fread(libent, 36, 1, slfile) != 1) || + (strlen((char *)libent) == 0)) { + if (dironly) { + return; + } + pm_error("slide %s not in library.", sname); + } + pos += 36; + if (dironly) { + pm_message(" %s", libent); + } else if (STREQ((char *)libent, uname)) { + long dpos = (((((libent[35] << 8) | libent[34]) << 8) | + libent[33]) << 8) | libent[32]; + if ((slfile == stdin) || (fseek(slfile, dpos, 0) == -1)) { + dpos -= pos; + + while (dpos-- > 0) + getc(slfile); + } + break; + } + } +} + + + +/* DRAW -- Draw a vector in the given AutoCAD color. */ + +static slvecfn draw; + +static void +draw(struct svector * vec, + int color) { + + pixel rgbcolor; + + if (blither) { + pm_message("Vector (%d, %d) - (%d, %d) Color %d", + vec->f.x, vec->f.y, vec->t.x, vec->t.y, color); + } + assert(vec->f.x >= 0 && vec->f.x < pixcols); + assert(vec->f.y >= 0 && vec->f.y < pixrows); + assert(vec->t.x >= 0 && vec->t.x < pixcols); + assert(vec->t.y >= 0 && vec->t.y < pixrows); + PPM_ASSIGN(rgbcolor, + acadcol[color][0], acadcol[color][1], acadcol[color][2]); + ppmd_line(pixels, pixcols, pixrows, pixmaxval, + vec->f.x, iydots - vec->f.y, vec->t.x, iydots - vec->t.y, + PPMD_NULLDRAWPROC, + (char *) &rgbcolor); +} + + + +/* FLOOD -- Draw a filled polygon. */ + +static slfloodfn flood; + +static void +flood(struct spolygon * const poly, + int const color) { + + unsigned int i; + struct fillobj * handle; + pixel rgbcolor; + + handle = ppmd_fill_create(); + + if (blither) { + unsigned int i; + pm_message("Polygon: %d points, fill type %d, color %d", + poly->npoints, poly->fill, color); + for (i = 0; i < poly->npoints; i++) { + pm_message(" Point %d: (%d, %d)", i + 1, + poly->pt[i].x, poly->pt[i].y); + } + } + + PPM_ASSIGN(rgbcolor, + acadcol[color][0], acadcol[color][1], acadcol[color][2]); + for (i = 0; i < poly->npoints; i++) { + assert(poly->pt[i].x >= 0 && poly->pt[i].x < pixcols); + assert(poly->pt[i].y >= 0 && poly->pt[i].y < pixrows); + ppmd_line(pixels, pixcols, pixrows, pixmaxval, + poly->pt[i].x, iydots - poly->pt[i].y, + poly->pt[(i + 1) % poly->npoints].x, + iydots - poly->pt[(i + 1) % poly->npoints].y, + ppmd_fill_drawproc, handle); + } + ppmd_fill(pixels, pixcols, pixrows, pixmaxval, + handle, PPMD_NULLDRAWPROC, (char *) &rgbcolor); + + ppmd_fill_destroy(handle); +} + + + /* SLIDER -- Read slide file. This is called with the name of the file to be read and function pointers to the routines which process vectors and polygon fill requests respectively. */ -static void slider(slvec, slflood) - void (*slvec) ARGS((struct svector *vec, int color)); - void (*slflood) ARGS((struct spolygon *poly, int color)); -{ +static void +slider(slvecfn slvec, + slfloodfn slflood) { + int i, rescale; unsigned char ubfr[4]; /* Utility character buffer */ int lx, ly; /* Last x and y point */ @@ -174,14 +321,14 @@ static void slider(slvec, slflood) short rtest; /* Value to test byte reversal */ short btest = 0x1234; /* Value to test byte-reversal */ static struct slhead slhi = /* Master slide header sample */ - {"AutoCAD Slide\r\n\32", 86,2, 0,0, 0.0, 0}; + {"AutoCAD Slide\r\n\32", 86,2, 0,0, 0.0, 0}; int curcolor = 7; /* Current vector color */ pixel rgbcolor; /* Pixel used to clear pixmap */ - + lx = ly = 32000; - + /* Process the header of the slide file. */ - + sdrawkcab = FALSE; /* Initially guess byte order is OK */ fread(slfrof.slh, 17, 1, slfile); fread(&slfrof.sntype, sizeof(char), 1, slfile); @@ -194,48 +341,46 @@ static void slider(slvec, slflood) /* Verify that slide format is compatible with this program. */ - if (STREQ(slfrof.slh, slhi.slh)) { + if (STREQ(slfrof.slh, slhi.slh)) pm_error("this is not an AutoCAD slide file."); - } /* Verify that the number format and file level in the header are compatible. All slides written by versions of AutoCAD released since September of 1987 are compatible with this format. */ - if ((slfrof.sntype != slhi.sntype) || (slfrof.slevel != slhi.slevel)) { + if ((slfrof.sntype != slhi.sntype) || (slfrof.slevel != slhi.slevel)) pm_error("incompatible slide file format"); - } /* Build SDSAR value from long scaled version. */ - + ldsar = 0L; - for (i = 3; i >= 0; i--) { - ldsar = (ldsar << 8) | ubfr[i]; - } + for (i = 3; i >= 0; --i) + ldsar = (ldsar << 8) | ubfr[i]; slfrof.sdsar = ((double) ldsar) / 1E7; - + /* Examine the byte order test value. If it's backwards, set the byte-reversal flag and correct all of the values we've read in - so far. */ + so far. + */ if (btest != rtest) { - sdrawkcab = TRUE; + sdrawkcab = TRUE; #define rshort(x) x = ((x >> 8) & 0xFF) | (x << 8) - rshort(slfrof.sxdots); - rshort(slfrof.sydots); - rshort(slfrof.shwfill); + rshort(slfrof.sxdots); + rshort(slfrof.sydots); + rshort(slfrof.shwfill); #undef rshort } - + /* Dump the header if we're blithering. */ if (blither || info) { pm_message("Slide file type %d, level %d, hwfill type %d.", - slfrof.sntype, slfrof.slevel, slfrof.shwfill); + slfrof.sntype, slfrof.slevel, slfrof.shwfill); pm_message("Original screen size %dx%d, aspect ratio %.3f.", - slfrof.sxdots + 1, slfrof.sydots + 1, slfrof.sdsar); + slfrof.sxdots + 1, slfrof.sydots + 1, slfrof.sdsar); pm_message("Byte order is %s.", - sdrawkcab ? "being reversed" : "the same"); + sdrawkcab ? "being reversed" : "the same"); } /* If the display aspect ratio indicates that the pixels on the @@ -246,405 +391,284 @@ static void slider(slvec, slflood) We always correct the aspect ratio by adjusting the width of the image. This guarantees that output from the SHADE command, which is essentially scan-line data written in vector form, - will not be corrupted. */ + will not be corrupted. + */ dsar = ((double) slfrof.sxdots) / slfrof.sydots; if (fabs(slfrof.sdsar - dsar) > 0.0001) { - if (adjust) { - ixdots = slfrof.sxdots * (slfrof.sdsar / dsar) + 0.5; - iydots = slfrof.sydots; - dsar = ((double) ixdots) / iydots; + if (adjust) { + ixdots = slfrof.sxdots * (slfrof.sdsar / dsar) + 0.5; + iydots = slfrof.sydots; + dsar = ((double) ixdots) / iydots; + } else { + pm_message("Warning - pixels on source screen were non-square. " + "Specifying -adjust will correct image width " + "to compensate."); + ixdots = slfrof.sxdots; + iydots = slfrof.sydots; + dsar = slfrof.sdsar; + } } else { - pm_message("Warning - pixels on source screen were non-square."); - pm_message(" Specifying -adjust will correct image width to compensate."); + /* Source pixels were square. */ ixdots = slfrof.sxdots; iydots = slfrof.sydots; dsar = slfrof.sdsar; - } - } else { - /* Source pixels were square. */ - ixdots = slfrof.sxdots; - iydots = slfrof.sydots; - dsar = slfrof.sdsar; - adjust = FALSE; /* Mark no adjustment needed */ + adjust = FALSE; /* Mark no adjustment needed */ } /* If there's a uniform scale factor specified, apply it. */ if (uscale > 0) { - ixdots = (ixdots * uscale) + 0.5; - iydots = (iydots * uscale) + 0.5; + ixdots = (ixdots * uscale) + 0.5; + iydots = (iydots * uscale) + 0.5; } /* If the image is to be stretched to a given width, set the output image sizes accordingly. If only a height or width is given, scale the other direction proportionally to preserve the - aspect ratio. */ + aspect ratio. + */ if (sxsize > 0) { - if (sysize > 0) { - iydots = sysize - 1; - } else { - iydots = ((((long) iydots) * (sxsize - 1)) + - (iydots / 2)) / ixdots; - } - ixdots = sxsize - 1; - } else if (sysize > 0) { - if (sxsize > 0) { + if (sysize > 0) { + iydots = sysize - 1; + } else { + iydots = ((((long) iydots) * (sxsize - 1)) + + (iydots / 2)) / ixdots; + } ixdots = sxsize - 1; - } else { - ixdots = ((((long) ixdots) * (sysize - 1)) + - (ixdots / 2)) / iydots; - } - iydots = sysize - 1; + } else if (sysize > 0) { + if (sxsize > 0) { + ixdots = sxsize - 1; + } else { + ixdots = ((((long) ixdots) * (sysize - 1)) + + (ixdots / 2)) / iydots; + } + iydots = sysize - 1; } - + if (adjust) { - pm_message( + pm_message( "Resized from %dx%d to %dx%d to correct pixel aspect ratio.", - slfrof.sxdots + 1, slfrof.sydots + 1, ixdots + 1, iydots + 1); + slfrof.sxdots + 1, slfrof.sydots + 1, ixdots + 1, iydots + 1); } - + /* Allocate image buffer and clear it to black. */ - + pixels = ppm_allocarray(pixcols = ixdots + 1, pixrows = iydots + 1); PPM_ASSIGN(rgbcolor, 0, 0, 0); ppmd_filledrectangle(pixels, pixcols, pixrows, pixmaxval, 0, 0, pixcols, pixrows, PPMD_NULLDRAWPROC, (char *) &rgbcolor); - + if ((rescale = slfrof.sxdots != ixdots || - slfrof.sydots != iydots || - slfrof.sdsar != dsar) != 0) { - + slfrof.sydots != iydots || + slfrof.sdsar != dsar) != 0) { + /* Rescale all coords. so they'll look (more or less) - right on this display. */ - - xfac = (ixdots + 1) * 0x10000L; - xfac /= (long) (slfrof.sxdots + 1); - yfac = (iydots + 1) * 0x10000L; - yfac /= (long) (slfrof.sydots + 1); - if (dsar < slfrof.sdsar) { - yfac = yfac * dsar / slfrof.sdsar; - } else { - xfac = xfac * slfrof.sdsar / dsar; - } + right on this display. + */ + + xfac = (ixdots + 1) * 0x10000L; + xfac /= (long) (slfrof.sxdots + 1); + yfac = (iydots + 1) * 0x10000L; + yfac /= (long) (slfrof.sydots + 1); + if (dsar < slfrof.sdsar) { + yfac = yfac * dsar / slfrof.sdsar; + } else { + xfac = xfac * slfrof.sdsar / dsar; + } } poly.npoints = 0; /* No flood in progress. */ - + while ((cw = sli()) != 0xFC00) { - switch (cw & 0xFF00) { + switch (cw & 0xFF00) { case 0xFB00: /* Short vector compressed */ - vec.f.x = lx + extend(cw & 0xFF); - vec.f.y = ly + slib(); - vec.t.x = lx + slib(); - vec.t.y = ly + slib(); - lx = vec.f.x; - ly = vec.f.y; - if (rescale) { - vscale(&vec.f.x, &vec.f.y); - vscale(&vec.t.x, &vec.t.y); - } - (*slvec)(&vec, curcolor);/* Draw vector on screen */ - slx = vec.f.x; /* Save scaled point */ - sly = vec.f.y; - break; - + vec.f.x = lx + extend(cw & 0xFF); + vec.f.y = ly + slib(); + vec.t.x = lx + slib(); + vec.t.y = ly + slib(); + lx = vec.f.x; + ly = vec.f.y; + if (rescale) { + vscale(&vec.f.x, &vec.f.y); + vscale(&vec.t.x, &vec.t.y); + } + (*slvec)(&vec, curcolor);/* Draw vector on screen */ + slx = vec.f.x; /* Save scaled point */ + sly = vec.f.y; + break; + case 0xFC00: /* End of file */ - break; - + break; + case 0xFD00: /* Flood command */ - vec.f.x = sli(); - vec.f.y = sli(); - if ((int) vec.f.y < 0) { /* start or end */ - if (poly.npoints != 0) { /* end? */ - if (poly.npoints > 2 && poly.npoints < 11) { - (*slflood)(&poly, curcolor); - } else { - pm_error("Bad polygon vertex count (%d)", - poly.npoints); - } - poly.npoints = 0; - } else { - poly.fill = -vec.f.y; /* Start */ + vec.f.x = sli(); + vec.f.y = sli(); + if ((int) vec.f.y < 0) { /* start or end */ + if (poly.npoints != 0) { /* end? */ + if (poly.npoints > 2 && poly.npoints < 11) { + (*slflood)(&poly, curcolor); + } else { + pm_error("Bad polygon vertex count (%d)", + poly.npoints); + } + poly.npoints = 0; + } else { + poly.fill = -vec.f.y; /* Start */ + } + } else { /* Polygon vertex */ + if (poly.npoints < 10) { + if (rescale) { + vscale(&vec.f.x, &vec.f.y); + } + poly.pt[poly.npoints].x = vec.f.x; + poly.pt[poly.npoints].y = vec.f.y; + } + poly.npoints++; } - } else { /* Polygon vertex */ - if (poly.npoints < 10) { + break; + + case 0xFE00: /* Common endpoint compressed */ + vec.f.x = lx + extend(cw & 0xFF); + vec.f.y = ly + slib(); + lx = vec.f.x; + ly = vec.f.y; + vec.t.x = slx; + vec.t.y = sly; if (rescale) { vscale(&vec.f.x, &vec.f.y); } - poly.pt[poly.npoints].x = vec.f.x; - poly.pt[poly.npoints].y = vec.f.y; - } - poly.npoints++; - } - break; - - case 0xFE00: /* Common endpoint compressed */ - vec.f.x = lx + extend(cw & 0xFF); - vec.f.y = ly + slib(); - lx = vec.f.x; - ly = vec.f.y; - vec.t.x = slx; - vec.t.y = sly; - if (rescale) { - vscale(&vec.f.x, &vec.f.y); - } - (*slvec)(&vec, curcolor);/* Draw vector */ - slx = vec.f.x; /* Save scaled point */ - sly = vec.f.y; - break; - + (*slvec)(&vec, curcolor);/* Draw vector */ + slx = vec.f.x; /* Save scaled point */ + sly = vec.f.y; + break; + case 0xFF00: /* Change color */ - curcolor = cw & 0xFF; - break; + curcolor = cw & 0xFF; + break; default: /* Co-ordinates */ - lx = vec.f.x = cw; - ly = vec.f.y = sli(); - vec.t.x = sli(); - vec.t.y = sli(); - if (rescale) { - vscale(&vec.f.x, &vec.f.y); - vscale(&vec.t.x, &vec.t.y); - } - (*slvec)(&vec, curcolor); - slx = vec.f.x; /* Save scaled point */ - sly = vec.f.y; - break; - } - } -} - -/* SLIDEFIND -- Find a slide in a library or, if DIRONLY is - nonzero, print a directory listing of the library. - If UCASEN is nonzero, the requested slide name is - converted to upper case. */ - -static void slidefind(sname, dironly, ucasen) - char *sname; - int dironly, ucasen; -{ - char uname[32]; - unsigned char libent[36]; - long pos; - - if (dironly) { - pm_message("Slides in library:"); - } else { - int i; - char *ip = sname; - - for (i = 0; i < 31; i++) { - char ch = *ip++; - if (ch == EOS) { - break; - } - if (ucasen && ISLOWER(ch)) { - ch = TOUPPER(ch); - } - uname[i] = ch; - } - uname[i] = EOS; - } - - /* Read slide library header and verify. */ - - if ((fread(libent, 32, 1, slfile) != 1) || - (!STREQ((char *)libent, "AutoCAD Slide Library 1.0\015\012\32"))) { - pm_error("not an AutoCAD slide library file."); - } - pos = 32; - - /* Search for a slide with the requested name. */ - - while (TRUE) { - if ((fread(libent, 36, 1, slfile) != 1) || - (strlen((char *)libent) == 0)) { - if (dironly) { - return; - } - pm_error("slide %s not in library.", sname); - } - pos += 36; - if (dironly) { - pm_message(" %s", libent); - } else if (STREQ((char *)libent, uname)) { - long dpos = (((((libent[35] << 8) | libent[34]) << 8) | - libent[33]) << 8) | libent[32]; - if ((slfile == stdin) || (fseek(slfile, dpos, 0) == -1)) { - dpos -= pos; - - while (dpos-- > 0) { - (void) getc(slfile); - } + lx = vec.f.x = cw; + ly = vec.f.y = sli(); + vec.t.x = sli(); + vec.t.y = sli(); + if (rescale) { + vscale(&vec.f.x, &vec.f.y); + vscale(&vec.t.x, &vec.t.y); + } + (*slvec)(&vec, curcolor); + slx = vec.f.x; /* Save scaled point */ + sly = vec.f.y; + break; } - break; - } } } -/* DRAW -- Draw a vector in the given AutoCAD color. */ -static void draw(vec, color) - struct svector *vec; - int color; -{ - pixel rgbcolor; - - if (blither) { - pm_message("Vector (%d, %d) - (%d, %d) Color %d", - vec->f.x, vec->f.y, vec->t.x, vec->t.y, color); - } - assert(vec->f.x >= 0 && vec->f.x < pixcols); - assert(vec->f.y >= 0 && vec->f.y < pixrows); - assert(vec->t.x >= 0 && vec->t.x < pixcols); - assert(vec->t.y >= 0 && vec->t.y < pixrows); - PPM_ASSIGN(rgbcolor, - acadcol[color][0], acadcol[color][1], acadcol[color][2]); - ppmd_line(pixels, pixcols, pixrows, pixmaxval, - vec->f.x, iydots - vec->f.y, vec->t.x, iydots - vec->t.y, - PPMD_NULLDRAWPROC, - (char *) &rgbcolor); -} - -/* FLOOD -- Draw a filled polygon. */ - -static void -flood(struct spolygon * const poly, - int const color) { - - int i; - struct fillobj * handle; - pixel rgbcolor; - - handle = ppmd_fill_create(); - - if (blither) { - pm_message("Polygon: %d points, fill type %d, color %d", - poly->npoints, poly->fill, color); - for (i = 0; i < poly->npoints; i++) { - pm_message(" Point %d: (%d, %d)", i + 1, - poly->pt[i].x, poly->pt[i].y); - } - } - - PPM_ASSIGN(rgbcolor, - acadcol[color][0], acadcol[color][1], acadcol[color][2]); - for (i = 0; i < poly->npoints; i++) { - assert(poly->pt[i].x >= 0 && poly->pt[i].x < pixcols); - assert(poly->pt[i].y >= 0 && poly->pt[i].y < pixrows); - ppmd_line(pixels, pixcols, pixrows, pixmaxval, - poly->pt[i].x, iydots - poly->pt[i].y, - poly->pt[(i + 1) % poly->npoints].x, - iydots - poly->pt[(i + 1) % poly->npoints].y, - ppmd_fill_drawproc, handle); - } - ppmd_fill(pixels, pixcols, pixrows, pixmaxval, - handle, PPMD_NULLDRAWPROC, (char *) &rgbcolor); - - ppmd_fill_destroy(handle); -} /* Main program. */ -int main(argc, argv) - int argc; - char *argv[]; -{ +int +main(int argc, + char * argv[]) { + int argn; const char * const usage = "[-verbose] [-info] [-adjust] [-scale <s>]\n\ - [-dir] [-lib|-Lib <name>]\n\ - [-xsize|-width <x>] [-ysize|-height <y>] [sldfile]"; +[-dir] [-lib|-Lib <name>]\n\ +[-xsize|-width <x>] [-ysize|-height <y>] [sldfile]"; int scalespec = FALSE, widspec = FALSE, hgtspec = FALSE, dironly = FALSE, - ucasen; - char *slobber = (char *) 0; /* Slide library item */ + ucasen; + const char * slobber; /* Slide library item */ + slobber = NULL; + ppm_init(&argc, argv); argn = 1; while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') { if (pm_keymatch(argv[argn], "-verbose", 2)) { - blither = TRUE; + blither = TRUE; } else if (pm_keymatch(argv[argn], "-adjust", 2)) { - adjust = TRUE; + adjust = TRUE; } else if (pm_keymatch(argv[argn], "-dir", 2)) { - dironly = TRUE; + dironly = TRUE; } else if (pm_keymatch(argv[argn], "-info", 2)) { - info = TRUE; + info = TRUE; } else if (pm_keymatch(argv[argn], "-lib", 2)) { - if (slobber != (char *) 0) { + if (slobber) pm_error("already specified a library item"); - } ucasen = argv[argn][1] != 'L'; - argn++; - if (argn == argc) { - pm_usage(usage); - } - slobber = argv[argn]; + argn++; + if (argn == argc) { + pm_usage(usage); + } + slobber = argv[argn]; } else if (pm_keymatch(argv[argn], "-scale", 2)) { - if (scalespec) { + if (scalespec) { pm_error("already specified a scale factor"); - } - argn++; + } + argn++; if ((argn == argc) || (sscanf(argv[argn], "%lf", &uscale) != 1)) - pm_usage(usage); - if (uscale <= 0.0) { + pm_usage(usage); + if (uscale <= 0.0) { pm_error("scale factor must be greater than 0"); - } - scalespec = TRUE; + } + scalespec = TRUE; } else if (pm_keymatch(argv[argn], "-xsize", 2) || pm_keymatch(argv[argn], "-width", 2)) { - if (widspec) { + if (widspec) { pm_error("already specified a width/xsize"); - } - argn++; + } + argn++; if ((argn == argc) || (sscanf(argv[argn], "%d", &sxsize) != 1)) - pm_usage(usage); - widspec = TRUE; + pm_usage(usage); + widspec = TRUE; } else if (pm_keymatch(argv[argn], "-ysize", 2) || pm_keymatch(argv[argn], "-height", 2)) { - if (hgtspec) { + if (hgtspec) { pm_error("already specified a height/ysize"); + } + argn++; + if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1)) + pm_usage(usage); + hgtspec = TRUE; + } else { + pm_usage(usage); } argn++; - if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1)) - pm_usage(usage); - hgtspec = TRUE; - } else { - pm_usage(usage); - } - argn++; } /* If a file name is specified, open it. Otherwise read from - standard input. */ + standard input. + */ if (argn < argc) { - slfile = pm_openr(argv[argn]); - argn++; + slfile = pm_openr(argv[argn]); + argn++; } else { - slfile = stdin; + slfile = stdin; } - + if (argn != argc) { /* Extra bogus arguments ? */ - pm_usage(usage); + pm_usage(usage); } - + /* If we're extracting an item from a slide library, position the - input stream to the start of the chosen slide. */ - - if (dironly || (slobber != (char *) 0)) { - slidefind(slobber, dironly, ucasen); - } - + input stream to the start of the chosen slide. + */ + + if (dironly || slobber) + slidefind(slobber, dironly, ucasen); + if (!dironly) { - slider(draw, flood); - ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, FALSE); + slider(draw, flood); + ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, FALSE); } pm_close(slfile); pm_close(stdout); - exit(0); + + return 0; } diff --git a/lib/pm.h b/lib/pm.h index 696d763c..3850943c 100644 --- a/lib/pm.h +++ b/lib/pm.h @@ -65,7 +65,7 @@ extern "C" { #ifdef __GNUC__ #define PM_GNU_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) #else -#define PM_GNU_PRINTF_ATTR +#define PM_GNU_PRINTF_ATTR(a,b) #endif diff --git a/lib/ppmdraw.h b/lib/ppmdraw.h index 9efe51b9..a3c4f831 100644 --- a/lib/ppmdraw.h +++ b/lib/ppmdraw.h @@ -265,17 +265,17 @@ ppmd_fill(pixel ** const pixels, /* Text drawing routines. */ void -ppmd_text(pixel** const pixels, - int const cols, - int const rows, - pixval const maxval, - int const xpos, - int const ypos, - int const height, - int const angle, - const char * const sArg, - void (*drawprocP)(pixel**, int, int, pixval, int, int, const void*), - const void* const clientdata); +ppmd_text(pixel** const pixels, + int const cols, + int const rows, + pixval const maxval, + int const xpos, + int const ypos, + int const height, + int const angle, + const char * const sArg, + ppmd_drawproc drawProc, + const void * const clientdata); /* Draws the null-terminated string 's' left justified at the point ('x', 'y'). The text will be 'height' pixels high and will be aligned on a baseline inclined 'angle' degrees with the X axis. The supplied |