|
Packit |
df99a1 |
/* minidjvu - library for handling bilevel images with DjVuBitonal support
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* frames.c - extracting frameworks and calculating "importance rating"
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* Copyright (C) 2005 Ilya Mezhirov
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
df99a1 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
df99a1 |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
df99a1 |
* (at your option) any later version.
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
df99a1 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
df99a1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
df99a1 |
* GNU General Public License for more details.
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
df99a1 |
* along with this program; if not, write to the Free Software
|
|
Packit |
df99a1 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* minidjvu is derived from DjVuLibre (http://djvu.sourceforge.net)
|
|
Packit |
df99a1 |
* All over DjVuLibre there is a patent alert from LizardTech
|
|
Packit |
df99a1 |
* which I guess I should reproduce (don't ask me what does this mean):
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* ------------------------------------------------------------------
|
|
Packit |
df99a1 |
* | DjVu (r) Reference Library (v. 3.5)
|
|
Packit |
df99a1 |
* | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
|
|
Packit |
df99a1 |
* | The DjVu Reference Library is protected by U.S. Pat. No.
|
|
Packit |
df99a1 |
* | 6,058,214 and patents pending.
|
|
Packit |
df99a1 |
* |
|
|
Packit |
df99a1 |
* | This software is subject to, and may be distributed under, the
|
|
Packit |
df99a1 |
* | GNU General Public License, either Version 2 of the license,
|
|
Packit |
df99a1 |
* | or (at your option) any later version. The license should have
|
|
Packit |
df99a1 |
* | accompanied the software or you may obtain a copy of the license
|
|
Packit |
df99a1 |
* | from the Free Software Foundation at http://www.fsf.org .
|
|
Packit |
df99a1 |
* |
|
|
Packit |
df99a1 |
* | The computer code originally released by LizardTech under this
|
|
Packit |
df99a1 |
* | license and unmodified by other parties is deemed "the LIZARDTECH
|
|
Packit |
df99a1 |
* | ORIGINAL CODE." Subject to any third party intellectual property
|
|
Packit |
df99a1 |
* | claims, LizardTech grants recipient a worldwide, royalty-free,
|
|
Packit |
df99a1 |
* | non-exclusive license to make, use, sell, or otherwise dispose of
|
|
Packit |
df99a1 |
* | the LIZARDTECH ORIGINAL CODE or of programs derived from the
|
|
Packit |
df99a1 |
* | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
|
|
Packit |
df99a1 |
* | General Public License. This grant only confers the right to
|
|
Packit |
df99a1 |
* | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
|
|
Packit |
df99a1 |
* | the extent such infringement is reasonably necessary to enable
|
|
Packit |
df99a1 |
* | recipient to make, have made, practice, sell, or otherwise dispose
|
|
Packit |
df99a1 |
* | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
|
|
Packit |
df99a1 |
* | any greater extent that may be necessary to utilize further
|
|
Packit |
df99a1 |
* | modifications or combinations.
|
|
Packit |
df99a1 |
* |
|
|
Packit |
df99a1 |
* | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
|
|
Packit |
df99a1 |
* | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
Packit |
df99a1 |
* | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
|
|
Packit |
df99a1 |
* | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit |
df99a1 |
* +------------------------------------------------------------------
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* Frameworks are funny things...
|
|
Packit |
df99a1 |
* The algorithm is to be commented yet.
|
|
Packit |
df99a1 |
* Here's a picture illustrating what is a frame
|
|
Packit |
df99a1 |
* (view with monospace font):
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* Original letter: Its framework:
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
.....@@@@@@@@........ .....................
|
|
Packit |
df99a1 |
...@@@@@@@@@@@@...... ......@@@@@..........
|
|
Packit |
df99a1 |
..@@@@@@@@@@@@@@..... .....@@...@@@........
|
|
Packit |
df99a1 |
..@@@@@...@@@@@@@.... ....@@......@@.......
|
|
Packit |
df99a1 |
..@@@@.....@@@@@@.... ....@........@.......
|
|
Packit |
df99a1 |
.@@@@@.....@@@@@@.... ....@........@.......
|
|
Packit |
df99a1 |
.@@@@@.....@@@@@@.... ....@........@.......
|
|
Packit |
df99a1 |
..@@@@.....@@@@@@.... ....@........@.......
|
|
Packit |
df99a1 |
..........@@@@@@@.... .............@.......
|
|
Packit |
df99a1 |
.......@@@@@@@@@@.... .............@.......
|
|
Packit |
df99a1 |
.....@@@@@@@@@@@@.... ........@@@@@@.......
|
|
Packit |
df99a1 |
...@@@@@@@@@@@@@@.... ......@@@....@.......
|
|
Packit |
df99a1 |
..@@@@@@@..@@@@@@.... .....@@......@.......
|
|
Packit |
df99a1 |
.@@@@@@....@@@@@@.... ...@@@.......@.......
|
|
Packit |
df99a1 |
.@@@@@.....@@@@@@.... ...@.........@.......
|
|
Packit |
df99a1 |
@@@@@......@@@@@@.... ..@@.........@.......
|
|
Packit |
df99a1 |
@@@@@......@@@@@@.... ..@..........@.......
|
|
Packit |
df99a1 |
@@@@@.....@@@@@@@.... ..@..........@.......
|
|
Packit |
df99a1 |
@@@@@@....@@@@@@@.@@@ ..@@.........@.......
|
|
Packit |
df99a1 |
.@@@@@@@@@@@@@@@@@@@@ ...@@.....@@@@@......
|
|
Packit |
df99a1 |
.@@@@@@@@@@@@@@@@@@@@ ....@@..@@@...@@@@@..
|
|
Packit |
df99a1 |
..@@@@@@@@@.@@@@@@@@. .....@@@@............
|
|
Packit |
df99a1 |
....@@@@@....@@@@@... .....................
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
* A letter is converted into grayshades,
|
|
Packit |
df99a1 |
* and a frame is the set of its purely black pixels after the transformation.
|
|
Packit |
df99a1 |
* In the grayshade version of a letter,
|
|
Packit |
df99a1 |
* all pixels that were white remain absolutely white,
|
|
Packit |
df99a1 |
* the frame is black and the blackness falls down from it to the border.
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* Offtopic: I wonder if this thing could help OCRing because frameworks
|
|
Packit |
df99a1 |
* perfectly retain readability while becoming essentially 1-dimensional.
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#include "mdjvucfg.h"
|
|
Packit |
df99a1 |
#include "minidjvu.h"
|
|
Packit |
df99a1 |
#include <stdlib.h>
|
|
Packit |
df99a1 |
#include <assert.h>
|
|
Packit |
df99a1 |
#include <string.h>
|
|
Packit |
df99a1 |
#include <math.h>
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* Stuff for not using malloc in C++
|
|
Packit |
df99a1 |
* (made by Leon Bottou; has no use in minidjvu,
|
|
Packit |
df99a1 |
* but left here for potential DjVuLibre compatibility)
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
#ifdef __cplusplus
|
|
Packit |
df99a1 |
# define MALLOC(Type) new Type
|
|
Packit |
df99a1 |
# define FREE(p) delete p
|
|
Packit |
df99a1 |
# define MALLOCV(Type,n) new Type[n]
|
|
Packit |
df99a1 |
# define FREEV(p) delete [] p
|
|
Packit |
df99a1 |
#else
|
|
Packit |
df99a1 |
# define MALLOC(Type) ((Type*)malloc(sizeof(Type)))
|
|
Packit |
df99a1 |
# define FREE(p) do{if(p)free(p);}while(0)
|
|
Packit |
df99a1 |
# define MALLOCV(Type,n) ((Type*)malloc(sizeof(Type)*(n)))
|
|
Packit |
df99a1 |
# define FREEV(p) do{if(p)free(p);}while(0)
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* This determines the gray level of the border (ratio of black).
|
|
Packit |
df99a1 |
* Setting it to 1 will effectively eliminate grayshading.
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
#define BORDER_FALLOFF .7 /* this is the main constant in all the matcher... */
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
typedef unsigned char byte;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static int donut_connectivity_test(byte *upper, byte *row, byte *lower)/*{{{*/
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
/*(on the pictures below 0 is white, 1 is black or gray)
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* 01.
|
|
Packit |
df99a1 |
* 1 . -> 1
|
|
Packit |
df99a1 |
* ...
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* .0.
|
|
Packit |
df99a1 |
* 1 1 -> 1
|
|
Packit |
df99a1 |
* .0.
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* all others -> 0
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int sum, l, u, d, r;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
sum = (u = *upper ? 1 : 0) + (d = *lower ? 1 : 0) +
|
|
Packit |
df99a1 |
(l = row[-1] ? 1 : 0) + (r = row[1] ? 1 : 0);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
switch(sum)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
case 3:/*{{{*/
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int x = 6 - (u + (l << 1) + d + (d << 1));
|
|
Packit |
df99a1 |
switch(x)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
case 0: /* l */
|
|
Packit |
df99a1 |
return upper[-1] && lower[-1] ? 0 : 1;
|
|
Packit |
df99a1 |
case 1: /* d */
|
|
Packit |
df99a1 |
return lower[-1] && lower[1] ? 0 : 1;
|
|
Packit |
df99a1 |
case 2: /* r */
|
|
Packit |
df99a1 |
return upper[1] && lower[1] ? 0 : 1;
|
|
Packit |
df99a1 |
case 3: /* u */
|
|
Packit |
df99a1 |
return upper[-1] && upper[1] ? 0 : 1;
|
|
Packit |
df99a1 |
default: assert(0); return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
break;/*}}}*/
|
|
Packit |
df99a1 |
case 2:/*{{{*/
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int s = l + r;
|
|
Packit |
df99a1 |
if (s & 1)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
/* A1.
|
|
Packit |
df99a1 |
* 1 0 - should be !A (2x2 square extermination)
|
|
Packit |
df99a1 |
* .0.
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
if (l)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (u)
|
|
Packit |
df99a1 |
return upper[-1] ? 0 : 1;
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
return lower[-1] ? 0 : 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else /* r */
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (u)
|
|
Packit |
df99a1 |
return upper[1] ? 0 : 1;
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
return lower[1] ? 0 : 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
/* .0.
|
|
Packit |
df99a1 |
* 1 1 - surely should be 1 to preserve connection
|
|
Packit |
df99a1 |
* .0.
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
return 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
break;/*}}}*/
|
|
Packit |
df99a1 |
case 0: case 4:
|
|
Packit |
df99a1 |
return 1;
|
|
Packit |
df99a1 |
case 1:
|
|
Packit |
df99a1 |
return 0;
|
|
Packit |
df99a1 |
default: assert(0); return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
assert(0); return 0;
|
|
Packit |
df99a1 |
}/*}}}*/
|
|
Packit |
df99a1 |
static byte donut_transform_pixel(byte *upper, byte *row, byte *lower)/*{{{*/
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
/* (center pixel should be gray in order for this to work)
|
|
Packit |
df99a1 |
* (on the pictures below 0 is white, 1 is black or gray)
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* 01.
|
|
Packit |
df99a1 |
* 1 . -> center will become 1
|
|
Packit |
df99a1 |
* ...
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* .0.
|
|
Packit |
df99a1 |
* 1 1 -> center will become 1
|
|
Packit |
df99a1 |
* .0.
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* 00.
|
|
Packit |
df99a1 |
* 1 0 -> center will become 1
|
|
Packit |
df99a1 |
* .0.
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* 1..
|
|
Packit |
df99a1 |
* 1 0 -> center will become 0
|
|
Packit |
df99a1 |
* 1..
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* 11.
|
|
Packit |
df99a1 |
* 1 0 -> center will become 0
|
|
Packit |
df99a1 |
* .0.
|
|
Packit |
df99a1 |
*
|
|
Packit |
df99a1 |
* .A.
|
|
Packit |
df99a1 |
* A A -> center will become 1
|
|
Packit |
df99a1 |
* .A.
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int sum, l, u, d, r;
|
|
Packit |
df99a1 |
if (!*row) return 0;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
sum = (u = *upper ? 1 : 0) + (d = *lower ? 1 : 0) +
|
|
Packit |
df99a1 |
(l = row[-1] ? 1 : 0) + (r = row[1] ? 1 : 0);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
switch(sum)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
case 1: case 3:/*{{{*/
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int x = u + (l << 1) + d + (d << 1);
|
|
Packit |
df99a1 |
if (sum == 3) x = (6 - x) ^ 2;
|
|
Packit |
df99a1 |
switch(x)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
case 0: /* r */
|
|
Packit |
df99a1 |
return upper[1] && lower[1] ? 0 : 1;
|
|
Packit |
df99a1 |
case 1: /* u */
|
|
Packit |
df99a1 |
return upper[-1] && upper[1] ? 0 : 1;
|
|
Packit |
df99a1 |
case 2: /* l */
|
|
Packit |
df99a1 |
return upper[-1] && lower[-1] ? 0 : 1;
|
|
Packit |
df99a1 |
case 3: /* d */
|
|
Packit |
df99a1 |
return lower[-1] && lower[1] ? 0 : 1;
|
|
Packit |
df99a1 |
default: assert(0); return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
break;/*}}}*/
|
|
Packit |
df99a1 |
case 2:/*{{{*/
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int s = l + r;
|
|
Packit |
df99a1 |
if (s & 1)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
/* A1.
|
|
Packit |
df99a1 |
* 1 0 - should be !A (2x2 square extermination)
|
|
Packit |
df99a1 |
* .0.
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
if (l)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (u)
|
|
Packit |
df99a1 |
return upper[-1] ? 0 : 1;
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
return lower[-1] ? 0 : 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else /* r */
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (u)
|
|
Packit |
df99a1 |
return upper[1] ? 0 : 1;
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
return lower[1] ? 0 : 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
/* .0.
|
|
Packit |
df99a1 |
* 1 1 - surely should be 1 to preserve connection
|
|
Packit |
df99a1 |
* .0.
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
return 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
break;/*}}}*/
|
|
Packit |
df99a1 |
case 0: case 4:
|
|
Packit |
df99a1 |
return 1; /* lone pixels are NOT omitted */
|
|
Packit |
df99a1 |
default: assert(0); return 0;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
assert(0); return 0;
|
|
Packit |
df99a1 |
}/*}}}*/
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* `pixels' should have a margin of 1 pixel at each side
|
|
Packit |
df99a1 |
* returns true if the image was changed
|
|
Packit |
df99a1 |
*/
|
|
Packit |
df99a1 |
static int flay(byte **pixels, int w, int h, int rank, int **ranks)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int i, j, result = 0;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
byte *buf = MALLOCV(byte, w * h);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
assert(pixels);
|
|
Packit |
df99a1 |
assert(w);
|
|
Packit |
df99a1 |
assert(h);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
for (i = 0; i < h; i++) for (j = 0; j < w; j++)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
buf[w * i + j] =
|
|
Packit |
df99a1 |
donut_transform_pixel(pixels[i-1] + j, pixels[i] + j, pixels[i+1] + j);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
for (i = 0; i < h; i++)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
byte *up = pixels[i-1], *row = pixels[i], *dn = pixels[i+1];
|
|
Packit |
df99a1 |
byte *buf_row = buf + w * i;
|
|
Packit |
df99a1 |
int *rank_row = NULL;
|
|
Packit |
df99a1 |
if (ranks) rank_row = ranks[i];
|
|
Packit |
df99a1 |
for (j = 0; j < w; j++)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (row[j] && !buf_row[j])
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (!donut_connectivity_test(up + j, row + j, dn + j))
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
row[j] = buf_row[j];
|
|
Packit |
df99a1 |
if (rank) rank_row[j] = rank;
|
|
Packit |
df99a1 |
result = 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
row[j] = buf_row[j];
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
FREEV(buf);
|
|
Packit |
df99a1 |
return result;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
/* TODO: use less temporary buffers and silly copyings */
|
|
Packit |
df99a1 |
MDJVU_IMPLEMENT void mdjvu_soften_pattern(byte **result, byte **pixels, int32 w, int32 h)/*{{{*/
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
byte *r = MALLOCV(byte, (w + 2) * (h + 2));
|
|
Packit |
df99a1 |
byte **pointers = MALLOCV(byte *, h + 2);
|
|
Packit |
df99a1 |
int *ranks_buf = MALLOCV(int, w * h);
|
|
Packit |
df99a1 |
int **ranks = MALLOCV(int *, h);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
int i, j, passes = 1;
|
|
Packit |
df99a1 |
double level = 1, falloff;
|
|
Packit |
df99a1 |
byte *colors;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
memset(r, 0, (w + 2) * (h + 2));
|
|
Packit |
df99a1 |
memset(ranks_buf, 0, w * h * sizeof(int));
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
for (i = 0; i < h + 2; i++)
|
|
Packit |
df99a1 |
pointers[i] = r + (w + 2) * i + 1;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
for (i = 0; i < h; i++)
|
|
Packit |
df99a1 |
memcpy(pointers[i+1], pixels[i], w);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
for (i = 0; i < h; i++)
|
|
Packit |
df99a1 |
ranks[i] = ranks_buf + w * i;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
while(flay(pointers + 1, w, h, passes, ranks)) passes++;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
colors = MALLOCV(byte, passes + 1);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
falloff = pow(BORDER_FALLOFF, 1./passes);
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
for (i = 0; i < passes; i++)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
colors[i] = (byte) (level * 255);
|
|
Packit |
df99a1 |
level *= falloff;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
/* TODO: test the next line */
|
|
Packit |
df99a1 |
/* colors[passes - 1] = 50; pay less attention to border pixels */
|
|
Packit |
df99a1 |
colors[passes] = 0;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
pointers++;
|
|
Packit |
df99a1 |
for (i = 0; i < h; i++)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
for (j = 0; j < w; j++)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (pointers[i][j])
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
result[i][j] = 255;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
result[i][j] = colors[passes - ranks[i][j]];
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
pointers--;
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
FREEV(colors);
|
|
Packit |
df99a1 |
FREEV(ranks);
|
|
Packit |
df99a1 |
FREEV(ranks_buf);
|
|
Packit |
df99a1 |
FREEV(r);
|
|
Packit |
df99a1 |
FREEV(pointers);
|
|
Packit |
df99a1 |
}/*}}}*/
|