comparison src/libgfx.c @ 1279:0d3f5f44c0c4

Somewhat improve PCX read support in libgfx.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 18 Aug 2017 02:03:15 +0300
parents 4e074b9b4789
children 300a51e98fc3
comparison
equal deleted inserted replaced
1278:5206e3d4e6b7 1279:0d3f5f44c0c4
679 return res; 679 return res;
680 } 680 }
681 #endif 681 #endif
682 682
683 683
684 #define DMPCX_PAL_COLORS 16 // Number of internal palette colors
685
684 typedef struct 686 typedef struct
685 { 687 {
686 Uint8 r,g,b; 688 Uint8 r,g,b;
687 } DMPCXColor; 689 } DMPCXColor;
688 690
689 691
690 typedef struct 692 typedef struct
691 { 693 {
692 Uint8 manufacturer, 694 Uint8 manufacturer, // always 0x0a
693 version, 695 version, // Z-Soft PCX Paintbrush version:
694 encoding, 696 // 0 = v2.5, 2 = v2.8 with palette, 3 = v2.8 without palette, 5 = v3.0 or better
695 bpp; 697 encoding, // usually 0x01 = RLE, 0x00 = uncompressed
698 bitsPerPlane; // bits per pixel per plane
699
696 Uint16 xmin, ymin, xmax, ymax; 700 Uint16 xmin, ymin, xmax, ymax;
697 Uint16 hres, vres; 701 Uint16 hres, vres; // resolution in DPI, can be image dimensions as well.
698 DMPCXColor colormap[16]; 702 DMPCXColor colorMap[DMPCX_PAL_COLORS];
699 Uint8 reserved; 703 Uint8 reserved; // should be set to 0
700 Uint8 nplanes; 704 Uint8 nplanes; // number of planes
701 Uint16 bpl; 705 Uint16 bpl; // bytes per plane LINE
702 Uint16 palinfo; 706 Uint16 palInfo; // 1 = color/BW, 2 = grayscale
703 Uint8 filler[58]; 707 Uint16 hScreenSize, vScreenSize;
708 Uint8 filler[54];
704 } DMPCXHeader; 709 } DMPCXHeader;
705 710
706 711
707 typedef struct 712 typedef struct
708 { 713 {
740 } 745 }
741 746
742 static int dmWritePCXRow(void *cbdata, Uint8 *row, size_t len) 747 static int dmWritePCXRow(void *cbdata, Uint8 *row, size_t len)
743 { 748 {
744 DMPCXData *pcx = (DMPCXData *) cbdata; 749 DMPCXData *pcx = (DMPCXData *) cbdata;
745 int plane;
746 size_t soffs = 0; 750 size_t soffs = 0;
747 751
748 // fprintf(stderr, "%d, %d * %d = %d\n", len, pcx->header->bpl, pcx->header->nplanes, pcx->header->nplanes * pcx->header->bpl); 752 // fprintf(stderr, "%d, %d * %d = %d\n", len, pcx->header->bpl, pcx->header->nplanes, pcx->header->nplanes * pcx->header->bpl);
749 753
750 pcx->bufOffs = 0; 754 pcx->bufOffs = 0;
751 755
752 for (plane = 0; plane < pcx->header->nplanes; plane++) 756 for (int plane = 0; plane < pcx->header->nplanes; plane++)
753 { 757 {
754 Uint8 data = dmPCXGetByte(row, len, soffs++), 758 Uint8 data = dmPCXGetByte(row, len, soffs++),
755 count = 1; 759 count = 1;
756 760
757 // size_t blen = pcx->header->bpl * pcx->header->nplanes; 761 // size_t blen = pcx->header->bpl * pcx->header->nplanes;
812 816
813 // Create PCX header 817 // Create PCX header
814 dmMemset(&hdr, 0, sizeof(hdr)); 818 dmMemset(&hdr, 0, sizeof(hdr));
815 if (spec->paletted) 819 if (spec->paletted)
816 { 820 {
817 int i; 821 for (int i = 0; i < (img->ncolors > DMPCX_PAL_COLORS ? DMPCX_PAL_COLORS : img->ncolors); i++)
818 for (i = 0; i < (img->ncolors > 16 ? 16 : img->ncolors); i++) 822 {
819 { 823 hdr.colorMap[i].r = img->pal[i].r;
820 hdr.colormap[i].r = img->pal[i].r; 824 hdr.colorMap[i].g = img->pal[i].g;
821 hdr.colormap[i].g = img->pal[i].g; 825 hdr.colorMap[i].b = img->pal[i].b;
822 hdr.colormap[i].b = img->pal[i].b;
823 } 826 }
824 } 827 }
825 hdr.manufacturer = 10; 828 hdr.manufacturer = 10;
826 hdr.version = 5; 829 hdr.version = 5;
827 hdr.encoding = 1; 830 hdr.encoding = 1;
828 hdr.bpp = 8; 831 hdr.bitsPerPlane = 8;
829 hdr.hres = img->width * spec->scaleX; 832 hdr.hres = img->width * spec->scaleX;
830 hdr.vres = img->height * spec->scaleY; 833 hdr.vres = img->height * spec->scaleY;
831 hdr.xmin = hdr.ymin = 0; 834 hdr.xmin = hdr.ymin = 0;
832 hdr.xmax = hdr.hres - 1; 835 hdr.xmax = hdr.hres - 1;
833 hdr.ymax = hdr.vres - 1; 836 hdr.ymax = hdr.vres - 1;
834 hdr.nplanes = dmImageGetBytesPerPixel(pcx.format); 837 hdr.nplanes = dmImageGetBytesPerPixel(pcx.format);
835 hdr.palinfo = 1; 838 hdr.palInfo = 1;
836 839
837 res = (img->width * spec->scaleX); 840 res = (img->width * spec->scaleX);
838 hdr.bpl = res / 2; 841 hdr.bpl = res / 2;
839 if (res % 2) hdr.bpl++; 842 if (res % 2) hdr.bpl++;
840 hdr.bpl *= 2; 843 hdr.bpl *= 2;
841 844
842 dmMsg(3, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n", 845 dmMsg(3, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n",
843 spec->paletted, hdr.nplanes, hdr.bpp, hdr.bpl); 846 spec->paletted, hdr.nplanes, hdr.bitsPerPlane, hdr.bpl);
844 847
845 pcx.bufLen = hdr.bpl * 4; 848 pcx.bufLen = hdr.bpl * 4;
846 if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL) 849 if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
847 { 850 {
848 res = dmError(DMERR_MALLOC, 851 res = dmError(DMERR_MALLOC,
853 856
854 // Write PCX header 857 // Write PCX header
855 if (!dm_fwrite_byte(pcx.fp, hdr.manufacturer) || 858 if (!dm_fwrite_byte(pcx.fp, hdr.manufacturer) ||
856 !dm_fwrite_byte(pcx.fp, hdr.version) || 859 !dm_fwrite_byte(pcx.fp, hdr.version) ||
857 !dm_fwrite_byte(pcx.fp, hdr.encoding) || 860 !dm_fwrite_byte(pcx.fp, hdr.encoding) ||
858 !dm_fwrite_byte(pcx.fp, hdr.bpp)) 861 !dm_fwrite_byte(pcx.fp, hdr.bitsPerPlane))
859 { 862 {
860 res = dmError(DMERR_FWRITE, 863 res = dmError(DMERR_FWRITE,
861 "PCX: Could not write basic header data.\n"); 864 "PCX: Could not write basic header data.\n");
862 goto error; 865 goto error;
863 } 866 }
872 res = dmError(DMERR_FWRITE, 875 res = dmError(DMERR_FWRITE,
873 "PCX: Could not write image dimensions.\n"); 876 "PCX: Could not write image dimensions.\n");
874 goto error; 877 goto error;
875 } 878 }
876 879
877 if (!dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap))) 880 if (!dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.colorMap, sizeof(hdr.colorMap)))
878 { 881 {
879 res = dmError(DMERR_FWRITE, 882 res = dmError(DMERR_FWRITE,
880 "PCX: Could not write colormap.\n"); 883 "PCX: Could not write colormap.\n");
881 goto error; 884 goto error;
882 } 885 }
883 886
884 if (!dm_fwrite_byte(pcx.fp, hdr.reserved) || 887 if (!dm_fwrite_byte(pcx.fp, hdr.reserved) ||
885 !dm_fwrite_byte(pcx.fp, hdr.nplanes) || 888 !dm_fwrite_byte(pcx.fp, hdr.nplanes) ||
886 !dm_fwrite_le16(pcx.fp, hdr.bpl) || 889 !dm_fwrite_le16(pcx.fp, hdr.bpl) ||
887 !dm_fwrite_le16(pcx.fp, hdr.palinfo) || 890 !dm_fwrite_le16(pcx.fp, hdr.palInfo) ||
888 !dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler))) 891 !dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler)))
889 { 892 {
890 res = dmError(DMERR_FWRITE, 893 res = dmError(DMERR_FWRITE,
891 "PCX: Could not write header remainder.\n"); 894 "PCX: Could not write header remainder.\n");
892 goto error; 895 goto error;
975 int dmReadPCXImageFILE(FILE *fp, DMImage **pimg) 978 int dmReadPCXImageFILE(FILE *fp, DMImage **pimg)
976 { 979 {
977 DMImage *img; 980 DMImage *img;
978 DMPCXData pcx; 981 DMPCXData pcx;
979 DMPCXHeader hdr; 982 DMPCXHeader hdr;
980 BOOL paletted; 983 int res = 0;
981 int res = 0, yc, xc;
982 Uint8 *dp;
983 984
984 pcx.buf = NULL; 985 pcx.buf = NULL;
985 986
986 // Read PCX header 987 // Read PCX header
987 if (!dm_fread_byte(fp, &hdr.manufacturer) || 988 if (!dm_fread_byte(fp, &hdr.manufacturer) ||
988 !dm_fread_byte(fp, &hdr.version) || 989 !dm_fread_byte(fp, &hdr.version) ||
989 !dm_fread_byte(fp, &hdr.encoding) || 990 !dm_fread_byte(fp, &hdr.encoding) ||
990 !dm_fread_byte(fp, &hdr.bpp)) 991 !dm_fread_byte(fp, &hdr.bitsPerPlane))
991 { 992 {
992 res = dmError(DMERR_FREAD, 993 res = dmError(DMERR_FREAD,
993 "PCX: Could not read basic header data.\n"); 994 "PCX: Could not read basic header data.\n");
994 goto error; 995 goto error;
995 } 996 }
996 997
997 if (hdr.manufacturer != 10 || 998 if (hdr.manufacturer != 10 ||
998 hdr.version != 5 || 999 hdr.version != 5 ||
999 hdr.encoding != 1 || 1000 hdr.encoding != 1)
1000 hdr.bpp != 8)
1001 { 1001 {
1002 res = dmError(DMERR_NOT_SUPPORTED, 1002 res = dmError(DMERR_NOT_SUPPORTED,
1003 "PCX: Not a PCX file, or unsupported variant.\n"); 1003 "PCX: Not a PCX file, or unsupported variant.\n");
1004 goto error; 1004 goto error;
1005 } 1005 }
1014 res = dmError(DMERR_FREAD, 1014 res = dmError(DMERR_FREAD,
1015 "PCX: Could not read image dimensions.\n"); 1015 "PCX: Could not read image dimensions.\n");
1016 goto error; 1016 goto error;
1017 } 1017 }
1018 1018
1019 if (!dm_fread_str(fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap))) 1019 if (!dm_fread_str(fp, (Uint8 *) &hdr.colorMap, sizeof(hdr.colorMap)))
1020 { 1020 {
1021 res = dmError(DMERR_FREAD, 1021 res = dmError(DMERR_FREAD,
1022 "PCX: Could not read colormap.\n"); 1022 "PCX: Could not read colormap.\n");
1023 goto error; 1023 goto error;
1024 } 1024 }
1025 1025
1026 if (!dm_fread_byte(fp, &hdr.reserved) || 1026 if (!dm_fread_byte(fp, &hdr.reserved) ||
1027 !dm_fread_byte(fp, &hdr.nplanes) || 1027 !dm_fread_byte(fp, &hdr.nplanes) ||
1028 !dm_fread_le16(fp, &hdr.bpl) || 1028 !dm_fread_le16(fp, &hdr.bpl) ||
1029 !dm_fread_le16(fp, &hdr.palinfo) || 1029 !dm_fread_le16(fp, &hdr.palInfo) ||
1030 !dm_fread_str(fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler))) 1030 !dm_fread_str(fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler)))
1031 { 1031 {
1032 res = dmError(DMERR_FREAD, 1032 res = dmError(DMERR_FREAD,
1033 "PCX: Could not read header remainder.\n"); 1033 "PCX: Could not read header remainder.\n");
1034 goto error; 1034 goto error;
1035 } 1035 }
1036 1036
1037 if (hdr.nplanes != 3 && hdr.nplanes != 1) 1037 if (hdr.nplanes < 1 || hdr.nplanes > 8)
1038 { 1038 {
1039 res = dmError(DMERR_FREAD, 1039 res = dmError(DMERR_NOT_SUPPORTED,
1040 "PCX: Unsupported number of bitplanes %d.\n", 1040 "PCX: Unsupported number of bitplanes %d.\n",
1041 hdr.nplanes); 1041 hdr.nplanes);
1042 goto error; 1042 goto error;
1043 } 1043 }
1044 1044
1048 res = dmError(DMERR_MALLOC, 1048 res = dmError(DMERR_MALLOC,
1049 "PCX: Could not allocate image structure.\n"); 1049 "PCX: Could not allocate image structure.\n");
1050 goto error; 1050 goto error;
1051 } 1051 }
1052 1052
1053 paletted = hdr.nplanes == 1; 1053 if (hdr.bpl < (img->width * hdr.bitsPerPlane) / 8)
1054 {
1055 res = dmError(DMERR_MALLOC,
1056 "PCX: The bytes per plane line value %d is smaller than width*bpp/8 = %d!\n",
1057 hdr.bpl, (img->width * hdr.bitsPerPlane) / 8);
1058 goto error;
1059 }
1060
1054 pcx.bufLen = hdr.nplanes * hdr.bpl; 1061 pcx.bufLen = hdr.nplanes * hdr.bpl;
1055 if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL) 1062 if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
1056 { 1063 {
1057 res = dmError(DMERR_MALLOC, 1064 res = dmError(DMERR_MALLOC,
1058 "PCX: Could not allocate RLE buffer.\n"); 1065 "PCX: Could not allocate RLE buffer.\n");
1059 goto error; 1066 goto error;
1060 } 1067 }
1061 1068
1062 // Read image data 1069 // Read image data
1063 dp = img->data; 1070 Uint8 *dp = img->data;
1064 for (yc = 0; yc < img->height; yc++) 1071 for (int yc = 0; yc < img->height; yc++)
1065 { 1072 {
1066 // Decode row of RLE'd data 1073 // Decode row of RLE'd data
1067 if (!dmPCXDecodeRLERow(fp, pcx.buf, pcx.bufLen)) 1074 if (!dmPCXDecodeRLERow(fp, pcx.buf, pcx.bufLen))
1068 { 1075 {
1069 res = dmError(DMERR_INVALID_DATA, 1076 res = dmError(DMERR_INVALID_DATA,
1070 "PCX: Error decoding RLE data.\n"); 1077 "PCX: Error decoding RLE compressed data.\n");
1071 goto error; 1078 goto error;
1072 } 1079 }
1073 1080
1074 // Decode bitplanes 1081 // Decode bitplanes
1075 switch (hdr.nplanes) 1082 switch (hdr.bitsPerPlane)
1076 { 1083 {
1077 case 1: 1084 case 8:
1078 memcpy(dp, pcx.buf, img->width); 1085 for (int nplane = 0; nplane < hdr.nplanes; nplane++)
1079 break;
1080
1081 case 3:
1082 { 1086 {
1083 Uint8 *dptr = dp, 1087 Uint8 *dptr = dp + nplane,
1084 *sptr1 = pcx.buf, 1088 *sptr = pcx.buf + (hdr.bpl * nplane);
1085 *sptr2 = sptr1 + hdr.bpl, 1089
1086 *sptr3 = sptr2 + hdr.bpl; 1090 for (int xc = 0; xc < img->width; xc += hdr.nplanes, dptr += hdr.nplanes, sptr++)
1087 1091 *dptr = *sptr;
1088 for (xc = 0; xc < img->width; xc++)
1089 {
1090 *dptr++ = *sptr1++;
1091 *dptr++ = *sptr2++;
1092 *dptr++ = *sptr3++;
1093 }
1094 } 1092 }
1095 break; 1093 break;
1094
1095 default:
1096 res = dmError(DMERR_INVALID_DATA,
1097 "PCX: Unsupported number of bits per plane %d.\n",
1098 hdr.bitsPerPlane);
1099 goto error;
1096 } 1100 }
1097 1101
1098 dp += img->pitch; 1102 dp += img->pitch;
1099 } 1103 }
1100 1104
1101 // Read VGA palette 1105 // Read additional VGA palette, if available
1102 if (paletted) 1106 {
1103 { 1107 int ncolors;
1104 int i, ncolors;
1105 Uint8 tmpb; 1108 Uint8 tmpb;
1106 BOOL read; 1109 BOOL read;
1107 1110
1108 if (!dm_fread_byte(fp, &tmpb) || tmpb != 0x0C) 1111 if (!dm_fread_byte(fp, &tmpb) || tmpb != 0x0C)
1109 { 1112 {
1123 goto error; 1126 goto error;
1124 } 1127 }
1125 1128
1126 if (read) 1129 if (read)
1127 { 1130 {
1131 // Okay, attempt to read the palette data
1128 if (!dmReadPaletteData(fp, img->pal, ncolors)) 1132 if (!dmReadPaletteData(fp, img->pal, ncolors))
1129 { 1133 {
1130 res = dmError(DMERR_FREAD, 1134 res = dmError(DMERR_FREAD,
1131 "PCX: Error reading palette.\n"); 1135 "PCX: Error reading palette.\n");
1132 goto error; 1136 goto error;
1133 } 1137 }
1134 } 1138 }
1135 else 1139 else
1136 { 1140 {
1137 for (i = 0; i < img->ncolors; i++) 1141 // If the extra palette is not available, copy the colors from
1138 { 1142 // the header palette to our internal palette structure.
1139 if (i < 16) 1143 for (int i = 0; i < (img->ncolors > DMPCX_PAL_COLORS ? DMPCX_PAL_COLORS : img->ncolors); i++)
1140 { 1144 {
1141 img->pal[i].r = hdr.colormap[i].r; 1145 img->pal[i].r = hdr.colorMap[i].r;
1142 img->pal[i].g = hdr.colormap[i].g; 1146 img->pal[i].g = hdr.colorMap[i].g;
1143 img->pal[i].b = hdr.colormap[i].b; 1147 img->pal[i].b = hdr.colorMap[i].b;
1144 }
1145 } 1148 }
1146 } 1149 }
1147 } 1150 }
1148 1151
1149 error: 1152 error: