Embroidermodder / libembroidery

Library for reading/writing/manipulating machine and design embroidery files
https://www.libembroidery.org
zlib License
45 stars 13 forks source link

Multiple version of an embroidery format? #139

Closed x2nie closed 2 years ago

x2nie commented 10 years ago

Is there a way to distict multiple version from each embroidery format (if any)? For instance: Many Brother's machine support *.PES file, but internally they only recognize a specific version of PES. Let say Brother model X accepts PES ver 001, while Brother model Y accepts PES ver 006.

Okay, not every embroidery format has several version. But some of it has.

So, how we can instruct libembroidery to save to .PES in specific version?

JoshVarga commented 10 years ago

Currently we only are capable of supporting version 1 of PES. I have code that it's not in github that we may be able to integrate eventually. Right now we don't have this problem, but implementing something to handle this would be beneficial when the time comes. On Jan 29, 2014 8:39 AM, "x2nie" notifications@github.com wrote:

Is there a way to distict multiple version of any embroidery format? For instance: Many Brother's machine support *.PES file, but internally they only recognize specific version of PES. Let say Brother model X accepts PES ver 001, while Brother model Y accepts PES ver 006.

So, how we can instruct libembroidery to save to .PES in specific version?

Reply to this email directly or view it on GitHubhttps://github.com/Embroidermodder/Embroidermodder/issues/22 .

redteam316 commented 10 years ago

This should really go into EmbSettings that way we can make a command line option for it too since the desired version is going to apply to many formats in the future. Probably should be implemented with EmbHash so we just need 2 functions: one for lookup and another for setting.

Josh, should I add stubs for this so it's there in the future or did you have a different idea?

JoshVarga commented 10 years ago

I think stubbing it out would be good, we will need it at some point. I know of a couple other distinct formats that share a file extension. This would not be able to save separately as it stands right now. When I get around to implementing more of the saving methods this will come in handy. On Jan 29, 2014 7:53 PM, "Jonathan Greig" notifications@github.com wrote:

This should really go into EmbSettings that way we can make a command line option for it too since the desired version is going to apply to many formats in the future. Probably should be implemented with EmbHash so we just need 2 functions: one for lookup and another for setting.

Josh, should I add stubs for this so it's there in the future or did you have a different idea?

Reply to this email directly or view it on GitHubhttps://github.com/Embroidermodder/Embroidermodder/issues/22#issuecomment-33653301 .

redteam316 commented 10 years ago

Good point about distinctly different formats sharing the same extension. I'll make stubs for this and a TODO note explicitly mentioning that we need to check for that also. I know for a fact that .nc and .nc1 extensions are commonly used for gcode, but the internal data can vary greatly. What other formats do you know this will be an issue? I can add that into the notes.

x2nie commented 10 years ago

Thredwork (*.thr) has multi version formats. But for saving, Thred only support ver 2.

May I have another question? I dont know if below question would be an another issue, but I think it has relation to this topic: "How to list the writers of supported format ? How to list the reader of supported format?" I have started a new application, a GUI embroider converter. It will support multiple input files. image This way, I need to list supported readers in OpenDialogBox, and I will put the list of supported writer in a CheckBoxList.

My current solution is fetching the readers by parsing the exported method from shared library. That is: when I found a method that the name started with "read" and the length is < 7, I assumed it is a reader. For example : readPes = "pes" reader. Next, I seek the founded extention ("pes") to the embroidery format array (copied from embroider-converter). Finally, if "pes" found in the array, I get the description for it ("pes" = "Brother Embroidery Format"). It also done for looking up writers.

This my solution has been satisfied me, but also has some potential problem for future usage:

redteam316 commented 10 years ago

@x2nie, I don't think the thr format really falls into this category unless it is advanced in the future(such as a new version of thred emerging that isn't just a port but adds the extra functionality to the format).

I would suggest writing a loop that calls embPattern_free() after each write, then load the next file and repeat. This has worked in the past for me but I haven't tested recently and there is a TODO note in the C code for the converter to eventually support this via command line options. It's not a high priority for us at the moment since you can achieve the same effect by calling it as a subprocess in a loop. Not the best solution, but it's pragmatic and 'just works'.

As far as supported formats when reading, you will need to check if the reader returns false. If it returns true, write the file, otherwise free the pattern and go onto the next one.

That's basically the explanation for how the C converter will work in the future, but it would require using the LONG_WAY not the SHORT_WAY. You would still need to use the same method in your GUI so if you want to implement the logic, port it back to the C converter and I will review it. Just do the work in a separate branch called "multi-read" or something of the similar. If that's the case, open a separate issue so discussion and work can continue there, otherwise Josh or I will tackle it when we specifically need it for other testing or functionality.

@JoshVarga, My mention of the .nc1 is due to the fact that I will be adding gcode eventually but I already have lib code for the DSTV format(steel platework) that I may consider adding in the future that would also be a usable format but it also shares the .nc1 extension and requires distinct parsing. What other formats are you thinking of? I think the .uXX type of format would fall under this category but again, is a slightly different problem of it's own.

x2nie commented 10 years ago

Hi ! Bad news :-1: : You have removed the publicity of read & write functions (readXxx & writeXxx is now private). My delphi project (embconv.dpr), then now is broken ! Okay, I will never use them any longer to make a list/array of the availability of supported fomats, by parsing the exported functions from shared library. Okay, it was my cross-platform problem... But, I think I still require them all for another purpose. Such for implementing "LONG_WAY" converter.

Good news :+1: :8ball: : I have new different approach to solve this first-thread-issue: I can distinctly save to a specific version of format that share the same file extension. Yeah!!, finally... :)D

The idea is to let user to specify which version of format she want to save to. For instance: when she decide to save to *.PES version 006, then I will save to that specification properly.

How ? By calling specific writer. This way, we must have several writers accordingly. In above case, we need to distinct 2 writers. Let say there are writePes to save default PES, and writePes006 to save to PES version 006. That is why I still need the reader and writer to be accessible (exported).

I am sure we have no problem about current readers name (since no matter version of PES could be loaded with single reader: readPes). But for writers name, I think better to make distinct name for each version. Further, the host application (GUI) must able to list all of those distinctive supported writers, to let user to choose one.

I've done of making prototype of this solution by introducing 2 new function:

How it work ? When application is going to run, it first build an array of supported format by libembroidery(*.dll). When user need to save a new design, she will see the SaveDialogBox.... She then pic a specific format; let say "Brother Embroidery ver. 006" is choosen. Okay, the application internally has made relation between that picked format to a specific writer. Application then easily call that writer to make a new file in properly format. Done.

For impatient searching, below is a small part of above functions:

/* wrapper must not define it */
#define EMBFORMAT_COUNT 59      /* total supported format, distinctive version included */

/*! Returns EMBFORMAT_COUNT.
 *  Intended to not lie the wrapper/binding of shared library usage
 *  The benefit is consistency of host code,
 *  while the shared library may is possibly upgraded */
int embFormat_count()
{
    return EMBFORMAT_COUNT;
}
/*! Fill related info to EmbFormat sequenced by given index.
 *  Due we may insert a new format at anywhere in future,
 *  index must not be hardcoded to any relevan EmbFormat. */
void embFormat_get(int index, EmbFormat* format){
    switch(index)
    {
    case 0:
        format->ext = ".10o";
        format->masterInfo = "Toyota Embroidery Format";
        format->readerName = "read10o";
        format->writerName = "write10o";
        format->formatType = EMBFORMAT_STITCHONLY;
        break;
/* TODO: list the rest formats alphabetically */
    case 1:
        format->ext = ".pes";
        format->masterInfo = "Brother Embroidery Format";
        format->detailInfo = "Brother Embroidery ver 001";
        format->readerName = "__readPes__";  /* share reader */
        format->writerName = "__writePes001__";
        format->formatType = EMBFORMAT_STITCHONLY ;
        break;
    case 2:
        format->ext = ".pes";
        format->masterInfo = "Brother Embroidery Format";
        format->detailInfo = "Brother Embroidery ver 006";
        format->readerName = "__readPes__";  /* share reader */
        format->writerName = "__writePes006__";
        format->formatType = EMBFORMAT_STITCHONLY;
        break;
    case 3:
        format->ext = ".thr";
        format->masterInfo = "ThredWorks Embroidery Format";
        format->detailInfo = "Brother Embroidery ver 001";
        format->readerName = "readThr";
        format->writerName = "__writeThr1__";
        format->formatType = EMBFORMAT_STITCHONLY + EMBFORMAT_OBJECTONLY;
        break;
    case 4:
        format->ext = ".thr";
        format->masterInfo = "ThredWorks Embroidery Format";
        format->readerName = "readThr";
        format->writerName = "__writeThr2__";
        format->formatType = EMBFORMAT_STITCHONLY + EMBFORMAT_OBJECTONLY;
        break;
/* TODO: list the rest formats alphabetically */
    default:
            /* do nothing for unrecognized index */
            break;
    }
}

File : formats.c at my master. Shall I make a pull request now? I think it will take a day or two to be completed. But, I think the idea is fully loaded. :)P

Yeah, this is not a perfect solution. It need more test to be mature. At least, using above function will made the list of supported format: available in cross-platform. (my prior way of getting the list is only work under Windows)

Best regards,

x2nie

redteam316 commented 10 years ago

@x2nie, The reader/writer functions were never really intended to be public so your code breaking is actually a good thing now that the intended API is defined properly with gcc even though it is still evolving.

Do not do any major work in that direction. Adding extra function pointers is not a good solution. Josh and I discussed these changes earlier today. This is something that needs to be handled in EmbSettings. The idea is to request a specific version of the format within the writer function. I think we can provide a minimum default version(typically 1) but if the requested version of that format is unavailable, the function should fail and the calling library code and/or application should react accordingly. Using an index in a function parameter is a bad design and is much more likely to break user code than breaking the API. The functions should look similar to this(preferring strings or either enums for version):

int embSettings_setFormatVersion(const char* format, int version); /* called by app before writing, error and return false if requested format is not available */
int embSettings_formatVersion(const char* format, int version); /* used in libembroidery, error and return false if requested format is not available */

I do think adding in an embFormat_count() function is a good idea. Currently this is not handled in the converter app code rather than libembroidery. This does need incorporated into the library and I would be fine with a pull request adding this functionality only. The function as is would return all unstable formats, so it may be smart to have an extra parameter so the developer can get the number of stable formats too. DST and PES are close to being considered stable but not quite yet. In the future, if we can mark all formats as being stable(hopefully with the cooperation of the original format creators), this could be deprecated.

x2nie commented 10 years ago

Oh yeah! You are right. Talking about how to save in specific version of a format using embSetting, it is a genius solution. I think, I dont actually need to access the writers, instead: what I really need is to save in specific version. You are right. :+1:

:8ball: But, before do that, how I know whether a format (or a specific version of a format) is available? The Shared lib it self shall tell me about them! So, I still need to get the list of supported format from shared library. Okay, since it's separated problem, I open discussion in another thread: Embroidermodder/Embroidermodder#25

robin-swift commented 2 years ago

I'm moving this to the "ideas" section of the manual.