Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. #include "fitz.h"
  2.  
  3. static int fz_memory_limit = 256 << 20;
  4. static int fz_memory_used = 0;
  5.  
  6. fz_pixmap *
  7. fz_new_pixmap_with_data(fz_colorspace *colorspace, int w, int h, unsigned char *samples)
  8. {
  9.         fz_pixmap *pix;
  10.  
  11.         pix = fz_malloc(sizeof(fz_pixmap));
  12.         pix->refs = 1;
  13.         pix->x = 0;
  14.         pix->y = 0;
  15.         pix->w = w;
  16.         pix->h = h;
  17.         pix->mask = NULL;
  18.         pix->interpolate = 1;
  19.         pix->xres = 96;
  20.         pix->yres = 96;
  21.         pix->colorspace = NULL;
  22.         pix->n = 1;
  23.  
  24.         if (colorspace)
  25.         {
  26.                 pix->colorspace = fz_keep_colorspace(colorspace);
  27.                 pix->n = 1 + colorspace->n;
  28.         }
  29.  
  30.         if (samples)
  31.         {
  32.                 pix->samples = samples;
  33.                 pix->free_samples = 0;
  34.         }
  35.         else
  36.         {
  37.                 fz_memory_used += pix->w * pix->h * pix->n;
  38.                 pix->samples = fz_calloc(pix->h, pix->w * pix->n);
  39.                 pix->free_samples = 1;
  40.         }
  41.  
  42.         return pix;
  43. }
  44.  
  45. fz_pixmap *
  46. fz_new_pixmap_with_limit(fz_colorspace *colorspace, int w, int h)
  47. {
  48.         int n = colorspace ? colorspace->n + 1 : 1;
  49.         int size = w * h * n;
  50.         if (fz_memory_used + size > fz_memory_limit)
  51.         {
  52.                 fz_warn("pixmap memory exceeds soft limit %dM + %dM > %dM",
  53.                         fz_memory_used/(1<<20), size/(1<<20), fz_memory_limit/(1<<20));
  54.                 return NULL;
  55.         }
  56.         return fz_new_pixmap_with_data(colorspace, w, h, NULL);
  57. }
  58.  
  59. fz_pixmap *
  60. fz_new_pixmap(fz_colorspace *colorspace, int w, int h)
  61. {
  62.         return fz_new_pixmap_with_data(colorspace, w, h, NULL);
  63. }
  64.  
  65. fz_pixmap *
  66. fz_new_pixmap_with_rect(fz_colorspace *colorspace, fz_bbox r)
  67. {
  68.         fz_pixmap *pixmap;
  69.         pixmap = fz_new_pixmap(colorspace, r.x1 - r.x0, r.y1 - r.y0);
  70.         pixmap->x = r.x0;
  71.         pixmap->y = r.y0;
  72.         return pixmap;
  73. }
  74.  
  75. fz_pixmap *
  76. fz_new_pixmap_with_rect_and_data(fz_colorspace *colorspace, fz_bbox r, unsigned char *samples)
  77. {
  78.         fz_pixmap *pixmap;
  79.         pixmap = fz_new_pixmap_with_data(colorspace, r.x1 - r.x0, r.y1 - r.y0, samples);
  80.         pixmap->x = r.x0;
  81.         pixmap->y = r.y0;
  82.         return pixmap;
  83. }
  84.  
  85. fz_pixmap *
  86. fz_keep_pixmap(fz_pixmap *pix)
  87. {
  88.         pix->refs++;
  89.         return pix;
  90. }
  91.  
  92. void
  93. fz_drop_pixmap(fz_pixmap *pix)
  94. {
  95.         if (pix && --pix->refs == 0)
  96.         {
  97.                 fz_memory_used -= pix->w * pix->h * pix->n;
  98.                 if (pix->mask)
  99.                         fz_drop_pixmap(pix->mask);
  100.                 if (pix->colorspace)
  101.                         fz_drop_colorspace(pix->colorspace);
  102.                 if (pix->free_samples)
  103.                         fz_free(pix->samples);
  104.                 fz_free(pix);
  105.         }
  106. }
  107.  
  108. fz_bbox
  109. fz_bound_pixmap(fz_pixmap *pix)
  110. {
  111.         fz_bbox bbox;
  112.         bbox.x0 = pix->x;
  113.         bbox.y0 = pix->y;
  114.         bbox.x1 = pix->x + pix->w;
  115.         bbox.y1 = pix->y + pix->h;
  116.         return bbox;
  117. }
  118.  
  119. void
  120. fz_clear_pixmap(fz_pixmap *pix)
  121. {
  122.         memset(pix->samples, 0, pix->w * pix->h * pix->n);
  123. }
  124.  
  125. void
  126. fz_clear_pixmap_with_color(fz_pixmap *pix, int value)
  127. {
  128.         if (value == 255)
  129.                 memset(pix->samples, 255, pix->w * pix->h * pix->n);
  130.         else
  131.         {
  132.                 int k, x, y;
  133.                 unsigned char *s = pix->samples;
  134.                 for (y = 0; y < pix->h; y++)
  135.                 {
  136.                         for (x = 0; x < pix->w; x++)
  137.                         {
  138.                                 for (k = 0; k < pix->n - 1; k++)
  139.                                         *s++ = value;
  140.                                 *s++ = 255;
  141.                         }
  142.                 }
  143.         }
  144. }
  145.  
  146. void
  147. fz_copy_pixmap_rect(fz_pixmap *dest, fz_pixmap *src, fz_bbox r)
  148. {
  149.         const unsigned char *srcp;
  150.         unsigned char *destp;
  151.         int y, w, destspan, srcspan;
  152.  
  153.         r = fz_intersect_bbox(r, fz_bound_pixmap(dest));
  154.         r = fz_intersect_bbox(r, fz_bound_pixmap(src));
  155.         w = r.x1 - r.x0;
  156.         y = r.y1 - r.y0;
  157.         if (w <= 0 || y <= 0)
  158.                 return;
  159.  
  160.         w *= src->n;
  161.         srcspan = src->w * src->n;
  162.         srcp = src->samples + srcspan * (r.y0 - src->y) + src->n * (r.x0 - src->x);
  163.         destspan = dest->w * dest->n;
  164.         destp = dest->samples + destspan * (r.y0 - dest->y) + dest->n * (r.x0 - dest->x);
  165.         do
  166.         {
  167.                 memcpy(destp, srcp, w);
  168.                 srcp += srcspan;
  169.                 destp += destspan;
  170.         }
  171.         while (--y);
  172. }
  173.  
  174. void
  175. fz_clear_pixmap_rect_with_color(fz_pixmap *dest, int value, fz_bbox r)
  176. {
  177.         unsigned char *destp;
  178.         int x, y, w, k, destspan;
  179.  
  180.         r = fz_intersect_bbox(r, fz_bound_pixmap(dest));
  181.         w = r.x1 - r.x0;
  182.         y = r.y1 - r.y0;
  183.         if (w <= 0 || y <= 0)
  184.                 return;
  185.  
  186.         destspan = dest->w * dest->n;
  187.         destp = dest->samples + destspan * (r.y0 - dest->y) + dest->n * (r.x0 - dest->x);
  188.         if (value == 255)
  189.                 do
  190.                 {
  191.                         memset(destp, 255, w * dest->n);
  192.                         destp += destspan;
  193.                 }
  194.                 while (--y);
  195.         else
  196.                 do
  197.                 {
  198.                         unsigned char *s = destp;
  199.                         for (x = 0; x < w; x++)
  200.                         {
  201.                                 for (k = 0; k < dest->n - 1; k++)
  202.                                         *s++ = value;
  203.                                 *s++ = 255;
  204.                         }
  205.                         destp += destspan;
  206.                 }
  207.                 while (--y);
  208. }
  209.  
  210. void
  211. fz_premultiply_pixmap(fz_pixmap *pix)
  212. {
  213.         unsigned char *s = pix->samples;
  214.         unsigned char a;
  215.         int k, x, y;
  216.  
  217.         for (y = 0; y < pix->h; y++)
  218.         {
  219.                 for (x = 0; x < pix->w; x++)
  220.                 {
  221.                         a = s[pix->n - 1];
  222.                         for (k = 0; k < pix->n - 1; k++)
  223.                                 s[k] = fz_mul255(s[k], a);
  224.                         s += pix->n;
  225.                 }
  226.         }
  227. }
  228.  
  229. fz_pixmap *
  230. fz_alpha_from_gray(fz_pixmap *gray, int luminosity)
  231. {
  232.         fz_pixmap *alpha;
  233.         unsigned char *sp, *dp;
  234.         int len;
  235.  
  236.         assert(gray->n == 2);
  237.  
  238.         alpha = fz_new_pixmap_with_rect(NULL, fz_bound_pixmap(gray));
  239.         dp = alpha->samples;
  240.         sp = gray->samples;
  241.         if (!luminosity)
  242.                 sp ++;
  243.  
  244.         len = gray->w * gray->h;
  245.         while (len--)
  246.         {
  247.                 *dp++ = sp[0];
  248.                 sp += 2;
  249.         }
  250.  
  251.         return alpha;
  252. }
  253.  
  254. void
  255. fz_invert_pixmap(fz_pixmap *pix)
  256. {
  257.         unsigned char *s = pix->samples;
  258.         int k, x, y;
  259.  
  260.         for (y = 0; y < pix->h; y++)
  261.         {
  262.                 for (x = 0; x < pix->w; x++)
  263.                 {
  264.                         for (k = 0; k < pix->n - 1; k++)
  265.                                 s[k] = 255 - s[k];
  266.                         s += pix->n;
  267.                 }
  268.         }
  269. }
  270.  
  271. void
  272. fz_gamma_pixmap(fz_pixmap *pix, float gamma)
  273. {
  274.         unsigned char gamma_map[256];
  275.         unsigned char *s = pix->samples;
  276.         int k, x, y;
  277.  
  278.         for (k = 0; k < 256; k++)
  279.                 gamma_map[k] = pow(k / 255.0f, gamma) * 255;
  280.  
  281.         for (y = 0; y < pix->h; y++)
  282.         {
  283.                 for (x = 0; x < pix->w; x++)
  284.                 {
  285.                         for (k = 0; k < pix->n - 1; k++)
  286.                                 s[k] = gamma_map[s[k]];
  287.                         s += pix->n;
  288.                 }
  289.         }
  290. }
  291.  
  292. /*
  293.  * Write pixmap to PNM file (without alpha channel)
  294.  */
  295.  
  296. fz_error
  297. fz_write_pnm(fz_pixmap *pixmap, char *filename)
  298. {
  299.         FILE *fp;
  300.         unsigned char *p;
  301.         int len;
  302.  
  303.         if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4)
  304.                 return fz_throw("pixmap must be grayscale or rgb to write as pnm");
  305.  
  306.         fp = fopen(filename, "wb");
  307.         if (!fp)
  308.                 return fz_throw("cannot open file '%s': %s", filename, strerror(errno));
  309.  
  310.         if (pixmap->n == 1 || pixmap->n == 2)
  311.                 fprintf(fp, "P5\n");
  312.         if (pixmap->n == 4)
  313.                 fprintf(fp, "P6\n");
  314.         fprintf(fp, "%d %d\n", pixmap->w, pixmap->h);
  315.         fprintf(fp, "255\n");
  316.  
  317.         len = pixmap->w * pixmap->h;
  318.         p = pixmap->samples;
  319.  
  320.         switch (pixmap->n)
  321.         {
  322.         case 1:
  323.                 fwrite(p, 1, len, fp);
  324.                 break;
  325.         case 2:
  326.                 while (len--)
  327.                 {
  328.                         putc(p[0], fp);
  329.                         p += 2;
  330.                 }
  331.                 break;
  332.         case 4:
  333.                 while (len--)
  334.                 {
  335.                         putc(p[0], fp);
  336.                         putc(p[1], fp);
  337.                         putc(p[2], fp);
  338.                         p += 4;
  339.                 }
  340.         }
  341.  
  342.         fclose(fp);
  343.         return fz_okay;
  344. }
  345.  
  346. /*
  347.  * Write pixmap to PAM file (with or without alpha channel)
  348.  */
  349.  
  350. fz_error
  351. fz_write_pam(fz_pixmap *pixmap, char *filename, int savealpha)
  352. {
  353.         unsigned char *sp;
  354.         int y, w, k;
  355.         FILE *fp;
  356.  
  357.         int sn = pixmap->n;
  358.         int dn = pixmap->n;
  359.         if (!savealpha && dn > 1)
  360.                 dn--;
  361.  
  362.         fp = fopen(filename, "wb");
  363.         if (!fp)
  364.                 return fz_throw("cannot open file '%s': %s", filename, strerror(errno));
  365.  
  366.         fprintf(fp, "P7\n");
  367.         fprintf(fp, "WIDTH %d\n", pixmap->w);
  368.         fprintf(fp, "HEIGHT %d\n", pixmap->h);
  369.         fprintf(fp, "DEPTH %d\n", dn);
  370.         fprintf(fp, "MAXVAL 255\n");
  371.         if (pixmap->colorspace)
  372.                 fprintf(fp, "# COLORSPACE %s\n", pixmap->colorspace->name);
  373.         switch (dn)
  374.         {
  375.         case 1: fprintf(fp, "TUPLTYPE GRAYSCALE\n"); break;
  376.         case 2: if (sn == 2) fprintf(fp, "TUPLTYPE GRAYSCALE_ALPHA\n"); break;
  377.         case 3: if (sn == 4) fprintf(fp, "TUPLTYPE RGB\n"); break;
  378.         case 4: if (sn == 4) fprintf(fp, "TUPLTYPE RGB_ALPHA\n"); break;
  379.         }
  380.         fprintf(fp, "ENDHDR\n");
  381.  
  382.         sp = pixmap->samples;
  383.         for (y = 0; y < pixmap->h; y++)
  384.         {
  385.                 w = pixmap->w;
  386.                 while (w--)
  387.                 {
  388.                         for (k = 0; k < dn; k++)
  389.                                 putc(sp[k], fp);
  390.                         sp += sn;
  391.                 }
  392.         }
  393.  
  394.         fclose(fp);
  395.  
  396.         return fz_okay;
  397. }
  398.  
  399. /*
  400.  * Write pixmap to PNG file (with or without alpha channel)
  401.  */
  402.  
  403. #include <zlib.h>
  404.  
  405. static inline void big32(unsigned char *buf, unsigned int v)
  406. {
  407.         buf[0] = (v >> 24) & 0xff;
  408.         buf[1] = (v >> 16) & 0xff;
  409.         buf[2] = (v >> 8) & 0xff;
  410.         buf[3] = (v) & 0xff;
  411. }
  412.  
  413. static inline void put32(unsigned int v, FILE *fp)
  414. {
  415.         putc(v >> 24, fp);
  416.         putc(v >> 16, fp);
  417.         putc(v >> 8, fp);
  418.         putc(v, fp);
  419. }
  420.  
  421. static void putchunk(char *tag, unsigned char *data, int size, FILE *fp)
  422. {
  423.         unsigned int sum;
  424.         put32(size, fp);
  425.         fwrite(tag, 1, 4, fp);
  426.         fwrite(data, 1, size, fp);
  427.         sum = crc32(0, NULL, 0);
  428.         sum = crc32(sum, (unsigned char*)tag, 4);
  429.         sum = crc32(sum, data, size);
  430.         put32(sum, fp);
  431. }
  432.  
  433. fz_error
  434. fz_write_png(fz_pixmap *pixmap, char *filename, int savealpha)
  435. {
  436.         static const unsigned char pngsig[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
  437.         FILE *fp;
  438.         unsigned char head[13];
  439.         unsigned char *udata, *cdata, *sp, *dp;
  440.         uLong usize, csize;
  441.         int y, x, k, sn, dn;
  442.         int color;
  443.         int err;
  444.  
  445.         if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4)
  446.                 return fz_throw("pixmap must be grayscale or rgb to write as png");
  447.  
  448.         sn = pixmap->n;
  449.         dn = pixmap->n;
  450.         if (!savealpha && dn > 1)
  451.                 dn--;
  452.  
  453.         switch (dn)
  454.         {
  455.         default:
  456.         case 1: color = 0; break;
  457.         case 2: color = 4; break;
  458.         case 3: color = 2; break;
  459.         case 4: color = 6; break;
  460.         }
  461.  
  462.         usize = (pixmap->w * dn + 1) * pixmap->h;
  463.         csize = compressBound(usize);
  464.         udata = fz_malloc(usize);
  465.         cdata = fz_malloc(csize);
  466.  
  467.         sp = pixmap->samples;
  468.         dp = udata;
  469.         for (y = 0; y < pixmap->h; y++)
  470.         {
  471.                 *dp++ = 1; /* sub prediction filter */
  472.                 for (x = 0; x < pixmap->w; x++)
  473.                 {
  474.                         for (k = 0; k < dn; k++)
  475.                         {
  476.                                 if (x == 0)
  477.                                         dp[k] = sp[k];
  478.                                 else
  479.                                         dp[k] = sp[k] - sp[k-sn];
  480.                         }
  481.                         sp += sn;
  482.                         dp += dn;
  483.                 }
  484.         }
  485.  
  486.         err = compress(cdata, &csize, udata, usize);
  487.         if (err != Z_OK)
  488.         {
  489.                 fz_free(udata);
  490.                 fz_free(cdata);
  491.                 return fz_throw("cannot compress image data");
  492.         }
  493.  
  494.         fp = fopen(filename, "wb");
  495.         if (!fp)
  496.         {
  497.                 fz_free(udata);
  498.                 fz_free(cdata);
  499.                 return fz_throw("cannot open file '%s': %s", filename, strerror(errno));
  500.         }
  501.  
  502.         big32(head+0, pixmap->w);
  503.         big32(head+4, pixmap->h);
  504.         head[8] = 8; /* depth */
  505.         head[9] = color;
  506.         head[10] = 0; /* compression */
  507.         head[11] = 0; /* filter */
  508.         head[12] = 0; /* interlace */
  509.  
  510.         fwrite(pngsig, 1, 8, fp);
  511.         putchunk("IHDR", head, 13, fp);
  512.         putchunk("IDAT", cdata, csize, fp);
  513.         putchunk("IEND", head, 0, fp);
  514.         fclose(fp);
  515.  
  516.         fz_free(udata);
  517.         fz_free(cdata);
  518.         return fz_okay;
  519. }
  520.