Logo Search packages:      
Sourcecode: paul version File versions  Download package

shrink.c

/*****************************************************************************
 *                                                                           *
 * Program:   paul                                                           *
 *            (P)rogramm zur (A)uswertung und (U)mformung von                *
 *            (L)aserbildern                                                 *
 * Modul:     shrink.c                                                       *
 *            Shrink an image "reasonable", i.e. in steps which make half    *
 *            thei width and half the size,  if the dimensions are odd       *
 *            numbers three border pixels end in one pixel                   *
 * Remark:    If it is intended to work also with storepix == 1 changes are  *
 *            necessary!!                                                    *
 * Author:    Andreas Tille                                                  *
 * Date:      07.05.1998                                                     *
 * Copyright: Andreas Tille, 1999; GNU Public License                        *
 *                                                                           *
 *****************************************************************************/

#include <stdio.h>
#include <string.h>

#include "paul.h"

static void ShrinkBorder(unsigned char *obuf, unsigned char *bbuf, 
                          int step, int nx, int ny)
/* Shrink the border
 * ATTENTION!! This function is designed to work only for storepix == 3 !!!
 * --- Parameter: ---
 * unsigned char *obuf  : Originaldatenpuffer
 * unsigned char *bbuf  : verkleinerter Puffer
 * int            step  : Schritt bis zur nächsten Zeile im Originalbild
 * int            nx    : 2 oder 3 pixel in x-Richtung zusammenfassen
 * int            ny    : 2 oder 3 pixel in y-Richtung zusammenfassen
 * --- R"uckgabe: ---
 * unsigned char *bbuf  : neues Pixel aus nx*ny alten Pixeln
 */
{
   register unsigned char *ap = obuf;
   register int  r = 0, g = 0, b = 0, n = 0;
   int      i, j;

   step -= 3*nx;
   for ( i = 0; i < ny; i++, ap += step ) {
      for ( j = 0; j < nx; j++ ) {
         n++;
         r += *(ap++);
         g += *(ap++);
         b += *(ap++);
      }
   }
   *bbuf   = r/n;
   *++bbuf = g/n;
   *++bbuf = b/n;
}

int ShrinkPicture(PICTURE *bild, unsigned char shr)
/* Shrink the image at a "reasonable" amount
 * --- Parameter: ---
 * PICTURE *bild           : image data structure
 * unsigned char shr       : level of shrinkage
 * --- Return: ---
 * int      ShrinkPicture(): RET_ERR or RET_OK
 */
{
#define MAX_SHRINK  5
#define MIN_SIZE   10
  unsigned char           zw = 0, *buf, *body, *bbody;
  register int            storepix;
  register unsigned char *ap, *bp, *fip, *fipp;
  int      w, h,           /* new dimensions */
           ix = 0, iy = 0, /* counter, how often left/right, top/bottom  *
                            * was put together                           */
           os, bs,         /* row step in the original image             */
           heightbody,     /* number of bytes from start to end of body  *
                            * ( = bild->storepix * bild->size )          */
           widthbody,      /* number of bytes in one line of the body    *
                            * ( = bild->storepix * bild->W )             */
           i;
  char    *desc, *app;
   
  g_return_val_if_fail ( IS_PICTURE(bild), RET_ERR ) ;
  storepix = bild->storepix;
   
  if ( shr == 0 ) {
    while ( (bild->W >> shr) * (bild->H >> shr) > 1000000 ) shr++;
    while ( (bild->W >> shr) > 2000 || (bild->H >> shr) > 2000 ) shr++;
  } else {
    zw = shr;
    if ( shr > MAX_SHRINK ) shr = MAX_SHRINK;
    while ( (bild->W >> shr) < MIN_SIZE || (bild->H >> shr) < MIN_SIZE )
      if ( --shr == 0 ) break;
    if ( zw != shr ) 
      g_warning("Width or height of image will be smaller than %i when shrinking %i levels!\n -> shrink only %i levels.", MIN_SIZE, zw, shr);
  }
   
   /* Eigentlich kann man ja alles in einem Ritt machen, doch die   *
    * Behandlung des Randes erfordert so viele Fallunterscheidungen *
    * (es sei denn es kommt mir noch eine klevere Idee), so daß     *
    * die einzelnen Schritte deutlich übersichtlicher zu            *
    * programmieren sind.                                           */

   /* HIER MUSZ ICH MIR NOCH EINEN SCHLAUEN TEST EINFALLEN LASSEN,  *
    * OB WIRKLICH IMMER WECHSELSEITIG ZUSAMMENGEFASZT WIRD!!!!!!!!! */
   /* AUSZERDEM MUSZ EIN SCHLAUES TESTBILD HER, WAS DEUTLICH MACHT, *
    * OB WIRKLICH ALLES SO WIE GEWÜNSCHT LÄUFT!!!!                  */
  for ( i = 0; i < shr; i++ ) {
    w   = bild->W >> 1;
    h   = bild->H >> 1;
    buf = g_malloc(storepix*w*h);

/* alles zur Kontrolle erstmal weiß machen, SPÄTER LÖSCHEN!!! */
/*memset(buf, 3*w*h, 255);                                    */
/* ... scheint OK zu sein!!                                   */
    os         = storepix*bild->W;
    bs         = storepix*w;
    heightbody = storepix*bild->size;
    widthbody  = os;
    body       = bild->DATA;
    bbody      = buf;
    if ( bild->W % 2 ) { /* odd width: make one column from three border columns */
      widthbody -= storepix;
      ap = bild->DATA;
      bp = buf;
      ix = !ix;
      if ( ix ) { /* every second run take the left border */
        if ( bild->H %2 ) {
          if ( iy ) { /* links oben zusammenfassen */
            ShrinkBorder(ap, bp, os, 3, 3);
            body   = (ap += storepix*os) + 3*storepix;
            bbody += bs + storepix;
            bp    += bs;
          } else { /* links unten zusammenfassen */
 /* Here is a bug which causes that the last row of the shrinked image remains black. *
  * Who will find that beast????                                                      */
            ShrinkBorder(ap+heightbody, bp + storepix*w*(h-1), os, 3, 3);
            body  += 3*storepix;
            bbody += storepix;
          }
          heightbody -= 3*storepix*(bild->W);
      }
      } else { /* every second run take the right border  */
        ap += os - 3*storepix;
      bp += bs - storepix;
      if ( bild->H %2 ) {
          if ( iy ) { /* rechts oben zusammenfassen */
            ShrinkBorder(ap, bp, os, 3, 3);
            body  += storepix*os;
            bbody += bs;
            ap    += storepix*os;
            bp    += bs;
          } else { /* rechts unten zusammenfassen */
            ShrinkBorder(ap+heightbody, bp + storepix*w*(h-1), os, 3, 3);
        }
          heightbody -= 3*storepix*(bild->W);
      }
      }
         /* rechts/links zusammen, da ap und bp entsprechend gesetzt */
      for ( fip = ap + heightbody; ap < fip; ap += 2*os, bp += bs)
        ShrinkBorder(ap, bp, os, 3, 2);
    }
    else if ( bild->H % 2 ) { /* odd height: make one row from three border rows */
      ap = bild->DATA;
      bp = buf;
      heightbody -= 3*storepix*bild->W;
      if ( (bild->W %2) && (ix) ) { /* links oben wurde schon zusammengefaßt */
        ap += storepix;
        bp++;
      }
      iy = !iy;  /* iy nun negiert => unten wenn true */
      if ( iy ) { /* ap/bp auf unten stellen */
        ap += storepix*(bild->W*(bild->H-3) + 1);
        bp += storepix*w*(h-1);
      }
      for ( fip = ap + widthbody; ap < fip; ap += (storepix<<1), bp += storepix )
      ShrinkBorder(ap, bp, os, 2, 3);
    }

    for ( fipp = body + heightbody; body < fipp; body += 2*os, bbody += bs ) 
      for ( fip = (ap = body) + widthbody, bp = bbody; ap < fip;
            ap += (storepix << 1), bp += storepix )
        ShrinkBorder(ap, bp, os, 2, 2);

    NewImage(bild, w, h, buf);
    bild->size = w*h;
  }

  desc = g_strdup_printf("%s shrinked at %i levels.", ImgFileName(bild), shr);
  app  = g_strdup_printf("%s%i", APPSHRINK, shr);
  ImgChunksUpdate(bild, TypShrink, desc, app, SHRINK);
  FREE(desc);
  FREE(app);
  return RET_OK;
   
#undef MAX_SHRINK
#undef MIN_SIZE
}


int ShrinkPictures(PAUL *p)
/* Shrink images at a "reasonable" amount
 * --- Parameter: ---
 * PAUL *p              : PAUL structure
 * --- Return: ---
 * int   ShrinkPicture(): RET_ERR or RET_OK
 */
{
  PICTURE *bild;
  GList   *pl;

  g_return_val_if_fail ( IS_PAUL(p), RET_ERR ) ;
  g_return_val_if_fail ( NBILDER(p->piclist), RET_ERR ) ;
  
  for ( bild = BILD(pl = p->piclist); pl; bild = BILD(pl = pl->next) ) 
    ShrinkPicture(BILD(pl), p->opt->shr);
  p->opt->shr = 0;
  p->opt->f  &= ~SHRINK;
  return RET_OK;
}





Generated by  Doxygen 1.6.0   Back to index