libdmtx 0.7.8.7
libdmtx is a software library that enables programs to read and write Data Matrix barcodes of the modern ECC200 variety.
Loading...
Searching...
No Matches
dmtxencodeoptimize.c
Go to the documentation of this file.
1
17#include "dmtx.h"
18#include "dmtxstatic.h"
19
20#define DUMPSTREAMS 0
21
23{
25 AsciiCompactOffset0, /* 0 offset from first regular input value */
27 C40Offset0, /* 0 offset from first expanded C40 value */
30 TextOffset0, /* 0 offset from first expanded Text value */
33 X12Offset0, /* 0 offset from first expanded X12 value */
36 EdifactOffset0, /* 0 offset from first regular input value */
42};
43
44#if DUMPSTREAMS
45static void DumpStreams(DmtxEncodeStream *streamBest)
46{
47 enum SchemeState state;
48 char prefix[32];
49
50 dmtxLogInfo("----------------------------------------\n");
51 for (state = 0; state < SchemeStateCount; state++) {
52 if (streamBest[state].status == DmtxStatusEncoding || streamBest[state].status == DmtxStatusComplete)
53 dmtxLogInfo("\"%c\" ", streamBest[state].input->b[streamBest[state].inputNext - 1]);
54 else
55 dmtxLogInfo(" ");
56
57 switch (streamBest[state].status) {
59 snprintf(prefix, sizeof(prefix), "%2d (%s): ", state, " encode ");
60 break;
62 snprintf(prefix, sizeof(prefix), "%2d (%s): ", state, "complete");
63 break;
65 snprintf(prefix, sizeof(prefix), "%2d (%s): ", state, "invalid ");
66 break;
67 case DmtxStatusFatal:
68 snprintf(prefix, sizeof(prefix), "%2d (%s): ", state, " fatal ");
69 break;
70 }
71 dmtxByteListPrint(streamBest[state].output, prefix);
72 }
73}
74#endif
75
80static int encodeOptimizeBest(DmtxByteList *input, DmtxByteList *output, int sizeIdxRequest, int fnc1)
81{
82 enum SchemeState state;
83 int inputNext, c40ValueCount, textValueCount, x12ValueCount;
84 int sizeIdx;
85 DmtxEncodeStream *winner;
86 DmtxPassFail passFail;
89 DmtxByte outputsBestStorage[SchemeStateCount][4096];
90 DmtxByte outputsTempStorage[SchemeStateCount][4096];
91 DmtxByte ctxTempStorage[4];
92 DmtxByteList outputsBest[SchemeStateCount];
93 DmtxByteList outputsTemp[SchemeStateCount];
94 DmtxByteList ctxTemp = dmtxByteListBuild(ctxTempStorage, sizeof(ctxTempStorage));
95
96 /* Initialize all streams with their own output storage */
97 for (state = 0; state < SchemeStateCount; state++) {
98 outputsBest[state] = dmtxByteListBuild(outputsBestStorage[state], sizeof(outputsBestStorage[state]));
99 outputsTemp[state] = dmtxByteListBuild(outputsTempStorage[state], sizeof(outputsTempStorage[state]));
100 streamsBest[state] = streamInit(input, &(outputsBest[state]));
101 streamsTemp[state] = streamInit(input, &(outputsTemp[state]));
102 streamsBest[state].fnc1 = fnc1;
103 streamsTemp[state].fnc1 = fnc1;
104 }
105
106 c40ValueCount = textValueCount = x12ValueCount = 0;
107
108 for (inputNext = 0; inputNext < input->length; inputNext++) {
109 streamAdvanceFromBest(streamsTemp, streamsBest, AsciiFull, sizeIdxRequest);
110
111 advanceAsciiCompact(streamsTemp, streamsBest, AsciiCompactOffset0, inputNext, sizeIdxRequest);
112 advanceAsciiCompact(streamsTemp, streamsBest, AsciiCompactOffset1, inputNext, sizeIdxRequest);
113
114 advanceCTX(streamsTemp, streamsBest, C40Offset0, inputNext, c40ValueCount, sizeIdxRequest);
115 advanceCTX(streamsTemp, streamsBest, C40Offset1, inputNext, c40ValueCount, sizeIdxRequest);
116 advanceCTX(streamsTemp, streamsBest, C40Offset2, inputNext, c40ValueCount, sizeIdxRequest);
117
118 advanceCTX(streamsTemp, streamsBest, TextOffset0, inputNext, textValueCount, sizeIdxRequest);
119 advanceCTX(streamsTemp, streamsBest, TextOffset1, inputNext, textValueCount, sizeIdxRequest);
120 advanceCTX(streamsTemp, streamsBest, TextOffset2, inputNext, textValueCount, sizeIdxRequest);
121
122 advanceCTX(streamsTemp, streamsBest, X12Offset0, inputNext, x12ValueCount, sizeIdxRequest);
123 advanceCTX(streamsTemp, streamsBest, X12Offset1, inputNext, x12ValueCount, sizeIdxRequest);
124 advanceCTX(streamsTemp, streamsBest, X12Offset2, inputNext, x12ValueCount, sizeIdxRequest);
125
126 advanceEdifact(streamsTemp, streamsBest, EdifactOffset0, inputNext, sizeIdxRequest);
127 advanceEdifact(streamsTemp, streamsBest, EdifactOffset1, inputNext, sizeIdxRequest);
128 advanceEdifact(streamsTemp, streamsBest, EdifactOffset2, inputNext, sizeIdxRequest);
129 advanceEdifact(streamsTemp, streamsBest, EdifactOffset3, inputNext, sizeIdxRequest);
130
131 streamAdvanceFromBest(streamsTemp, streamsBest, Base256, sizeIdxRequest);
132
133 /* Overwrite best streams with new results */
134 for (state = 0; state < SchemeStateCount; state++) {
135 if (streamsBest[state].status != DmtxStatusComplete) {
136 streamCopy(&(streamsBest[state]), &(streamsTemp[state]));
137 }
138 }
139
140 dmtxByteListClear(&ctxTemp);
141 pushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeC40, &passFail, fnc1);
142 c40ValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1);
143
144 dmtxByteListClear(&ctxTemp);
145 pushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeText, &passFail, fnc1);
146 textValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1);
147
148 dmtxByteListClear(&ctxTemp);
149 pushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeX12, &passFail, fnc1);
150 x12ValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1);
151
152#if DUMPSTREAMS
153 DumpStreams(streamsBest);
154#endif
155 }
156
157 /* Choose the overall winner */
158 winner = NULL;
159 for (state = 0; state < SchemeStateCount; state++) {
160 if (streamsBest[state].status == DmtxStatusComplete) {
161 if (winner == NULL || streamsBest[state].output->length < winner->output->length) {
162 winner = &(streamsBest[state]);
163 }
164 }
165 }
166
167 /* Copy winner to output */
168 if (winner == NULL) {
169 sizeIdx = DmtxUndefined;
170 } else {
171 dmtxByteListCopy(output, winner->output, &passFail);
172 sizeIdx = (passFail == DmtxPass) ? winner->sizeIdx : DmtxUndefined;
173 }
174
175 return sizeIdx;
176}
177
183static void streamAdvanceFromBest(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest, int targetState,
184 int sizeIdxRequest)
185{
186 enum SchemeState fromState;
187 DmtxScheme targetScheme;
188 DmtxEncodeOption encodeOption;
189 DmtxByte outputTempStorage[4096];
190 DmtxByteList outputTemp = dmtxByteListBuild(outputTempStorage, sizeof(outputTempStorage));
191 DmtxEncodeStream streamTemp;
192 DmtxEncodeStream *targetStream = &(streamsNext[targetState]);
193
194 streamTemp.output = &outputTemp; /* Set directly instead of calling streamInit() */
195 targetScheme = getScheme(targetState);
196
197 if (targetState == AsciiFull) {
198 encodeOption = DmtxEncodeFull;
199 } else if (targetState == AsciiCompactOffset0 || targetState == AsciiCompactOffset1) {
200 encodeOption = DmtxEncodeCompact;
201 } else {
202 encodeOption = DmtxEncodeNormal;
203 }
204
205 for (fromState = 0; fromState < SchemeStateCount; fromState++) {
206 if (streamsBest[fromState].status != DmtxStatusEncoding ||
207 validStateSwitch(fromState, targetState) == DmtxFalse) {
208 continue;
209 }
210
211 streamCopy(&streamTemp, &(streamsBest[fromState]));
212 encodeNextChunk(&streamTemp, targetScheme, encodeOption, sizeIdxRequest);
213
214 if (fromState == 0 ||
215 (streamTemp.status != DmtxStatusInvalid && streamTemp.output->length < targetStream->output->length)) {
216 streamCopy(targetStream, &streamTemp);
217 }
218 }
219}
220
224static void advanceAsciiCompact(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest, int targetState,
225 int inputNext, int sizeIdxRequest)
226{
227 DmtxEncodeStream *currentStream = &(streamsBest[targetState]);
228 DmtxEncodeStream *targetStream = &(streamsNext[targetState]);
229 DmtxBoolean isStartState;
230
231 switch (targetState) {
233 isStartState = (inputNext % 2 == 0) ? DmtxTrue : DmtxFalse;
234 break;
235
237 isStartState = (inputNext % 2 == 1) ? DmtxTrue : DmtxFalse;
238 break;
239
240 default:
242 return;
243 }
244
245 if (inputNext < currentStream->inputNext) {
246 streamCopy(targetStream, currentStream);
247 } else if (isStartState == DmtxTrue) {
248 streamAdvanceFromBest(streamsNext, streamsBest, targetState, sizeIdxRequest);
249 } else {
250 streamCopy(targetStream, currentStream);
251 streamMarkInvalid(targetStream, DmtxErrorUnknown);
252 }
253}
254
258static void advanceCTX(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest, int targetState, int inputNext,
259 int ctxValueCount, int sizeIdxRequest)
260{
261 DmtxEncodeStream *currentStream = &(streamsBest[targetState]);
262 DmtxEncodeStream *targetStream = &(streamsNext[targetState]);
263 DmtxBoolean isStartState;
264
265 /* we won't actually use inputNext here */
266 switch (targetState) {
267 case C40Offset0:
268 case TextOffset0:
269 case X12Offset0:
270 isStartState = (ctxValueCount % 3 == 0) ? DmtxTrue : DmtxFalse;
271 break;
272
273 case C40Offset1:
274 case TextOffset1:
275 case X12Offset1:
276 isStartState = (ctxValueCount % 3 == 1) ? DmtxTrue : DmtxFalse;
277 break;
278
279 case C40Offset2:
280 case TextOffset2:
281 case X12Offset2:
282 isStartState = (ctxValueCount % 3 == 2) ? DmtxTrue : DmtxFalse;
283 break;
284
285 default:
287 return;
288 }
289
290 if (inputNext < currentStream->inputNext) {
291 streamCopy(targetStream, currentStream);
292 } else if (isStartState == DmtxTrue) {
293 streamAdvanceFromBest(streamsNext, streamsBest, targetState, sizeIdxRequest);
294 } else {
295 streamCopy(targetStream, currentStream);
296 streamMarkInvalid(targetStream, DmtxErrorUnknown);
297 }
298}
299
303static void advanceEdifact(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest, int targetState, int inputNext,
304 int sizeIdxRequest)
305{
306 DmtxEncodeStream *currentStream = &(streamsBest[targetState]);
307 DmtxEncodeStream *targetStream = &(streamsNext[targetState]);
308 DmtxBoolean isStartState;
309
310 switch (targetState) {
311 case EdifactOffset0:
312 isStartState = (inputNext % 4 == 0) ? DmtxTrue : DmtxFalse;
313 break;
314
315 case EdifactOffset1:
316 isStartState = (inputNext % 4 == 1) ? DmtxTrue : DmtxFalse;
317 break;
318
319 case EdifactOffset2:
320 isStartState = (inputNext % 4 == 2) ? DmtxTrue : DmtxFalse;
321 break;
322
323 case EdifactOffset3:
324 isStartState = (inputNext % 4 == 3) ? DmtxTrue : DmtxFalse;
325 break;
326
327 default:
329 return;
330 }
331
332 if (isStartState == DmtxTrue) {
333 streamAdvanceFromBest(streamsNext, streamsBest, targetState, sizeIdxRequest);
334 } else {
335 streamCopy(targetStream, currentStream);
336 if (currentStream->status == DmtxStatusEncoding && currentStream->currentScheme == DmtxSchemeEdifact) {
337 encodeNextChunk(targetStream, DmtxSchemeEdifact, DmtxEncodeNormal, sizeIdxRequest);
338 } else {
339 streamMarkInvalid(targetStream, DmtxErrorUnknown);
340 }
341 }
342}
343
348static int getScheme(int state)
349{
350 DmtxScheme scheme;
351
352 switch (state) {
353 case AsciiFull:
356 scheme = DmtxSchemeAscii;
357 break;
358 case C40Offset0:
359 case C40Offset1:
360 case C40Offset2:
361 scheme = DmtxSchemeC40;
362 break;
363 case TextOffset0:
364 case TextOffset1:
365 case TextOffset2:
366 scheme = DmtxSchemeText;
367 break;
368 case X12Offset0:
369 case X12Offset1:
370 case X12Offset2:
371 scheme = DmtxSchemeX12;
372 break;
373 case EdifactOffset0:
374 case EdifactOffset1:
375 case EdifactOffset2:
376 case EdifactOffset3:
377 scheme = DmtxSchemeEdifact;
378 break;
379 case Base256:
380 scheme = DmtxSchemeBase256;
381 break;
382 default:
383 scheme = DmtxUndefined;
384 break;
385 }
386
387 return scheme;
388}
389
394static DmtxBoolean validStateSwitch(int fromState, int targetState)
395{
397 DmtxScheme fromScheme = getScheme(fromState);
398 DmtxScheme toScheme = getScheme(targetState);
399
400 if (fromScheme == toScheme && fromState != targetState && fromState != AsciiFull && targetState != AsciiFull) {
402 } else {
404 }
405
406 return validStateSwitch;
407}
libdmtx - Data Matrix Encoding/Decoding Library Copyright 2008, 2009 Mike Laughton.
#define DmtxPassFail
Definition dmtx.h:42
#define DmtxTrue
Definition dmtx.h:47
DmtxByteList dmtxByteListBuild(DmtxByte *storage, int capacity)
#define DmtxBoolean
Definition dmtx.h:46
#define DmtxPass
Definition dmtx.h:43
enum DmtxScheme_enum DmtxScheme
#define DmtxUndefined
Definition dmtx.h:40
@ DmtxSchemeText
Definition dmtx.h:92
@ DmtxSchemeC40
Definition dmtx.h:91
@ DmtxSchemeBase256
Definition dmtx.h:95
@ DmtxSchemeEdifact
Definition dmtx.h:94
@ DmtxSchemeX12
Definition dmtx.h:93
@ DmtxSchemeAscii
Definition dmtx.h:90
void dmtxByteListCopy(DmtxByteList *dst, const DmtxByteList *src, DmtxPassFail *passFail)
#define DmtxFalse
Definition dmtx.h:48
void dmtxByteListClear(DmtxByteList *list)
unsigned char DmtxByte
Definition dmtx.h:293
#define dmtxLogInfo(...)
Definition dmtx.h:69
void dmtxByteListPrint(DmtxByteList *list, char *prefix)
@ DmtxStatusComplete
Definition dmtx.h:81
@ DmtxStatusEncoding
Definition dmtx.h:80
@ DmtxStatusInvalid
Definition dmtx.h:82
@ DmtxStatusFatal
Definition dmtx.h:83
static int encodeOptimizeBest(DmtxByteList *input, DmtxByteList *output, int sizeIdxRequest, int fnc1)
static DmtxBoolean validStateSwitch(int fromState, int targetState)
static void advanceAsciiCompact(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest, int targetState, int inputNext, int sizeIdxRequest)
static void advanceCTX(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest, int targetState, int inputNext, int ctxValueCount, int sizeIdxRequest)
static void streamAdvanceFromBest(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest, int targetState, int sizeIdxRequest)
It's safe to compare output length because all targetState combinations start on same input and encod...
@ SchemeStateCount
@ EdifactOffset3
@ X12Offset0
@ C40Offset1
@ Base256
@ TextOffset0
@ EdifactOffset0
@ TextOffset1
@ TextOffset2
@ AsciiCompactOffset1
@ X12Offset2
@ EdifactOffset2
@ C40Offset0
@ AsciiCompactOffset0
@ X12Offset1
@ EdifactOffset1
@ AsciiFull
@ C40Offset2
static int getScheme(int state)
static void advanceEdifact(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest, int targetState, int inputNext, int sizeIdxRequest)
libdmtx - Data Matrix Encoding/Decoding Library Copyright 2008, 2009 Mike Laughton.
static void encodeNextChunk(DmtxEncodeStream *stream, int scheme, int subScheme, int sizeIdxRequest)
@ DmtxEncodeFull
Definition dmtxstatic.h:109
@ DmtxEncodeNormal
Definition dmtxstatic.h:107
@ DmtxEncodeCompact
Definition dmtxstatic.h:108
@ DmtxErrorUnknown
Definition dmtxstatic.h:394
@ DmtxErrorIllegalParameterValue
Definition dmtxstatic.h:397
static DmtxEncodeStream streamInit(DmtxByteList *input, DmtxByteList *output)
static void streamCopy(DmtxEncodeStream *dst, DmtxEncodeStream *src)
static void streamMarkInvalid(DmtxEncodeStream *stream, int reasonIdx)
enum DmtxEncodeOption_enum DmtxEncodeOption
static void pushCTXValues(DmtxByteList *valueList, DmtxByte inputValue, int targetScheme, DmtxPassFail *passFail, int fnc1)
static void streamMarkFatal(DmtxEncodeStream *stream, int reasonIdx)
DmtxByteList Use signed int for length fields instead of size_t to play nicely with RS arithmetic.
DmtxByteList * output
Definition dmtx.h:319
DmtxStatus status
Definition dmtx.h:317