/* Copyright (c) 2000-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file b2tool1.c Tool functions. */ /** Inside the b2tool1.c module. */ #define B2TOOL1_C 1 #include "bmepsi.h" $(trace-include) /** Find out how to handle image size. @param bj Bmeps job. @return 0= use width and height as is, 1= use pHY chunk (resolution chunk) in image, 2= use specified media size. */ int bmeps_tool_how_to_handle_bb DK_P1(BJ *,bj) { int back = 0; $? "+ how_to_handle_bb" if(((bj->bo)->opt) & BMEPS_OPT_PAPER_SIZE) { back = 2; $? ". paper size specified" } else { if(((bj->bo)->opt) & BMEPS_OPT_RESOLUTION) { back = 1; $? ". resolution specified" } } $? "- how_to_handle_bb %d", back return back; } /** Initialize areas. @param bj Bmeps job. */ static void initialize_areas DK_P1(BJ *,bj) { (bj->trans).must_rotate = 0; (bj->trans).must_scale = 0; (bj->trans).sfx = 1.0; (bj->trans).sfy = 1.0; (bj->trans).hrbb.x0 = 0.0; (bj->trans).hrbb.x1 = 0.0; (bj->trans).hrbb.y0 = 0.0; (bj->trans).hrbb.y1 = 0.0; (bj->trans).ia.x0 = 0.0; (bj->trans).ia.x1 = 0.0; (bj->trans).ia.y0 = 0.0; (bj->trans).ia.y1 = 0.0; (bj->trans).iu.x0 = 0.0; (bj->trans).iu.x1 = 0.0; (bj->trans).iu.y0 = 0.0; (bj->trans).iu.y1 = 0.0; (bj->trans).bb.x0 = 0UL; (bj->trans).bb.x1 = 0UL; (bj->trans).bb.y0 = 0UL; (bj->trans).bb.y1 = 0UL; } /** Get bounding box from a named paper size. @param bj Bmeps job. */ static void bb_from_paper_size DK_P1(BJ *,bj) { unsigned long w, h, rotw, roth; double dw, dh, deltax, deltay, usedx, usedy; int me = 0; $? "+ bb_from_paper_size" /* available page range */ (bj->trans).hrbb.x0 = ((bj->bo)->ms).px0; (bj->trans).hrbb.x1 = ((bj->bo)->ms).px1; (bj->trans).hrbb.y0 = ((bj->bo)->ms).py0; (bj->trans).hrbb.y1 = ((bj->bo)->ms).py1; /* page range allowed for image placement */ (bj->trans).ia.x0 = ((bj->bo)->ms).bx0; (bj->trans).ia.x1 = ((bj->bo)->ms).bx1; (bj->trans).ia.y0 = ((bj->bo)->ms).by0; (bj->trans).ia.y1 = ((bj->bo)->ms).by1; /* page range used for image placement, rot, scale */ deltax = dkma_sub_double_ok( (bj->trans).ia.x1, (bj->trans).ia.x0, &me ); deltay = dkma_sub_double_ok( (bj->trans).ia.y1, (bj->trans).ia.y0, &me ); /* deltax = fabs(deltax); deltay = fabs(deltay); */ w = dkbif_get_width(bj->bif); h = dkbif_get_height(bj->bif); rotw = w; roth = h; dw = dkma_ul_to_double(w); dh = dkma_ul_to_double(h); $? ". w=%lu h=%lu", w, h $? ". deltax=%lg deltay=%lg", deltax, deltay if(w > h) { if(deltay > deltax) { (bj->trans).must_rotate = 1; $? ". must_rotate (1)" } } else { if(w < h) { if(deltay < deltax) { (bj->trans).must_rotate = 1; $? ". must_rotate (2)" } } } if((bj->trans).must_rotate) { $? ". must_rotate" rotw = h; roth = w; } dw = dkma_ul_to_double(rotw); $? ". dw = %lg", dw dh = dkma_ul_to_double(roth); $? ". dh = %lg", dh (bj->trans).sfx = dkma_div_double_ok(deltax, rotw, &me); (bj->trans).sfy = dkma_div_double_ok(deltay, roth, &me); $? ". sfx = %lg sfy = %lg", (bj->trans).sfx, (bj->trans).sfy (bj->trans).sfx = dkma_double_restrict_downwards((bj->trans).sfx, 3); (bj->trans).sfy = dkma_double_restrict_downwards((bj->trans).sfy, 3); $? ". sfx = %lg sfy = %lg", (bj->trans).sfx, (bj->trans).sfy if((bj->trans).sfx > (bj->trans).sfy) { $? ". decrease sfx" (bj->trans).sfx = (bj->trans).sfy; } else { $? ". decrease sfy" (bj->trans).sfy = (bj->trans).sfx; } $? ". sfx = %lg sfy = %lg", (bj->trans).sfx, (bj->trans).sfy usedx = dkma_mul_double_ok(dw, (bj->trans).sfx, &me); usedy = dkma_mul_double_ok(dh, (bj->trans).sfy, &me); /* correct mathematical problem */ if(usedx > deltax) { usedx = deltax; } if(usedy > deltay) { usedy = deltay; } $? ". deltax = %lg usedx = %lg", deltax, usedx $? ". deltay = %lg usedy = %lg", deltay, usedy (bj->trans).iu.x0 = (bj->trans).ia.x0 + 0.5 * dkma_sub_double_ok(deltax, usedx, &me); /* correct mathematical problem */ if(fabs((bj->trans).iu.x0) < 0.001) { (bj->trans).iu.x0 = 0.0; } (bj->trans).iu.x1 = dkma_add_double_ok((bj->trans).iu.x0, usedx, &me); (bj->trans).iu.y0 = (bj->trans).ia.y0 + 0.5 * dkma_sub_double_ok(deltay, usedy, &me); /* correct mathematical problem */ if(fabs((bj->trans).iu.y0) < 0.001) { (bj->trans).iu.y0 = 0.0; } (bj->trans).iu.y1 = dkma_add_double_ok((bj->trans).iu.y0, usedy, &me); /* real bounding box */ /* (bj->trans).bb.x0 = dkma_double_to_ul_ok(floor((bj->trans).iu.x0), &me); (bj->trans).bb.y0 = dkma_double_to_ul_ok(floor((bj->trans).iu.y0), &me); (bj->trans).bb.x1 = dkma_double_to_ul_ok(ceil((bj->trans).iu.x1), &me); (bj->trans).bb.y1 = dkma_double_to_ul_ok(ceil((bj->trans).iu.y1), &me); */ (bj->trans).bb.x0 = dkma_double_to_ul_ok(floor((bj->trans).hrbb.x0), &me); (bj->trans).bb.y0 = dkma_double_to_ul_ok(floor((bj->trans).hrbb.y0), &me); (bj->trans).bb.x1 = dkma_double_to_ul_ok(ceil((bj->trans).hrbb.x1), &me); (bj->trans).bb.y1 = dkma_double_to_ul_ok(ceil((bj->trans).hrbb.y1), &me); $? ". hrbb = %lg %lg %lg %lg", (bj->trans).hrbb.x0, (bj->trans).hrbb.y0, (bj->trans).hrbb.x1, (bj->trans).hrbb.y1 $? ". ia = %lg %lg %lg %lg", (bj->trans).ia.x0, (bj->trans).ia.y0, (bj->trans).ia.x1, (bj->trans).ia.y1 $? ". ui = %lg %lg %lg %lg", (bj->trans).iu.x0, (bj->trans).iu.y0, (bj->trans).iu.x1, (bj->trans).iu.y1 $? ". bb = %lu %lu %lu %lu", (bj->trans).bb.x0, (bj->trans).bb.y0, (bj->trans).bb.x1, (bj->trans).bb.y1 $? "- bb_from_paper_size" } /** Complete bounding box calculation @param bj Bmeps job. */ static void bb_complete DK_P1(BJ *,bj) { /* allowed area */ (bj->trans).ia.x0 = (bj->trans).iu.x0; (bj->trans).ia.y0 = (bj->trans).iu.y0; (bj->trans).ia.x1 = (bj->trans).iu.x1; (bj->trans).ia.y1 = (bj->trans).iu.y1; /* paper size */ (bj->trans).hrbb.x0 = dkma_ul_to_double((bj->trans).bb.x0); (bj->trans).hrbb.y0 = dkma_ul_to_double((bj->trans).bb.y0); (bj->trans).hrbb.x1 = dkma_ul_to_double((bj->trans).bb.x1); (bj->trans).hrbb.y1 = dkma_ul_to_double((bj->trans).bb.y1); } /** Create bounding box, ignore resolution settings. @param bj Bmeps job. */ static void bb_ignore_resolution DK_P1(BJ *,bj) { $? "+ bb_ignore_resolution" /* real bounding box */ (bj->trans).bb.x0 = 0UL; (bj->trans).bb.y0 = 0UL; (bj->trans).bb.x1 = dkbif_get_width(bj->bif); $? ". x1 = %lu", (bj->trans).bb.x1 (bj->trans).bb.y1 = dkbif_get_height(bj->bif); $? ". y1= %lu", (bj->trans).bb.y1 /* used area */ (bj->trans).iu.x0 = 0.0; (bj->trans).iu.y0 = 0.0; (bj->trans).iu.x1 = dkma_ul_to_double((bj->trans).bb.x1); (bj->trans).iu.y1 = dkma_ul_to_double((bj->trans).bb.y1); bb_complete(bj); $? "- bb_ignore_resolution" } /** Create bounding box using resolution information. @param bj Bmeps job. */ static void bb_use_resolution DK_P1(BJ *,bj) { int me = 0; double delta; (bj->trans).must_scale = dkbif_get_must_scale(bj->bif); if((bj->trans).must_scale) { (bj->trans).iu.x0 = 0.0; (bj->trans).iu.y0 = 0.0; (bj->trans).iu.x1 = dkbif_get_real_width(bj->bif); (bj->trans).iu.y1 = dkbif_get_real_height(bj->bif); (bj->trans).sfx = dkma_div_double_ok( (bj->trans).iu.x1, dkma_ul_to_double(dkbif_get_width(bj->bif)), &me ); (bj->trans).sfx = dkma_double_restrict_downwards((bj->trans).sfx, 5); (bj->trans).iu.x1 = dkma_mul_double_ok( dkma_ul_to_double(dkbif_get_width(bj->bif)), (bj->trans).sfx, &me ); (bj->trans).sfy = dkma_div_double_ok( (bj->trans).iu.y1, dkma_ul_to_double(dkbif_get_height(bj->bif)), &me ); (bj->trans).sfy = dkma_double_restrict_downwards((bj->trans).sfy, 5); (bj->trans).iu.y1 = dkma_mul_double_ok( dkma_ul_to_double(dkbif_get_height(bj->bif)), (bj->trans).sfy, &me ); (bj->trans).ia.x0 = 0.0; (bj->trans).ia.y0 = 0.0; (bj->trans).ia.x1 = ceil((bj->trans).iu.x1); (bj->trans).ia.y1 = ceil((bj->trans).iu.y1); delta = 0.5 * dkma_sub_double_ok( (bj->trans).ia.x1, (bj->trans).iu.x1, &me ); (bj->trans).iu.x0 = delta; (bj->trans).iu.x1 = dkma_add_double_ok((bj->trans).iu.x1, delta, &me); delta = 0.5 * dkma_sub_double_ok( (bj->trans).ia.y1, (bj->trans).iu.y1, &me ); (bj->trans).iu.y0 = delta; (bj->trans).iu.y1 = dkma_add_double_ok((bj->trans).iu.y1, delta, &me); (bj->trans).bb.x0 = 0UL; (bj->trans).bb.y0 = 0UL; (bj->trans).bb.x1 = dkma_double_to_ul((bj->trans).ia.x1); (bj->trans).bb.y1 = dkma_double_to_ul((bj->trans).ia.y1); (bj->trans).hrbb.x0 = dkma_ul_to_double((bj->trans).bb.x0); (bj->trans).hrbb.y0 = dkma_ul_to_double((bj->trans).bb.y0); (bj->trans).hrbb.x1 = dkma_ul_to_double((bj->trans).bb.x1); (bj->trans).hrbb.y1 = dkma_ul_to_double((bj->trans).bb.y1); } else { bb_ignore_resolution(bj); } if(me) { /* ##### ERROR: Math error. Not yet handled! */ } } /** Calculate used areas, shifting and rotation. @param bj Bmeps job. */ void bmeps_tool_calculate_areas DK_P1(BJ *,bj) { $? "+ bmeps_tool_calculate_areas" if(bj) { initialize_areas(bj); switch(bmeps_tool_how_to_handle_bb(bj)) { case 2: { /* bb from paper size */ bb_from_paper_size(bj); } break; case 1: { /* bb from pHY chunk if available */ bb_use_resolution(bj); } break; default: { /* bb from image dimensions */ bb_ignore_resolution(bj); } break; } } $? "- bmeps_tool_calculate_areas" } /** Get number of PDF bits per component for a specified input number of bits per component. @param b Bits per component from input file. @return Bits per component for PDF output. */ unsigned short bmeps_tool_pdf_output_bits DK_P1(unsigned short,b) { unsigned short back = 1; if(b > 1) { back = 2; if(b > 2) { back = 4; if(b > 4) { back = 8; } } } return back; } /** Get number of EPS bits per component for a specified input number of bits per component. @param b Bits per component from input file. @return Bits per component for PS/EPS output. */ unsigned short bmeps_tool_eps_output_bits DK_P1(unsigned short,b) { unsigned short back = 1; if(b > 1) { back = 2; if(b > 2) { back = 4; if(b > 4) { back = 8; if(b > 8) { back = 12; } } } } return back; } /** Correct inconsitencies (if any) in bmeps options set. @param bo Bmeps options set. */ void bmeps_tool_correct_bo DK_P1(BO *,bo) { $? "+ correct_bo" switch(bo->ot) { case BMEPS_OUTPUT_TYPE_EPS: { if(bo->l < BMEPS_PS_LEVEL_2) { bo->opt &= (~(BMEPS_OPT_OPERATOR_DICTIONARY)); bo->opt &= (~(BMEPS_OPT_COLOR_OUTPUT)); bo->opt &= (~(BMEPS_OPT_OPERATOR_DICTIONARY)); bo->enc &= (~(BMEPS_ENCODING_ASCII85)); bo->enc &= (~(BMEPS_ENCODING_RUNLENGTH)); bo->enc &= (~(BMEPS_ENCODING_DCT)); bo->enc &= (~(BMEPS_ENCODING_LZW)); } if(bo->l < BMEPS_PS_LEVEL_3) { bo->opt &= (~(BMEPS_OPT_IMAGE_MASK)); bo->enc &= (~(BMEPS_ENCODING_FLATE)); } else { if(bo->opt & BMEPS_OPT_IMAGE_MASK) { bo->opt |= BMEPS_OPT_OPERATOR_DICTIONARY; } } if(!(bo->opt & BMEPS_OPT_COLOR_OUTPUT)) { bo->opt &= (~(BMEPS_OPT_SEPARATED_DATA)); } if(!(bo->opt & BMEPS_OPT_DICTIONARY)) { bo->opt &= (~(BMEPS_OPT_VMRECLAIM)); } if(!(bo->opt & BMEPS_OPT_OPERATOR_DICTIONARY)) { bo->opt &= (~(BMEPS_OPT_INTERPOLATE)); } } break; case BMEPS_OUTPUT_TYPE_PDF: { if(bo->l < BMEPS_PDF_LEVEL_14) { bo->opt &= (~(BMEPS_OPT_TRANSFER_ALPHA)); } if(bo->opt & BMEPS_OPT_TRANSFER_ALPHA) { bo->opt &= (~(BMEPS_OPT_ALPHA_MIX)); bo->opt &= (~(BMEPS_OPT_IMAGE_MASK)); } } break; default: { } break; } $? "- correct_bo" } /** Check whether interpolation flag must be enabled. @param bj Bmeps job. @return Value of interpolation flag. */ int bmeps_tool_interpolate DK_P1(BJ *,bj) { int back = 0; if(bj) { switch(bj->it) { case DKBIF_TYPE_JPG: { if((bj->bo2)->opt & BMEPS_OPT_JPEG_INTERPOLATE) { if((bj->bo2)->opt & BMEPS_OPT_INTERPOLATE) { back = 1; } } } break; default: { if((bj->bo2)->opt & BMEPS_OPT_INTERPOLATE) { back = 1; } } break; } } return back; } /** File name suffixes for output types. */ char *b2tool_ot_suffixes[] = { ".eps", ".pdf", ".bb", NULL }; /** Find file name suffix for output type. @param t Output type. @return File name suffix. */ char * bmeps_tool_suffix_for_output_type DK_P1(int,t) { char *back = NULL; back = b2tool_ot_suffixes[0]; switch(t) { case BMEPS_OUTPUT_TYPE_PDF: { back = b2tool_ot_suffixes[1]; } break; case BMEPS_OUTPUT_TYPE_BB : { back = b2tool_ot_suffixes[2]; } break; } return back; } /** Calculate dimensions (line width, angle) for draft. @param bj Bmeps job. @param dp1 Inner lines. @param dp2 Outer lines. @param f1 Inner lines factor. @param f2 Border lines factor. @return 1 on success, 0 on error. */ int bmeps_tool_calc_di DK_P5(BJ *,bj, DI *,dp1, DI *,dp2, double,f1, double,f2) { int back = 1; int me = 0; double w, h, alpha, d1, d2; w = dkma_sub_double_ok((bj->trans).iu.x1, (bj->trans).iu.x0, &me); h = dkma_sub_double_ok((bj->trans).iu.y1, (bj->trans).iu.y0, &me); alpha = atan2(w, h); if(w < h) { d1 = f1 * w; d2 = f2 * w; } else { d1 = f1 * h; d2 = f2 * h; } dp1->d = d1; dp2->d = d2; dp1->deltax = dkma_div_double_ok( d1, (2.0 * sin(alpha)), &me ); dp1->deltay = dkma_div_double_ok( d1, (2.0 * cos(alpha)), &me ); dp2->deltax = dkma_div_double_ok( d2, (2.0 * sin(alpha)), &me ); dp2->deltay = dkma_div_double_ok( d2, (2.0 * cos(alpha)), &me ); if(me) back = 0; return back; } /** Get text for a message number. @param bj Bmeps job. @param n Index in message array. @return The message text. */ char * bmeps_get_msg_no DK_P2(BJ *,bj, size_t,n) { char *back = NULL; if(bj->msg) { back = (bj->msg)[n]; if(!back) { back = bmeps_str_get(n); } } else { back = bmeps_str_get(n); } return back; } /** Show simple error message. @param bj Bmeps job. @param ll Log level (DK_LOG_xxx). @param n Index in string array. */ void bmeps_tool_msg_1 DK_P3(BJ *,bj, int,ll, size_t,n) { char *buffer[2]; buffer[0] = bmeps_get_msg_no(bj, n); if(bj->a) { dkapp_log_msg(bj->a, ll, buffer, 1); } else { if(ll <= DK_LOG_LEVEL_INFO) { buffer[1] = bmeps_get_msg_no(bj, (26 + ll)); fprintf(stderr, "%s%s\n", buffer[1], buffer[0]); fflush(stderr); } } } /** Show error message, one custom string: bmeps_str_get(n1) s bmeps_str_get(n2). @param bj Bmeps job. @param ll Log level (DK_LOG_xxx). @param n1 Index in string array. @param n2 Index in string array. @param s Customized string. */ void bmeps_tool_msg_3 DK_P5(BJ *,bj, int,ll, size_t,n1, size_t,n2, char *,s) { char *buffer[4]; buffer[0] = bmeps_get_msg_no(bj, n1); buffer[1] = s; buffer[2] = bmeps_get_msg_no(bj, n2); if(bj->a) { dkapp_log_msg(bj->a, ll, buffer, 3); } else { if(ll <= DK_LOG_LEVEL_INFO) { buffer[3] = bmeps_get_msg_no(bj, (26 + ll)); fprintf( stderr, "%s%s%s%s\n", buffer[3], buffer[0], buffer[1], buffer[2] ); fflush(stderr); } } } /** Show error message, two custom strings: bmeps_str_get(n1) s1 bmeps_str_get(n2) s2 bmeps_str_get(n3). @param bj Bmeps job. @param ll Log level (DK_LOG_xxx). @param n1 Index in string array. @param n2 Index in string array. @param n3 Index in string array. @param s1 1st customized string. @param s2 2nd customized string. */ void bmeps_tool_msg_5 DK_P7(BJ *,bj, int,ll, size_t,n1, size_t,n2, size_t,n3, char *,s1, char *,s2) { char *buffer[6]; buffer[0] = bmeps_get_msg_no(bj, n1); buffer[1] = s1; buffer[2] = bmeps_get_msg_no(bj, n2); buffer[3] = s2; buffer[4] = bmeps_get_msg_no(bj, n3); if(bj->a) { dkapp_log_msg(bj->a, ll, buffer, 5); } else { if(ll <= DK_LOG_LEVEL_INFO) { buffer[5] = bmeps_get_msg_no(bj, (26 + ll)); fprintf( stderr, "%s%s%s%s%s%s\n", buffer[5], buffer[0], buffer[1], buffer[2], buffer[3], buffer[4] ); fflush(stderr); } } } /** Show error message: Not enough memory. @param bj Bmeps job. */ void bmeps_tool_error_memory DK_P1(BJ *,bj) { if(bj->msg) { bmeps_tool_msg_1(bj, DK_LOG_LEVEL_ERROR, 32); } else { fprintf(stderr, "ERROR: Not enough memory (RAM/swap space)!\n"); fflush(stderr); } }