#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
typedef int BOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
#define FALSE 0
#define TRUE 1
BOOL GetBMPSize(FILE *BMPStream,long *offset);
void Write_CrossReferenceTable(FILE *AStream,DWORD ObjectPosArray[],int Count);
void Write_ContentsObject(FILE *AStream,DWORD ObjectPosArray[],int *ObjectIndex,int w,int h);
int BMPtoPDF(const char *OpenName,const char *SaveName);
int main(int argc,char *argv[]) {
if (argc >= 2)
return (BMPtoPDF(argv[1],argv[2]));
else {
printf("Not Found!/n");
return(1);
}
}
/* 1ラインの幅を算出 */
int GetLineWidth(WORD biBitCount, int biWidth) {
return ((biBitCount * biWidth + 15) / 16) * 2 ;
}
/* イメージデータのサイズを算出 */
int GetBitsSize(int biWidth, int biHeight,WORD biBitCount) {
switch (biBitCount) {
case 1:
return ( ((1 * biWidth + 15) / 16) * 2 * (biHeight) );
break;
case 4:
return ( ((4 * biWidth + 15) / 16) * 2 * (biHeight) );
break;
case 8:
return ( biWidth*biHeight ) ;
break;
case 24:
return ( biWidth*biHeight*3 );
break;
default :
return ( 0 );
break;
}
}
/* イメージデータの取得 */
BOOL GetBitsData(FILE *AStream,int bfOffBits,BYTE *BitsData, int biWidth, int biHeight,WORD biBitCount) {
int i;
BYTE Dummy[4],DummyCnt;
fseek(AStream,bfOffBits,SEEK_SET);
switch (biBitCount) {
case 1:
;
case 4:
;
case 8:
DummyCnt= biWidth % 4;
switch (DummyCnt) {
case 0:
for (i=0;i< biHeight;i++)
fread(BitsData+(biWidth*i),1,biWidth,AStream);
break;
case 1 :
;
case 2 :
;
case 3 :
;
for (i=0;i< biHeight;i++) {
fread(BitsData+(biWidth*i),1,biWidth,AStream);
fread(Dummy,1,4-DummyCnt,AStream);
}
break;
default:
return (FALSE);
}
break;
;
break;
case 24:
DummyCnt= biWidth % 4;
switch (DummyCnt) {
case 0:
for (i=0;i< biHeight;i++)
fread(BitsData+(biWidth*3*i),1,biWidth*3,AStream);
break;
case 1 :
;
case 2 :
;
case 3 :
for (i=0;i< biHeight;i++) {
fread(BitsData+(biWidth*3*i),1,biWidth*3,AStream);
fread(Dummy,1,DummyCnt,AStream);
}
break;
default:
return (FALSE);
}
break;
}
return (TRUE);
}
/* イメージデータを反転させる */
BOOL TurnBits(BYTE *BitsData,int BitsSize,int biWidth,WORD biBitCount) {
int i,j,LineWidth=0;
BYTE *buffer,*Linebuffer,tmp;
// 1ラインの幅を算出
switch (biBitCount) {
case 1:
;
case 4:
LineWidth=GetLineWidth(biBitCount,biWidth);
break;
case 8:
LineWidth=biWidth;
break;
case 24:
LineWidth=biWidth*3;
break;
}
Linebuffer=(BYTE *)malloc(LineWidth);
if (Linebuffer==NULL)
return FALSE;
buffer=(BYTE *)malloc(BitsSize);
if (buffer==NULL) {
free(Linebuffer);
return FALSE;
}
if (biBitCount==24) {
for (i=0;i< (BitsSize / LineWidth);i++) {
/* 1ラインを取得 */
memcpy(Linebuffer,BitsData+(LineWidth*i),LineWidth);
/* BGR<->RGB変換 */
for (j=0;j<LineWidth ;j+=3) {
tmp = Linebuffer[j];
Linebuffer[j] = Linebuffer[j+2];
Linebuffer[j+2] = tmp;
}
/* 1ラインをメモリに書き込む */
memcpy(buffer+ (BitsSize- LineWidth * (i+1) ),Linebuffer,LineWidth);
}
} else {
for (i=0;i< (BitsSize / LineWidth);i++) {
/* 1ラインを取得 */
memcpy(Linebuffer,BitsData+(LineWidth*i),LineWidth);
/* 1ラインをメモリに書き込む */
memcpy(buffer+ (BitsSize- LineWidth * (i+1) ),Linebuffer,LineWidth);
}
}
// 元のデータと置き換える
memcpy(BitsData,buffer,BitsSize);
free(buffer);
free(Linebuffer);
return(TRUE);
}
BOOL GetBMPSize(FILE *BMPStream,long *offset) {
//WORD wrk;
//BYTE Sampling;
//WORD SOF0 =0xFFC0; /* 通常 */
//WORD SOF2 =0xFFC2; /* 進歩 */
/*----------------------------*/
/* ファイルヘッダ部 (14 Byte) */
/*----------------------------*/
int count = 0;
long var_long;
short var_short;
char s[10];
// BITMAP 認識文字 "BM"
if (fread(s, 2, 1, BMPStream) == 1) {
if (memcmp(s, "BM", 2) == 0) {
printf("[BM] BITMAP file/n");
} else {
fprintf(stderr, "%s : Not a BITMAP file/n", s);
exit(1);
}
count += 2;
}
printf(" [BITMAPFILEHEADER]/n");
// ファイルサイズ
if (fread(&var_long, 4, 1, BMPStream) == 1) {
printf(" Size : %ld [Byte]/n", var_long);
count += 4;
}
// 予約領域 0
if (fread(&var_short, 2, 1, BMPStream) == 1) {
count += 2;
}
// 予約領域 0
if (fread(&var_short, 2, 1, BMPStream) == 1) {
count += 2;
}
// ファイルの先頭から画像データまでの位置
if (fread(&var_long, 4, 1, BMPStream) == 1) {
printf(" OffBits : %ld [Byte]/n", var_long);
*offset = var_long;
count += 4;
}
return count;
}
/*------------------------------------------------------------------*/
/* 情報ヘッダ部 (12 Byte -> OS/2 Bitmap, 40 Byte -> Windows Bitmap) */
/*------------------------------------------------------------------*/
int infoheader(FILE *BMPStream,
short *infosize,
long *width, long *height,
long *x_coodinate, long *y_coodinate,
short *BitCount,
long *ClrUsed) {
int count = 0;
long var_long, compress = 0;
short var_short;
// BITMAPINFOHEADER のサイズ
if (fread(&var_long, 4, 1, BMPStream) == 1) {
count += 4;
*infosize = var_long;
}
printf(" [BITMAPINFOHEADER]/n");
// OS/2 Bitmap
if (*infosize == 12) {
// 画像データの幅
if (fread(&var_short, 2, 1, BMPStream) == 1) {
printf(" Width : %d [pixel]/n", var_short);
*width = var_short;
count += 2;
}
// 画像データの高さ
if (fread(&var_short, 2, 1, BMPStream) == 1) {
printf(" Height : %d [pixel]/n", var_short);
*height = var_short;
count += 2;
}
// プレーン数 (1のみ)
if (fread(&var_short, 2, 1, BMPStream) == 1) {
count += 2;
}
// 1画素あたりのビット数 (1, 4, 8, 24, 32)
if (fread(&var_short, 2, 1, BMPStream) == 1) {
printf(" BitCount : %d [bit]/n", var_short);
*BitCount = var_short;
count += 2;
}
}
// Windows BMP
else if (*infosize == 40) {
// 画像データの幅
if (fread(&var_long, 4, 1, BMPStream) == 1) {
printf(" Width : %ld [pixel]/n", var_long);
*width = var_long;
count += 4;
}
// 画像データの高さ
if (fread(&var_long, 4, 1, BMPStream) == 1) {
printf(" Height : %ld [pixel]/n", var_long);
*height = var_long;
count += 4;
}
// プレーン数 (1のみ)
if (fread(&var_short, 2, 1, BMPStream) == 1) {
count += 2;
}
// 1画素あたりのビット数 (1, 4, 8, 24, 32)
if (fread(&var_short, 2, 1, BMPStream) == 1) {
printf(" BitCount : %d [bit]/n", var_short);
*BitCount = var_short;
count += 2;
}
// 圧縮方式 0 : 無圧縮
// 1 : BI_RLE8 8bit RunLength 圧縮
// 2 : BI_RLE4 4bit RunLength 圧縮
if (fread(&var_long, 4, 1, BMPStream) == 1) {
printf(" Compression : %ld/n", var_long);
compress = var_long;
count += 4;
}
// 画像データのサイズ
if (fread(&var_long, 4, 1, BMPStream) == 1) {
printf(" SizeImage : %ld [Byte]/n", var_long);
count += 4;
}
// 横方向解像度 (Pixel/meter)
if (fread(&var_long, 4, 1, BMPStream) == 1) {
printf(" XPelsPerMeter : %ld [pixel/m]/n", var_long);
*x_coodinate = var_long;
count += 4;
}
// 縦方向解像度 (Pixel/meter)
if (fread(&var_long, 4, 1, BMPStream) == 1) {
printf(" YPelsPerMeter : %ld [pixel/m]/n", var_long);
*y_coodinate = var_long;
count += 4;
}
// 使用色数
if (fread(&var_long, 4, 1, BMPStream) == 1) {
printf(" ClrUsed : %ld [color]/n", var_long);
*ClrUsed = var_long;
count += 4;
}
// 重要な色の数 0の場合すべての色
if (fread(&var_long, 4, 1, BMPStream) == 1) {
count += 4;
}
} else {
fprintf(stderr, "Bitmap Info Header error/n");
}
if (compress != 0) {
fprintf(stderr, "圧縮ビットマップには対応していません/n");
exit(1);
}
if (*BitCount == 4 || *BitCount == 8 || *BitCount == 24 || *BitCount == 32) {
;
} else {
fprintf(stderr, "%d ビット色には対応していません/n", *BitCount);
exit(1);
}
return count;
}
/*-------------*/
/* OS/2 bitmap */
/*-------------*/
int rgbtriple(FILE *BMPStream,
long used,
unsigned char *red,
unsigned char *green,
unsigned char *blue) {
long i;
int count = 0;
// ビットの並びは B G R
for (i = 0; i < used; i++) {
blue[i] = fgetc(BMPStream);
green[i] = fgetc(BMPStream);
red[i] = fgetc(BMPStream);
count++;
}
return count;
}
/*----------------*/
/* Windows bitmap */
/*----------------*/
int rgbquad(FILE *BMPStream,
long used,
unsigned char *red,
unsigned char *green,
unsigned char *blue) {
long i;
int receive, count = 0;
// ビットの並びは B G R 予約
for (i = 0; i < used; i++) {
blue[i] = fgetc(BMPStream);
green[i] = fgetc(BMPStream);
red[i] = fgetc(BMPStream);
receive = fgetc(BMPStream);
count++;
}
return count;
}
void Write_CrossReferenceTable(FILE *AStream,DWORD ObjectPosArray[],int Count) {
int i;
fprintf(AStream,"xref/n");
fprintf(AStream,"0 %d/n",Count+1);
fprintf(AStream,"0000000000 65535 f /n");
for (i= 0; i<=Count-1;i++)
fprintf(AStream,"%0.10d 00000 n /n",ObjectPosArray[i]);
}
void Write_ContentsObject(FILE *AStream,DWORD ObjectPosArray[],int *ObjectIndex,int w,int h) {
int Length;
/* PDFコンテンツ */
ObjectPosArray[*ObjectIndex] =(DWORD)ftell(AStream);
fprintf(AStream,"%d 0 obj/n",*ObjectIndex+1);
fprintf(AStream,"<< /Length %d 0 R >>/n",*ObjectIndex+2);
fprintf(AStream,"stream/n");
/* stream */
Length=ftell(AStream);
fprintf(AStream,"q/n");
fprintf(AStream,"%d 0 0 %d 0 0 cm/n",w,h);
fprintf(AStream,"/Im0 Do/n");
fprintf(AStream,"Q/n");
Length=ftell(AStream)-Length;
fprintf(AStream,"endstream/n");
fprintf(AStream,"endobj/n");
*ObjectIndex=*ObjectIndex+1;
/* stream Length */
ObjectPosArray[*ObjectIndex] =(DWORD)ftell(AStream);
fprintf(AStream,"%d 0 obj/n",*ObjectIndex+1);
fprintf(AStream,"%d/n",Length);
fprintf(AStream,"endobj/n");
*ObjectIndex=*ObjectIndex+1;
}
int BMPtoPDF(const char *OpenName,const char *SaveName) {
int ObjectIndex;
short infosize, bits;
long used = 0, color = 0, offset, width, height, xreso, yreso;
unsigned char red[256],blue[256],green[256];
DWORD ObjectPosArray[10];
FILE *BMPStream,*AStream;
int i,j=0;
DWORD BitsSize; // イメージデータのサイズ
BYTE *BitsData; // イメージデータ
BYTE BitsPalette[768]; // カラーパレット
ObjectIndex=0;
/* BMPファイルを開く*/
BMPStream=fopen(OpenName,"rb");
if(BMPStream==NULL) {
printf("Error : Can not Open File./n");
return(-1);
}
// ヘッダ情報 BITMAPFILEHEADER
GetBMPSize(BMPStream, &offset);
// ヘッダ情報 BITMAPINFOHEADER
infoheader(BMPStream, &infosize, &width, &height, &xreso, &yreso, &bits, &color);
//color = usedcolor(bits, color);
// OS/2 Bitmap
if (infosize == 12) {
if (bits == 1 || bits == 4 || bits == 8) {
used = rgbtriple(BMPStream, color, red, green, blue);
}
printf("[OS/2 bitmap] --- %d bit %ld color/n", bits, used);
}
// Windows Bitmap
else if (infosize == 40) {
if (bits == 1 || bits == 4 || bits == 8) {
used = rgbquad(BMPStream, color, red, green, blue);
}
printf("[Windows bitmap] --- %d bit %ld color/n", bits, used);
} else if (infosize == 108) {
printf("[other bitmap]/n");
} else {
fprintf(stderr, "BITMAP INFOHEADER error/n");
}
/* とりあえず、8bitと24bitのみ*/
if (!(bits == 8 || bits == 24)) {
printf("Error : 対応していない形式です/n");
fclose(BMPStream);
return(-1);
}
/* PDFファイル作成 */
AStream=fopen(SaveName,"wb+");
if(AStream==NULL) {
printf("Error : Can not Create File./n");
fclose(BMPStream);
return(-1);
}
/* ------------------------------------------------------------- */
/* Writting PDF (PDFの書式) */
/* ------------------------------------------------------------- */
/* PDF のバージョン */
fprintf(AStream,"%%PDF-1.2/n");
/* Catalog */
ObjectPosArray[ObjectIndex] =ftell(AStream);
fprintf(AStream,"%d 0 obj/n",ObjectIndex+1);
fprintf(AStream,"<</n");
fprintf(AStream,"/Type /Catalog/n");
fprintf(AStream,"/Pages 2 0 R/n");
/* View Option (100%) */
fprintf(AStream,"/OpenAction [3 0 R /XYZ -32768 -32768 1 ]/n");
fprintf(AStream,">>/n");
fprintf(AStream,"endobj/n");
ObjectIndex++;
/* Parent Pages */
ObjectPosArray[ObjectIndex] =ftell(AStream);
fprintf(AStream,"%d 0 obj/n",ObjectIndex+1);
fprintf(AStream,"<</n");
fprintf(AStream,"/Type /Pages/n");
fprintf(AStream,"/Kids [ 3 0 R ]/n");
fprintf(AStream,"/Count 1/n");
fprintf(AStream,">>/n");
fprintf(AStream,"endobj/n");
ObjectIndex++;
/* Kids Page */
ObjectPosArray[ObjectIndex] =ftell(AStream);
fprintf(AStream,"%d 0 obj/n",ObjectIndex+1);
fprintf(AStream,"<</n");
fprintf(AStream,"/Type /Page/n");
fprintf(AStream,"/Parent 2 0 R/n");
fprintf(AStream,"/Resources/n");
fprintf(AStream,"<</n");
fprintf(AStream,"/XObject << /Im0 4 0 R >>/n");
// ProcSet
switch (bits) {
case 4 :
;
case 8 :
fprintf(AStream,"/ProcSet [ /PDF /ImageI ]/n");
break;
default :
fprintf(AStream,"/ProcSet [ /PDF /ImageC ]/n");
break;
}
fprintf(AStream,">>/n");
fprintf(AStream,"/MediaBox [ 0 0 %d %d ]/n",width,abs(height));
// コンテンツのオブジェクト番号
switch (bits) {
case 4 :
;
case 8 :
fprintf(AStream,"/Contents 6 0 R/n");
break;
default :
fprintf(AStream,"/Contents 5 0 R/n");
break;
}
fprintf(AStream,">>/n");
fprintf(AStream,"endobj/n");
ObjectIndex++;
/* XObject Resource */
ObjectPosArray[ObjectIndex] =ftell(AStream);
fprintf(AStream,"%d 0 obj/n",ObjectIndex+1);
fprintf(AStream,"<</n");
fprintf(AStream,"/Type /XObject/n");
fprintf(AStream,"/Subtype /Image/n");
fprintf(AStream,"/Name /Im0/n");
fprintf(AStream,"/Width %d/n",width);
fprintf(AStream,"/Height %d/n",abs(height));
fprintf(AStream,"/Filter []/n");
/* BitsPerComponent */
switch (bits) {
case 1 :
fprintf(AStream,"/BitsPerComponent 1/n");
break;
case 4 :
fprintf(AStream,"/BitsPerComponent 4/n");
break;
default :
fprintf(AStream,"/BitsPerComponent 8/n");
break;
}
/* ColorSpace */
switch (bits) {
case 1 :
fprintf(AStream,"/ColorSpace /DeviceGray/n");
break;
case 4 :
;
case 8 :
fprintf(AStream,"/ColorSpace [/Indexed /DeviceRGB 255 %d 0 R]/n",ObjectIndex+2);
break;
case 24 :
fprintf(AStream,"/ColorSpace /DeviceRGB/n");
break;
}
/* イメージデータのサイズを算出 */
BitsSize =GetBitsSize(width, abs(height),bits);
fprintf(AStream,"/Length %d >>/n",BitsSize);
/* イメージデータの書き込み */
fprintf(AStream,"stream/n");
/* 生データを突っ込む */
BitsData=(BYTE *)malloc(BitsSize);
GetBitsData(BMPStream,offset,BitsData,width,height,bits);
TurnBits(BitsData,BitsSize,width,bits);
fwrite(BitsData,1,BitsSize,AStream);
free(BitsData);
fprintf(AStream,"/nendstream/n");
fprintf(AStream,"endobj/n");
ObjectIndex++;
// カラーパレットの書き込み
if (bits==4 || bits==8) {
for (i=0;i<768;i+=3) {
BitsPalette[i] = red[j];
BitsPalette[i+1]= green[j];
BitsPalette[i+2]= blue[j];
j++;
}
ObjectPosArray[ObjectIndex] =ftell(AStream);
fprintf(AStream,"%d 0 obj/n",ObjectIndex+1);
fprintf(AStream,"<</n");
fprintf(AStream,"/Length 768/n");
fprintf(AStream,"/Filter []/n");
fprintf(AStream,">>/n");
fprintf(AStream,"stream/n");
fwrite(BitsPalette,1,768,AStream);
fprintf(AStream,"/nendstream/n");
fprintf(AStream,"endobj/n");
ObjectIndex++;
}
/* Contents Stream & Object */
Write_ContentsObject(AStream,ObjectPosArray,&ObjectIndex,width,height);
/* CrossReferenceTable */
ObjectPosArray[ObjectIndex] =ftell(AStream);
Write_CrossReferenceTable(AStream,ObjectPosArray,(int)ObjectIndex);
/* trailer */
fprintf(AStream,"trailer/n");
fprintf(AStream,"<</n");
fprintf(AStream,"/Size %d/n",ObjectIndex+1);
fprintf(AStream,"/Root 1 0 R/n");
fprintf(AStream,">>/n");
fprintf(AStream,"startxref/n");
fprintf(AStream,"%d/n",ObjectPosArray[ObjectIndex]);
fprintf(AStream,"%%%%EOF/n");
fclose(BMPStream);
fclose(AStream);
printf("/nSuccess!/n");
return (0);
}