1 /*
2 * Copyright 2009 Chris Young <chris@unsatisfactorysoftware.co.uk>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifdef WITH_NS_SVG
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <svgtiny.h>
24 #include <proto/exec.h>
25 #include <string.h>
26 #include <proto/dos.h>
27
28 #include "netsurf/inttypes.h"
29 #ifndef AMIGA_DR2D_STANDALONE
30 #include "utils/nsurl.h"
31 #include "netsurf/content.h"
32 #include "amiga/os3support.h"
33 #include "amiga/iff_dr2d.h"
34 #else
35 #include "os3support.h"
36 #include "iff_dr2d.h"
37 #endif
38
39 static struct ColorRegister cm[1000];
40 static ULONG numcols;
41
findcolour(ULONG newcol)42 static ULONG findcolour(ULONG newcol)
43 {
44 ULONG i;
45 ULONG colr = 0xFFFFFFFF;
46 UBYTE red,grn,blu;
47
48 red = svgtiny_RED(newcol);
49 grn = svgtiny_GREEN(newcol);
50 blu = svgtiny_BLUE(newcol);
51
52 for(i=0;i<numcols;i++)
53 {
54 if((cm[i].red == red) && (cm[i].green == grn) && (cm[i].blue == blu))
55 colr = i;
56 }
57
58 return colr;
59 }
60
addcolour(ULONG newcol)61 static void addcolour(ULONG newcol)
62 {
63 ULONG colr = findcolour(newcol);
64
65 if(colr == 0xFFFFFFFF)
66 {
67 cm[numcols].red = svgtiny_RED(newcol);
68 cm[numcols].green = svgtiny_GREEN(newcol);
69 cm[numcols].blue = svgtiny_BLUE(newcol);
70
71 numcols++;
72 }
73 }
74
ami_svg_to_dr2d(struct IFFHandle * iffh,const char * buffer,uint32_t size,const char * url)75 bool ami_svg_to_dr2d(struct IFFHandle *iffh, const char *buffer,
76 uint32_t size, const char *url)
77 {
78 struct svgtiny_diagram *diagram;
79 svgtiny_code code;
80 BOOL fons_written = FALSE;
81 struct fons_struct *fons;
82 struct stxt_struct *stxt;
83 struct attr_struct *attr;
84
85 /* create svgtiny object */
86 diagram = svgtiny_create();
87 if (!diagram) {
88 fprintf(stderr, "svgtiny_create failed\n");
89 return 1;
90 }
91
92 /* parse */
93 code = svgtiny_parse(diagram, buffer, size, url, 1000, 1000);
94 if (code != svgtiny_OK) {
95 fprintf(stderr, "svgtiny_parse failed: ");
96 switch (code) {
97 case svgtiny_OUT_OF_MEMORY:
98 fprintf(stderr, "svgtiny_OUT_OF_MEMORY");
99 break;
100 case svgtiny_LIBDOM_ERROR:
101 fprintf(stderr, "svgtiny_LIBDOM_ERROR");
102 break;
103 case svgtiny_NOT_SVG:
104 fprintf(stderr, "svgtiny_NOT_SVG");
105 break;
106 case svgtiny_SVG_ERROR:
107 fprintf(stderr, "svgtiny_SVG_ERROR: line %i: %s",
108 diagram->error_line,
109 diagram->error_message);
110 break;
111 default:
112 fprintf(stderr, "unknown svgtiny_code %i", code);
113 break;
114 }
115 fprintf(stderr, "\n");
116 }
117
118 if(!(PushChunk(iffh,ID_DR2D,ID_FORM,IFFSIZE_UNKNOWN)))
119 {
120 if(!(PushChunk(iffh,0,ID_NAME,IFFSIZE_UNKNOWN)))
121 {
122 WriteChunkBytes(iffh,url,strlen(url));
123 PopChunk(iffh);
124 }
125
126 if(!(PushChunk(iffh,0,ID_ANNO,19)))
127 {
128 WriteChunkBytes(iffh,"Created by NetSurf\0",19);
129 PopChunk(iffh);
130 }
131
132 if(!(PushChunk(iffh,0,ID_DRHD,16)))
133 {
134 struct drhd_struct drhd;
135 drhd.XLeft = (float) 0.0;
136 drhd.YTop = (float) 0.0;
137 drhd.XRight = (float) diagram->width;
138 drhd.YBot = (float) diagram->height;
139
140 WriteChunkBytes(iffh,&drhd,16);
141 PopChunk(iffh);
142 }
143
144 if(!(PushChunk(iffh,0,ID_DASH,IFFSIZE_UNKNOWN)))
145 {
146 struct dash_struct dash;
147 dash.DashID = 1;
148 dash.NumDashes = 0;
149
150 WriteChunkBytes(iffh,&dash,sizeof(struct dash_struct));
151 PopChunk(iffh);
152 }
153
154 if(!(PushChunk(iffh,0,ID_CMAP,IFFSIZE_UNKNOWN)))
155 {
156 for (unsigned int i = 0; i != diagram->shape_count; i++) {
157 if(diagram->shape[i].fill != svgtiny_TRANSPARENT)
158 {
159 addcolour(diagram->shape[i].fill);
160 }
161
162 if(diagram->shape[i].stroke != svgtiny_TRANSPARENT)
163 {
164 addcolour(diagram->shape[i].stroke);
165 }
166 }
167
168 WriteChunkBytes(iffh,cm,3*numcols);
169 PopChunk(iffh);
170 }
171
172 for (unsigned int i = 0; i != diagram->shape_count; i++) {
173 attr = calloc(1, sizeof(struct attr_struct));
174 if (diagram->shape[i].fill == svgtiny_TRANSPARENT)
175 attr->FillType = FT_NONE;
176 else
177 {
178 attr->FillType = FT_COLOR;
179 attr->FillValue = findcolour(diagram->shape[i].fill);
180 }
181 if (diagram->shape[i].stroke == svgtiny_TRANSPARENT)
182 attr->DashPattern = 0;
183 else
184 {
185 attr->DashPattern = 1;
186 attr->EdgeValue = findcolour(diagram->shape[i].stroke);
187 }
188 attr->EdgeThick = (float) diagram->shape[i].stroke_width;
189
190 if(!(PushChunk(iffh,0,ID_ATTR,IFFSIZE_UNKNOWN)))
191 {
192 WriteChunkBytes(iffh,attr,14);
193 PopChunk(iffh);
194 }
195 free(attr);
196
197 if (diagram->shape[i].path) {
198 union {
199 float PolyPoints;
200 ULONG val;
201 } poly[(diagram->shape[i].path_length)*2];
202
203 USHORT NumPoints;
204 long type;
205 float curx,cury;
206
207 curx = 0.0;
208 cury = 0.0;
209 NumPoints = 0;
210 type = ID_OPLY;
211
212 for (unsigned int j = 0;
213 j != diagram->shape[i].path_length; ) {
214 switch ((int) diagram->shape[i].path[j]) {
215 case svgtiny_PATH_MOVE:
216 if(j != 0)
217 {
218 poly[NumPoints*2].val = INDICATOR;
219 poly[(NumPoints*2)+1].val = IND_MOVETO;
220 NumPoints++;
221 }
222 poly[(NumPoints*2)].PolyPoints = diagram->shape[i].path[j + 1];
223 poly[(NumPoints*2)+1].PolyPoints = diagram->shape[i].path[j + 2];
224 NumPoints++;
225 curx = (float) diagram->shape[i].path[j + 1];
226 cury = (float) diagram->shape[i].path[j + 2];
227
228 j += 3;
229 break;
230 case svgtiny_PATH_CLOSE:
231 type = ID_CPLY;
232 j += 1;
233 break;
234 case svgtiny_PATH_LINE:
235 poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 1];
236 poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 2];
237 NumPoints++;
238 curx = (float) diagram->shape[i].path[j + 1];
239 cury = (float) diagram->shape[i].path[j + 2];
240 j += 3;
241 break;
242 case svgtiny_PATH_BEZIER:
243 poly[NumPoints*2].val = INDICATOR;
244 poly[(NumPoints*2)+1].val = IND_CURVE;
245 NumPoints++;
246 poly[(NumPoints*2)].PolyPoints = curx;
247 poly[(NumPoints*2)+1].PolyPoints = cury;
248 NumPoints++;
249 poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 1];
250 poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 2];
251 NumPoints++;
252 poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 3];
253 poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 4];
254 NumPoints++;
255 poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 5];
256 poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 6];
257 curx = poly[(NumPoints*2)].PolyPoints;
258 cury = poly[(NumPoints*2)+1].PolyPoints;
259 NumPoints++;
260 j += 7;
261 break;
262 default:
263 printf("error\n");
264 j += 1;
265 }
266 }
267 if(!(PushChunk(iffh,0,type,IFFSIZE_UNKNOWN)))
268 {
269 WriteChunkBytes(iffh,&NumPoints,sizeof(USHORT));
270 WriteChunkBytes(iffh,poly,NumPoints*2*4);
271 PopChunk(iffh);
272 }
273 } else if (diagram->shape[i].text) {
274 stxt = calloc(1, sizeof(struct stxt_struct));
275 stxt->BaseX = diagram->shape[i].text_x;
276 stxt->BaseY = diagram->shape[i].text_y;
277 stxt->NumChars = strlen(diagram->shape[i].text);
278 if(!fons_written)
279 {
280 fons = calloc(1, sizeof(struct fons_struct));
281 if(!(PushChunk(iffh, 0, ID_FONS, IFFSIZE_UNKNOWN)))
282 {
283 WriteChunkBytes(iffh, fons, sizeof(struct fons_struct));
284 WriteChunkBytes(iffh, "Topaz\0", 6);
285 PopChunk(iffh);
286 }
287 free(fons);
288 fons_written = TRUE;
289 }
290
291 if(!(PushChunk(iffh, 0, ID_STXT, IFFSIZE_UNKNOWN)))
292 {
293 WriteChunkBytes(iffh, stxt, 26);
294 WriteChunkBytes(iffh, diagram->shape[i].text, strlen(diagram->shape[i].text));
295 PopChunk(iffh);
296 }
297 free(stxt);
298 }
299 }
300
301 PopChunk(iffh);
302 }
303
304 svgtiny_free(diagram);
305
306 return 0;
307 }
308
309 #ifndef AMIGA_DR2D_STANDALONE
ami_save_svg(struct hlcache_handle * c,char * filename)310 bool ami_save_svg(struct hlcache_handle *c,char *filename)
311 {
312 struct IFFHandle *iffh;
313 const uint8_t *source_data;
314 size_t source_size;
315
316 if (!ami_download_check_overwrite(filename, NULL, 0)) return false;
317
318 if ((iffh = AllocIFF())) {
319 if ((iffh->iff_Stream = Open(filename,MODE_NEWFILE))) {
320 InitIFFasDOS(iffh);
321 }
322 else return false;
323 }
324
325 if ((OpenIFF(iffh,IFFF_WRITE))) return false;
326
327 source_data = content_get_source_data(c, &source_size);
328 if (source_data != NULL) {
329 ami_svg_to_dr2d(iffh,
330 (const char *)source_data,
331 source_size,
332 nsurl_access(hlcache_handle_get_url(c)));
333 }
334
335 if(iffh) CloseIFF(iffh);
336 if(iffh->iff_Stream) Close((BPTR)iffh->iff_Stream);
337 if(iffh) FreeIFF(iffh);
338
339 return true;
340 }
341 #else
342 /*
343 * This code can be compiled as a standalone program for testing etc.
344 * Use something like the following line:
345 * gcc -o svg2dr2d iff_dr2d.c -lauto -lsvgtiny -lpthread -lsvgtiny
346 * -ldom -lwapcaplet -lexpat -lparserutils
347 * -DWITH_NS_SVG -DAMIGA_DR2D_STANDALONE -D__USE_INLINE__ -D__NOLIBBASE__
348 */
349
350 const char __attribute__((used)) ver[] = "\0$VER: svg2dr2d 1.2 (05.01.2015)\0";
351
main(int argc,char ** argv)352 int main(int argc, char **argv)
353 {
354 BPTR fh = 0;
355 char *buffer;
356 struct IFFHandle *iffh = NULL;
357 int64_t size;
358 LONG rarray[] = {0,0};
359 struct RDArgs *args;
360 STRPTR template = "SVG=INPUT/A,DR2D=OUTPUT/A";
361 enum
362 {
363 A_SVG,
364 A_DR2D
365 };
366
367 #ifndef __amigaos4__
368 DOSBase = OpenLibrary("dos.library", 37);
369 if(!DOSBase) return RETURN_FAIL;
370
371 IFFParseBase = OpenLibrary("iffparse.library", 37);
372 if(!IFFParseBase) return RETURN_FAIL;
373 #endif
374
375 args = ReadArgs(template,rarray,NULL);
376
377 if(!args)
378 {
379 printf("Required argument missing\n");
380 return 20;
381 }
382
383 if(fh = Open((char *)rarray[A_SVG],MODE_OLDFILE))
384 {
385 size = GetFileSize(fh);
386
387 buffer = malloc((uint32_t)size);
388
389 Read(fh,buffer,(uint32_t)size);
390 Close(fh);
391 }
392 else
393 {
394 printf("Unable to open file\n");
395 return 20;
396 }
397
398 if(iffh = AllocIFF())
399 {
400 if(iffh->iff_Stream = Open((char *)rarray[A_DR2D],MODE_NEWFILE))
401 {
402 InitIFFasDOS(iffh);
403 }
404 else return 20;
405 }
406
407 if((OpenIFF(iffh,IFFF_WRITE))) return 20;
408
409 ami_svg_to_dr2d(iffh,buffer,size,(char *)rarray[A_SVG]);
410
411 free(buffer);
412 if(iffh) CloseIFF(iffh);
413 if(iffh->iff_Stream) Close((BPTR)iffh->iff_Stream);
414 if(iffh) FreeIFF(iffh);
415 FreeArgs(args);
416
417 #ifndef __amigaos4__
418 if(DOSBase) CloseLibrary(DOSBase);
419 if(IFFParseBase) CloseLibrary(IFFParseBase);
420 #endif
421 }
422
423 #endif // AMIGA_DR2D_STANDALONE
424 #endif // WITH_NS_SVG
425
426