Nickolay.info. Алгоритмы. Чтение и запись формата PCX на Си

Был некогда такой популярный графический формат, поддерживал до 256 цветов, паковал данные построчно. Приложенная ниже демка содержит функции для чтения и записи 256-цветных правильно запакованных файлов PCX. Запускать её нужно с одним или двумя параметрами, переданными через командную строку, например, так:

pcx256 test.pcx result.pcx

Как и любые графические DOS-программы, работать демка будет только из-под эмулятора, такого как DOSbox.

Конечно, демка в данном случае запишет то же, что прочитала, но метод WritePCX может писать и любую нужную область с экрана.

Вот файл test.pcx (новое окно). Не знаю, покажет ли его Ваш браузер. Стандартные графические программы офиса точно это умеют.

 test.pcx (13 Кб)

#include <stdio.h>
#include <alloc.h>
 
typedef struct pcxheader {
 char manuf;
 char hard;
 char endcod;
 char bitpx;
 int x1,y1,x2,y2;
 int hres,vres;
 char clrma[48];
 char vmode;
 char nplanes;
 int bplin;
 int palinfo;
 int shres,svres;
 int xtra[54];
} PCXHEADER;
 
void putpixel (int X, char Y, char C) {
 // Устанавливает пиксел (X,Y) в цвет Color
 asm  mov bx,X;
 asm  mov cl,Y;
 asm  mov dl,C;
 asm  mov ax,0a000h;
 asm  mov es,ax;
 asm  mov al,0a0h;
 asm  mul cl;
 asm  add ax,ax;
 asm  add bx,ax;
 asm  mov [es:bx],dl;
return;
}
 
char getpixel (int X, char Y) {
 // Возвращает цвет пиксела (X,Y)
 asm  mov bx,X;
 asm  mov cl,Y;
 asm  mov ax,0a000h;
 asm  mov es,ax;
 asm  mov al,0a0h;
 asm  mul cl;
 asm  add ax,ax;
 asm  add bx,ax;
 asm  mov al,[es:bx];
return (_AL);
}
 
void setpalette (int Num,char R_, char G_, char B_) {
 asm mov ax,0x1010;
 asm mov bx,Num;
 asm mov dh,R_;
 asm mov ch,G_;
 asm mov cl,B_;
 asm int 10h;
 return;
}
 
void getpalette (int Num,char *R_, char *G_, char *B_) {
 char R,G,B;
 asm mov ax,0x1015;
 asm mov bx,Num;
 asm int 10h;
 asm mov R,dh;
 asm mov G,ch;
 asm mov B,cl;
 *R_=R; *G_=G; *B_=B;
 return;
}
 
char Table[768];
 
void setallpalette (void) {
 asm push es;
 asm mov ax, seg Table;
 asm mov es,ax;
 asm mov dx, offset Table;
 asm mov ax, 0x1012;
 asm mov bx,0;
 asm mov cx,256;
 asm int 10h;
 asm pop es;
 return;
}
 
void getallpalette (void) {
 asm push es;
 asm mov ax, seg Table;
 asm mov es,ax;
 asm mov dx, offset Table;
 asm mov ax, 0x1017;
 asm mov bx,0;
 asm mov cx,256;
 asm int 10h;
 asm pop es;
 return;
}
 
static PCXHEADER header;
FILE *fp;
 
unsigned char WritePCX (int x1,int y1,int x2,int y2,char *fname) {
 // Возвращает 0 в случае успеха
 // 1 - ошибка открытия файла
 // 3 - ошибка записи в файл
 // 11 - нет памяти для буферов
 int y,x,i,len=128;
 unsigned char  *buffer, *mb, *pack_buffer, *mpb;
 int buf_full,pack_count;
 unsigned char rep,cur_byte,Ten=0x0C,R,G,B;
 fp=fopen(fname,"wb");
 if (fp==NULL) return 1;
 header.manuf=0x0A;
 header.hard=5;
 header.endcod=1;
 header.bitpx=8;
 header.x1=x1; header.y1=y1;
 header.x2=x2; header.y2=y2;
 header.hres=0;   header.vres=0;
 header.vmode=0x13; header.nplanes=1;
 header.bplin=320;  header.palinfo=1;
 for (i=0; i<16; i++) { // Палитра 16 цветов
  getpalette (i,&R, &G, &B);
  header.clrma[3*i]=R<<2;
  header.clrma[3*i+1]=G<<2;
  header.clrma[3*i+2]=B<<2;
 }
 i=fwrite (&header,1,len,fp);
 if (!i) return -2;
 buffer=(unsigned char *)malloc(320);
 pack_buffer=(unsigned char *)malloc(640);
 //Размер "упакованного" м.б. в 2 раза больше, если исп.цвета старше 191
 //без повторений
 if ((buffer==NULL)||(pack_buffer==NULL)) return 11;
 for (y=y1;y<=y2;y++) {
  for (x=x1; x<=x2; x++) buffer[x-x1]=getpixel (x,y);
  mb=buffer;
  mpb=pack_buffer;
  buf_full=x2-x1+1;
  pack_count=0;
  for (;;) {
   if (buf_full==0) break;
   cur_byte=*mb++;
   rep=1;
   buf_full--;
   while ((*mb==cur_byte)&&(buf_full>0)) {
    mb++; rep++; buf_full--;
    if (buf_full==0) break; //Пакуем построчно;
     //Иначе в этом месте обновление буфера
    if (rep==63) break;
   }
   if (rep>1) {
    *mpb=(0xC0|rep); mpb++;
    *mpb=cur_byte; mpb++;
    pack_count+=2;
   }
   else if (cur_byte<0xC0) {
    *mpb=cur_byte; mpb++; pack_count++;
   }
   else {
    *mpb=0xC1; mpb++;
    *mpb=cur_byte; mpb++;
    pack_count+=2;
   }
  }
  i=fwrite (pack_buffer,1,pack_count,fp);
  if (!i) return 3;
 }
 fwrite (&Ten,1,1,fp);
 getallpalette(); // Палитра 256 цветов
 for (i=0; i<768; i++) (Table[i])<<=2;
 fwrite (&Table[0],768,1,fp);
 fclose (fp);
 free (buffer); free (pack_buffer);
 return 0;
}
 
unsigned char ReadPCX (char *fname) {
 // Возвращает 0 в случае успеха
 // 1 - ошибка открытия файла
 // 4 - ошибка чтения из файла
 // 11 - нет памяти для буферов
 int k,n,y,l,rest,rep_count=0,len=128,xpos; char ypos;
 unsigned char *planes,*buffer,*b,c,bits,Ten,R,G,B;
 fp=fopen(fname,"rb");
 if (fp==NULL) return 0x01;
 buffer=(unsigned char *)malloc(120);
 planes=(unsigned char *)malloc(3840);
 //Макс. сжатие 120 байт - в 32 раза, т.е. 3840 байт
 if ((buffer==NULL)||(planes==NULL)) return 11;
 l=fread (&header,len,1,fp);
 if (!l) return 0x04;
 
 fseek (fp,-769L,SEEK_END); fread (&Ten,1,1,fp);
 if (Ten==0x0A || Ten==0x0C) { // Получить палитру
  fread (&Table[0],768,1,fp);
  for (l=0; l<768; l++) {
   if (Ten==0x0C) (Table[l])>>=2;
   else (Table[l])&=0x3f;
  }
  setallpalette ();
 }
 
 fseek (fp,len,SEEK_SET);
 rest=fread (buffer,1,120,fp);
 b=buffer;
 xpos=header.x1; ypos=(unsigned char)header.y1;
 for (y=header.y1; y<=header.y2; y++) {
	      //header.nplanes*header.bplin;
  for (k=0; k<header.bplin; k+=rep_count) {
   if (rest==0) {
    rest=fread (buffer,1,120,fp);
    b=buffer;
   }
   c=b[0]; b++; rest--;
   if ((c&0xC0)==0xC0) {
    rep_count=(c&0x3F);
    if (rest==0) {
     rest=fread (buffer,1,120,fp);
     b=buffer;
    }
    bits=(*b); b++; rest--;
   }
   else { rep_count=1; bits=c; }
   for (l=0;l<rep_count;l++) planes[k+l]=bits;
  }
  for (l=0; l<k; l++) {
   if (xpos>header.x2) {
    xpos=header.x1; ypos++;
    if (ypos>header.y2) {
     ypos--; xpos=header.x2+1; break; }
   }
   putpixel (xpos,ypos,planes[l]);
   xpos++;
  }
 }
 free (planes); free (buffer);
 fclose (fp); return 0;
}
 
#include <stdlib.h>
void main(int argc, char *argv[]) {
 int i,j;
 asm {  mov ax,0013h; int 10h; }
// for (i=0;i<320;i++)
// for (j=0;j<200;j++) putpixel (i,j,(i+j)%256);
 if (argc>1) {
  i=ReadPCX (argv[1]);
  if (i) {
   printf ("\n Error %d",i);
   return;
  }
  //getallpalette();
  /* for (i=0; i<768; i++) {
   Table[i]=i%64;
  } */
  //setallpalette();
  //WritePCX (0,0,319,199,"!.pcx"); //!!!
 }
 if (argc>2) {
  WritePCX (0,0,319,199,argv[2]);
 }
/* else {
  WritePCX (0,0,319,199,"!.pcx");
  for (i=0;i<320;i++) 
  for (j=0;j<200;j++) putpixel (i,j,0);
  ReadPCX ("!.pcx");
 } */
 getchar();
 asm {  mov ax,0003h; int 10h; }
 return;
}

Рейтинг@Mail.ru

вверх гостевая; E-mail