#include "format-pec.h"
#include "emb-file.h"
#include "emb-logging.h"
#include "helpers-binary.h"
#include "helpers-misc.h"
#include <stdlib.h>
#include <string.h>
void readPecStitches(EmbPattern* pattern, EmbFile* file)
{
int stitchNumber = 0;
if(!pattern) { embLog_error("format-pec.c readPecStitches(), pattern argument is null\n"); return; }
if(!file) { embLog_error("format-pec.c readPecStitches(), file argument is null\n"); return; }
while(!embFile_eof(file))
{
int val1 = (int)binaryReadUInt8(file);
int val2 = (int)binaryReadUInt8(file);
int stitchType = NORMAL;
if(val1 == 0xFF && val2 == 0x00)
{
embPattern_addStitchRel(pattern, 0.0, 0.0, END, 1);
break;
}
if(val1 == 0xFE && val2 == 0xB0)
{
(void)binaryReadByte(file);
embPattern_addStitchRel(pattern, 0.0, 0.0, STOP, 1);
stitchNumber++;
continue;
}
if(val1 & 0x80)
{
if(val1 & 0x20) stitchType = TRIM;
if(val1 & 0x10) stitchType = JUMP;
val1 = ((val1 & 0x0F) << 8) + val2;
if(val1 & 0x800)
{
val1 -= 0x1000;
}
val2 = binaryReadUInt8(file);
}
else if(val1 >= 0x40)
{
val1 -= 0x80;
}
if(val2 & 0x80)
{
if(val2 & 0x20) stitchType = TRIM;
if(val2 & 0x10) stitchType = JUMP;
val2 = ((val2 & 0x0F) << 8) + binaryReadUInt8(file);
if(val2 & 0x800)
{
val2 -= 0x1000;
}
}
else if(val2 >= 0x40)
{
val2 -= 0x80;
}
embPattern_addStitchRel(pattern, val1 / 10.0, val2 / 10.0, stitchType, 1);
stitchNumber++;
}
}
static void pecEncodeJump(EmbFile* file, int x, int types)
{
int outputVal = abs(x) & 0x7FF;
unsigned int orPart = 0x80;
if(!file) { embLog_error("format-pec.c pecEncodeJump(), file argument is null\n"); return; }
if(types & TRIM)
{
orPart |= 0x20;
}
if(types & JUMP)
{
orPart |= 0x10;
}
if(x < 0)
{
outputVal = x + 0x1000 & 0x7FF;
outputVal |= 0x800;
}
binaryWriteByte(file, (unsigned char)(((outputVal >> 8) & 0x0F) | orPart));
binaryWriteByte(file, (unsigned char)(outputVal & 0xFF));
}
static void pecEncodeStop(EmbFile* file, unsigned char val)
{
if(!file) { embLog_error("format-pec.c pecEncodeStop(), file argument is null\n"); return; }
binaryWriteByte(file, 0xFE);
binaryWriteByte(file, 0xB0);
binaryWriteByte(file, val);
}
int readPec(EmbPattern* pattern, const char* fileName)
{
unsigned int graphicsOffset;
unsigned char colorChanges;
int i;
EmbFile* file = 0;
if(!pattern) { embLog_error("format-pec.c readPec(), pattern argument is null\n"); return 0; }
if(!fileName) { embLog_error("format-pec.c readPec(), fileName argument is null\n"); return 0; }
file = embFile_open(fileName, "rb");
if(!file)
{
embLog_error("format-pec.c readPec(), cannot open %s for reading\n", fileName);
return 0;
}
embFile_seek(file, 0x38, SEEK_SET);
colorChanges = (unsigned char)binaryReadByte(file);
for(i = 0; i <= colorChanges; i++)
{
embPattern_addThread(pattern, pecThreads[binaryReadByte(file) % 65]);
}
embFile_seek(file, 0x20A, SEEK_SET);
graphicsOffset = (unsigned int)(binaryReadUInt8(file));
graphicsOffset |= (binaryReadUInt8(file) << 8);
graphicsOffset |= (binaryReadUInt8(file) << 16);
(void)binaryReadByte(file);
(void)binaryReadByte(file);
(void)binaryReadByte(file);
binaryReadInt16(file);
binaryReadInt16(file);
binaryReadInt16(file);
binaryReadInt16(file);
binaryReadInt16(file);
binaryReadInt16(file);
readPecStitches(pattern, file);
embFile_close(file);
if(pattern->lastStitch->stitch.flags != END)
embPattern_addStitchRel(pattern, 0, 0, END, 1);
embPattern_flipVertical(pattern);
return 1;
}
static void pecEncode(EmbFile* file, EmbPattern* p)
{
double thisX = 0.0;
double thisY = 0.0;
unsigned char stopCode = 2;
EmbStitchList* list = 0;
if(!file) { embLog_error("format-pec.c pecEncode(), file argument is null\n"); return; }
if(!p) { embLog_error("format-pec.c pecEncode(), p argument is null\n"); return; }
list = p->stitchList;
while(list)
{
int deltaX, deltaY;
EmbStitch s = list->stitch;
deltaX = roundDouble(s.xx - thisX);
deltaY = roundDouble(s.yy - thisY);
thisX += (double)deltaX;
thisY += (double)deltaY;
if(s.flags & STOP)
{
pecEncodeStop(file, stopCode);
if(stopCode == (unsigned char)2)
{
stopCode = (unsigned char)1;
}
else
{
stopCode = (unsigned char)2;
}
}
else if(s.flags & END)
{
binaryWriteByte(file, 0xFF);
break;
}
else if(deltaX < 63 && deltaX > -64 && deltaY < 63 && deltaY > -64 && (!(s.flags & (JUMP | TRIM))))
{
binaryWriteByte(file, (deltaX < 0) ? (unsigned char)(deltaX + 0x80) : (unsigned char)deltaX);
binaryWriteByte(file, (deltaY < 0) ? (unsigned char)(deltaY + 0x80) : (unsigned char)deltaY);
}
else
{
pecEncodeJump(file, deltaX, s.flags);
pecEncodeJump(file, deltaY, s.flags);
}
list = list->next;
}
}
static void clearImage(unsigned char image[][48])
{
memcpy(image, imageWithFrame, 48*38);
}
static void writeImage(EmbFile* file, unsigned char image[][48])
{
int i, j;
if(!file) { embLog_error("format-pec.c writeImage(), file argument is null\n"); return; }
for(i = 0; i < 38; i++)
{
for(j = 0; j < 6; j++)
{
int offset = j * 8;
unsigned char output = 0;
output |= (unsigned char)(image[i][offset] != 0);
output |= (unsigned char)(image[i][offset + 1] != (unsigned char)0) << 1;
output |= (unsigned char)(image[i][offset + 2] != (unsigned char)0) << 2;
output |= (unsigned char)(image[i][offset + 3] != (unsigned char)0) << 3;
output |= (unsigned char)(image[i][offset + 4] != (unsigned char)0) << 4;
output |= (unsigned char)(image[i][offset + 5] != (unsigned char)0) << 5;
output |= (unsigned char)(image[i][offset + 6] != (unsigned char)0) << 6;
output |= (unsigned char)(image[i][offset + 7] != (unsigned char)0) << 7;
binaryWriteByte(file, output);
}
}
}
void writePecStitches(EmbPattern* pattern, EmbFile* file, const char* fileName)
{
EmbStitchList* tempStitches = 0;
EmbRect bounds;
unsigned char image[38][48];
int i, flen, currentThreadCount, graphicsOffsetLocation, graphicsOffsetValue, height, width;
double xFactor, yFactor;
const char* forwardSlashPos = strrchr(fileName, '/');
const char* backSlashPos = strrchr(fileName, '\\');
const char* dotPos = strrchr(fileName, '.');
const char* start = 0;
if(!pattern) { embLog_error("format-pec.c writePecStitches(), pattern argument is null\n"); return; }
if(!file) { embLog_error("format-pec.c writePecStitches(), file argument is null\n"); return; }
if(!fileName) { embLog_error("format-pec.c writePecStitches(), fileName argument is null\n"); return; }
if(forwardSlashPos)
{
start = forwardSlashPos + 1;
}
if(backSlashPos && backSlashPos > start)
{
start = backSlashPos + 1;
}
if(!start)
{
start = fileName;
}
binaryWriteBytes(file, "LA:", 3);
flen = (int)(dotPos - start);
while(start < dotPos)
{
binaryWriteByte(file, (unsigned char)*start);
start++;
}
for(i = 0; i < (int)(16-flen); i++)
{
binaryWriteByte(file, (unsigned char)0x20);
}
binaryWriteByte(file, 0x0D);
for(i = 0; i < 12; i++)
{
binaryWriteByte(file, (unsigned char)0x20);
}
binaryWriteByte(file, (unsigned char)0xFF);
binaryWriteByte(file, (unsigned char)0x00);
binaryWriteByte(file, (unsigned char)0x06);
binaryWriteByte(file, (unsigned char)0x26);
for(i = 0; i < 12; i++)
{
binaryWriteByte(file, (unsigned char)0x20);
}
currentThreadCount = embThreadList_count(pattern->threadList);
binaryWriteByte(file, (unsigned char)(currentThreadCount-1));
for(i = 0; i < currentThreadCount; i++)
{
binaryWriteByte(file, (unsigned char)embThread_findNearestColorInArray(embThreadList_getAt(pattern->threadList, i).color, (EmbThread*)pecThreads, pecThreadCount));
}
for(i = 0; i < (int)(0x1CF - currentThreadCount); i++)
{
binaryWriteByte(file, (unsigned char)0x20);
}
binaryWriteShort(file, (short)0x0000);
graphicsOffsetLocation = embFile_tell(file);
binaryWriteByte(file, (unsigned char)0x00);
binaryWriteByte(file, (unsigned char)0x00);
binaryWriteByte(file, (unsigned char)0x00);
binaryWriteByte(file, (unsigned char)0x31);
binaryWriteByte(file, (unsigned char)0xFF);
binaryWriteByte(file, (unsigned char)0xF0);
bounds = embPattern_calcBoundingBox(pattern);
height = roundDouble(embRect_height(bounds));
width = roundDouble(embRect_width(bounds));
binaryWriteShort(file, (short)width);
binaryWriteShort(file, (short)height);
binaryWriteShort(file, (short)0x1E0);
binaryWriteShort(file, (short)0x1B0);
binaryWriteUShortBE(file, (unsigned short)(0x9000 | -roundDouble(bounds.left)));
binaryWriteUShortBE(file, (unsigned short)(0x9000 | -roundDouble(bounds.top)));
pecEncode(file, pattern);
graphicsOffsetValue = embFile_tell(file) - graphicsOffsetLocation + 2;
embFile_seek(file, graphicsOffsetLocation, SEEK_SET);
binaryWriteByte(file, (unsigned char)(graphicsOffsetValue & 0xFF));
binaryWriteByte(file, (unsigned char)((graphicsOffsetValue >> 8) & 0xFF));
binaryWriteByte(file, (unsigned char)((graphicsOffsetValue >> 16) & 0xFF));
embFile_seek(file, 0x00, SEEK_END);
clearImage(image);
tempStitches = pattern->stitchList;
yFactor = 32.0 / height;
xFactor = 42.0 / width;
while(tempStitches->next)
{
int x = roundDouble((tempStitches->stitch.xx - bounds.left) * xFactor) + 3;
int y = roundDouble((tempStitches->stitch.yy - bounds.top) * yFactor) + 3;
image[y][x] = 1;
tempStitches = tempStitches->next;
}
writeImage(file, image);
tempStitches = pattern->stitchList;
for(i = 0; i < currentThreadCount; i++)
{
clearImage(image);
while(tempStitches->next)
{
int x = roundDouble((tempStitches->stitch.xx - bounds.left) * xFactor) + 3;
int y = roundDouble((tempStitches->stitch.yy - bounds.top) * yFactor) + 3;
if(tempStitches->stitch.flags & STOP)
{
tempStitches = tempStitches->next;
break;
}
image[y][x] = 1;
tempStitches = tempStitches->next;
}
writeImage(file, image);
}
}
int writePec(EmbPattern* pattern, const char* fileName)
{
EmbFile* file = 0;
if(!embStitchList_count(pattern->stitchList))
{
embLog_error("format-pec.c writePec(), pattern contains no stitches\n");
return 0;
}
if(pattern->lastStitch->stitch.flags != END)
embPattern_addStitchRel(pattern, 0, 0, END, 1);
file = embFile_open(fileName, "wb");
if(!file)
{
embLog_error("format-pec.c writePec(), cannot open %s for writing\n", fileName);
return 0;
}
embPattern_flipVertical(pattern);
embPattern_fixColorCount(pattern);
embPattern_correctForMaxStitchLength(pattern,12.7, 204.7);
embPattern_scale(pattern, 10.0);
binaryWriteBytes(file, "#PEC0001", 8);
writePecStitches(pattern, file, fileName);
embFile_close(file);
return 1;
}