Pers.narod.ru. Алгоритмы. Чтение и запись формата 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;
}
|
|