/* hpcdtoppm (Hadmut's pcdtoppm) v0.6
*  Copyright (c) 1992, 1993, 1994 by Hadmut Danisch (danisch@ira.uka.de).
*  Permission to use and distribute this software and its
*  documentation for noncommercial use and without fee is hereby granted,
*  provided that the above copyright notice appear in all copies and that
*  both that copyright notice and this permission notice appear in
*  supporting documentation. It is not allowed to sell this software in 
*  any way. This software is not public domain.
*/

#include "hpcdtoppm.h"


void clearimpl(implane *l,sINT n)
{ dim x,y;
  uBYTE *ptr;

  ptr=l->im;
  for (x=0;x<l->mwidth;x++)
    for (y=0; y<l->mheight;y++)
      *(ptr++)=n;
}




void halve(implane *p)
 {dim w,h,x,y;
  uBYTE *optr,*nptr;

  melde("halve\n");
  if ((!p) || (!p->im)) error(E_INTERN);

  w=p->iwidth/=2;      
  h=p->iheight/=2;     


  for(y=0;y<h;y++)
   {
    nptr=(p->im) +   y*(p->mwidth);
    optr=(p->im) + 2*y*(p->mwidth);

    for(x=0;x<w;x++,nptr++,optr+=2)
     { *nptr = *optr;
     }

   }

 }







void interpolate(implane *p)
 {dim w,h,x,y,yi;
  uBYTE *optr,*nptr,*uptr;

  melde("interpolate\n");
  if ((!p) || (!p->im)) error(E_INTERN);

  w=p->iwidth;
  h=p->iheight;

  if(p->mwidth  < 2*w ) error(E_INTERN);
  if(p->mheight < 2*h ) error(E_INTERN);


  p->iwidth=2*w;
  p->iheight=2*h;


  for(y=0;y<h;y++)
   {yi=h-1-y;
    optr=p->im+  yi*p->mwidth + (w-1);
    nptr=p->im+2*yi*p->mwidth + (2*w - 2);

    nptr[0]=nptr[1]=optr[0];

    for(x=1;x<w;x++)
     { optr--; nptr-=2;
       nptr[0]=optr[0];
       nptr[1]=(((sINT)optr[0])+((sINT)optr[1])+1)>>1;
     }
    }

  for(y=0;y<h-1;y++)
   {optr=p->im + 2*y*p->mwidth;
    nptr=optr+p->mwidth;
    uptr=nptr+p->mwidth;

    for(x=0;x<w-1;x++)
     {
      nptr[0]=(((sINT)optr[0])+((sINT)uptr[0])+1)>>1;
      nptr[1]=(((sINT)optr[0])+((sINT)optr[2])+((sINT)uptr[0])+((sINT)uptr[2])+2)>>2;
      nptr+=2; optr+=2; uptr+=2;
     }
    *(nptr++)=(((sINT)*(optr++))+((sINT)*(uptr++))+1)>>1;
    *(nptr++)=(((sINT)*(optr++))+((sINT)*(uptr++))+1)>>1;
   }


  optr=p->im + (2*h-2)*p->mwidth;
  nptr=p->im + (2*h-1)*p->mwidth;
  for(x=0;x<w;x++)
   { *(nptr++) = *(optr++);  *(nptr++) = *(optr++); }

 }




static sINT testbegin(void)
 {sINT i,j;
  for(i=j=0;i<32;i++)
    if(sbuffer[i]==0xff) j++;

  return (j>30);
  
 }


sINT Skip4Base(void)
 {sINT cd_offset,cd_offhelp;
  
  cd_offset = L_Head + L_Base16 + L_Base4 + L_Base ;
  SEEK(cd_offset+3);          
  EREADBUF;    
  cd_offhelp=((((sINT)sbuffer[510])<<8)|sbuffer[511]) + 1;

  cd_offset+=cd_offhelp;

  SEEK(cd_offset);
  EREADBUF;
  while(!testbegin())
   {cd_offset++;
    EREADBUF;
   }
  return cd_offset;
 }





void planealloc(implane *p, dim width, dim height)
 {melde("planealloc\n");
 
  p->iwidth=p->iheight=0;
  p->mwidth=width;
  p->mheight=height;

  p->mp = ( p->im = ( uBYTE * ) malloc  (width*height*sizeof(uBYTE)) );
  if(!(p->im)) error(E_MEM);
 }
 


static void pastequer(implane *gross,dim px,dim py,implane *klein)
 {dim x,y;
  uBYTE *von,*nach;

  if(px+klein->iwidth  > gross->iwidth)  error(E_INTERN);
  if(py+klein->iheight > gross->iheight) error(E_INTERN);

  for(y=0;y<klein->iheight;y++)
   { von=klein->im + y * klein->mwidth;
     nach=gross->im + (y+py) * gross->mwidth + px;
     for(x=0;x<klein->iwidth;x++)
        *(nach++)=*(von++);
   }
 }

 
static void pastehead(implane *gross,dim px,dim py,implane *klein)
 {dim x,y;
  uBYTE *von,*nach;

  if(px+klein->iwidth  > gross->iwidth)  error(E_INTERN);
  if(py+klein->iheight > gross->iheight) error(E_INTERN);

  for(y=0;y<klein->iheight;y++)
   { von= klein->im + (klein->iheight-1-y) * klein->mwidth + (klein->iwidth - 1);
     nach=gross->im + (y+py) * gross->mwidth + px;
     for(x=0;x<klein->iwidth;x++)
        *(nach++)=*(von--);
   }
 }

 
static void pastelinks(implane *gross,dim px,dim py,implane *klein)
 {dim x,y;
  uBYTE *von,*nach;

  if(px+klein->iheight > gross->iwidth)  error(E_INTERN);
  if(py+klein->iwidth  > gross->iheight) error(E_INTERN);

  for(y=0;y<klein->iwidth;y++)
   { von=klein->im + klein->iwidth - 1 - y;
     nach=gross->im + (y+py) * gross->mwidth + px;
     for(x=0;x<klein->iheight;x++,von+=klein->mwidth)
        *(nach++)=*(von);
   }
 }
 
static void pasterechts(implane *gross,dim px,dim py,implane *klein)
 {dim x,y;
  uBYTE *von,*nach;

  if(px+klein->iheight > gross->iwidth)  error(E_INTERN);
  if(py+klein->iwidth  > gross->iheight) error(E_INTERN);

  for(y=0;y<klein->iwidth;y++)
   { von=klein->im + (klein->iheight-1)*klein->mwidth + y;
     nach=gross->im + (y+py) * gross->mwidth + px;
     for(x=0;x<klein->iheight;x++,von-=klein->mwidth)
        *(nach++)=*(von);
   }
 }


void pastein(implane *gross,
             dim xpos,dim xw,
             dim ypos,dim yh,
             implane *klein, enum TURNS ori)
 {
  switch (ori)
   {
    case T_NONE: pastequer(gross,xpos+(xw-klein->iwidth)/2,ypos+(yh-klein->iheight)/2,klein);
                 break;
    case T_LEFT: pastelinks(gross,xpos+(xw-klein->iheight)/2,ypos+(yh-klein->iwidth)/2,klein);
                 break;
    case T_RIGHT:pasterechts(gross,xpos+(xw-klein->iheight)/2,ypos+(yh-klein->iwidth)/2,klein);
                 break;
    case T_HEAD: pastehead(gross,xpos+(xw-klein->iwidth)/2,ypos+(yh-klein->iheight)/2,klein);
                 break;
    case T_AUTO:
    default: error(E_INTERN);
   }
 }




#define cro(p,d) {if(p) {p->im+=d*p->mwidth; p->iheight-=d;}}
#define cru(p,d) {if(p) {p->iheight-=d;}}
#define crl(p,d) {if(p) {p->im+=d; p->iwidth-=d;}}
#define crr(p,d) {if(p) {p->iwidth-=d;}}

void cropit(sizeinfo *si,implane *l,implane *c1,implane *c2)
 {dim x,y,s,w,h;
  sINT nl,nr,no,nu;

  uBYTE *ptr;

  melde("crop\n");

  if(si->imvlen || si->imhlen) error(E_INTERN);
  w=si->rdhlen;
  h=si->rdvlen;

  if((!l) || (l->iwidth != w) || (l->iheight != h)) error(E_INTERN);
  
  if(!monochrome)
   {if((!c1) || (c1->iwidth != w) || (c1->iheight != h)) error(E_INTERN);
    if((!c2) || (c2->iwidth != w) || (c2->iheight != h)) error(E_INTERN);
   }


  for(y=0,no=0;y<h;y++,no++)
   {for(x=0,ptr=(l->im)+y*(l->mwidth); x<w && (*ptr)<MAX_BLACK ;x++,ptr++);
    if(x<w) break;
   }
  cro(l ,no);
  cro(c1,no);
  cro(c2,no);
  h-=no;


  for(y=h-1,nu=0;y;y--,nu++)
   {for(x=0,ptr=(l->im)+y*(l->mwidth); x<w && (*ptr)<MAX_BLACK ;x++,ptr++);
    if(x<w) break;
   }
  cru(l ,nu);
  cru(c1,nu);
  cru(c2,nu);
  h-=nu;


  s=l->mwidth;

  for(x=0,nl=0;x<w;x++,nl++)
   {for(y=0,ptr=(l->im)+x; y<h && (*ptr)<MAX_BLACK ; y++, ptr+=s);
    if(y<h) break;
   }
  crl(l ,nl);
  crl(c1,nl);
  crl(c2,nl);
  w-=nl;
  

  for(x=w-1,nr=0;x;x--,nr++)
   {for(y=0,ptr=(l->im)+x; y<h && (*ptr)<MAX_BLACK ; y++, ptr+=s);
    if(y<h) break;
   }
  crr(l ,nr);
  crr(c1,nr);
  crr(c2,nr);
  w-=nr;
  
  if (do_melde) 
   {
    if (no || nu || nr || nl )
      fprintf(stderr,"Cut off %d top, %d bottom, %d left, %d right,  new size is %dx%d\n",
              no,nu,nl,nr,w,h);
    else
      fprintf(stderr,"Nothing cut off\n");
   }

  si->imvlen=h;
  si->imhlen=w;
 }















void shrink(sizeinfo *si,implane *l,implane *c1,implane *c2)
 {dim w,h;

  melde("shrink\n");

  w=si->rdhlen;
  h=si->rdvlen;

  if((!l) || (l->iwidth != w) || (l->iheight != h)) error(E_INTERN);
  
  if(!monochrome)
   {if((!c1) || (c1->iwidth != w) || (c1->iheight != h)) error(E_INTERN);
    if((!c2) || (c2->iwidth != w) || (c2->iheight != h)) error(E_INTERN);
   }

  if((!si->imvlen) && (!si->imhlen))  /* no subrectangle given */
   {si->imvlen=si->rdvlen;
    si->imhlen=si->rdhlen;
    return;
   }

  if (si->imvlen>h || si->imvlen<1 )       error(E_INTERN);
  if (si->imvoff> si->rdvlen - si->imvlen) error(E_INTERN);

  if (si->imhlen>w || si->imhlen<1 ) error(E_INTERN);
  if (si->imhoff> si->rdhlen - si->imhlen) error(E_INTERN);

  cro(l ,si->imvoff);
  cro(c1,si->imvoff);
  cro(c2,si->imvoff);

  cru(l ,si->rdvlen - si->imvoff - si->imvlen);
  cru(c1,si->rdvlen - si->imvoff - si->imvlen);
  cru(c2,si->rdvlen - si->imvoff - si->imvlen);
  
  crl(l ,si->imhoff);
  crl(c1,si->imhoff);
  crl(c2,si->imhoff);

  crr(l ,si->rdhlen - si->imhoff - si->imhlen);
  crr(c1,si->rdhlen - si->imhoff - si->imhlen);
  crr(c2,si->rdhlen - si->imhoff - si->imhlen);
  

 }



/* Test Data types for their size an whether they 
   are signed / unsigned */

void typecheck(void)
 { sBYTE sbyte;
   uBYTE ubyte;
   sINT  sint;
   uINT  uint;


   if(sizeof(sBYTE) != 1) error(E_CONFIG);
   sbyte=126; sbyte++; sbyte++;
   if(sbyte > 126 ) error(E_CONFIG);

   if(sizeof(uBYTE) != 1) error(E_CONFIG);
   ubyte=126; ubyte++; ubyte++;
   if(ubyte < 126 ) error(E_CONFIG);

#ifdef U_TOO_LONG
   if(sizeof(sINT) < 4) error(E_CONFIG);
   if(sizeof(uINT) < 4) error(E_CONFIG);
#else
   if(sizeof(sINT) != 4) error(E_CONFIG);
   if(sizeof(uINT) != 4) error(E_CONFIG);
#endif

   sint=1; sint--; sint--;
   if(sint>1) error(E_CONFIG);

   uint=1; uint--; uint--;
   if(uint<1) error(E_CONFIG);

 }

