NetSurf
iff_dr2d.c
Go to the documentation of this file.
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
39static struct ColorRegister cm[1000];
40static ULONG numcols;
41
42static 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
61static 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
75bool 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 WriteChunkBytes(iffh,"\0",1);
124 PopChunk(iffh);
125 }
126
127 if(!(PushChunk(iffh,0,ID_ANNO,19)))
128 {
129 WriteChunkBytes(iffh,"Created by NetSurf\0",19);
130 PopChunk(iffh);
131 }
132
133 if(!(PushChunk(iffh,0,ID_DRHD,16)))
134 {
135 struct drhd_struct drhd;
136 drhd.XLeft = (float) 0.0;
137 drhd.YTop = (float) 0.0;
138 drhd.XRight = (float) diagram->width;
139 drhd.YBot = (float) diagram->height;
140
141 WriteChunkBytes(iffh,&drhd,16);
142 PopChunk(iffh);
143 }
144
145 if(!(PushChunk(iffh,0,ID_DASH,IFFSIZE_UNKNOWN)))
146 {
147 struct dash_struct dash;
148 dash.DashID = 1;
149 dash.NumDashes = 0;
150
151 WriteChunkBytes(iffh,&dash,sizeof(struct dash_struct));
152 PopChunk(iffh);
153 }
154
155 if(!(PushChunk(iffh,0,ID_CMAP,IFFSIZE_UNKNOWN)))
156 {
157 for (unsigned int i = 0; i != diagram->shape_count; i++) {
158 if(diagram->shape[i].fill != svgtiny_TRANSPARENT)
159 {
160 addcolour(diagram->shape[i].fill);
161 }
162
163 if(diagram->shape[i].stroke != svgtiny_TRANSPARENT)
164 {
165 addcolour(diagram->shape[i].stroke);
166 }
167 }
168
169 WriteChunkBytes(iffh,cm,3*numcols);
170 PopChunk(iffh);
171 }
172
173 for (unsigned int i = 0; i != diagram->shape_count; i++) {
174 attr = calloc(1, sizeof(struct attr_struct));
175 if (diagram->shape[i].fill == svgtiny_TRANSPARENT)
176 attr->FillType = FT_NONE;
177 else
178 {
179 attr->FillType = FT_COLOR;
180 attr->FillValue = findcolour(diagram->shape[i].fill);
181 }
182 if (diagram->shape[i].stroke == svgtiny_TRANSPARENT)
183 attr->DashPattern = 0;
184 else
185 {
186 attr->DashPattern = 1;
187 attr->EdgeValue = findcolour(diagram->shape[i].stroke);
188 }
189
190 attr->EdgeThick = (float) diagram->shape[i].stroke_width;
191
192 if(!(PushChunk(iffh,0,ID_ATTR,IFFSIZE_UNKNOWN)))
193 {
194 WriteChunkBytes(iffh,attr,14);
195 PopChunk(iffh);
196 }
197 free(attr);
198
199 if (diagram->shape[i].path) {
200 union {
201 float PolyPoints;
202 ULONG val;
203 } poly[(diagram->shape[i].path_length)*2];
204
205 USHORT NumPoints;
206 long type;
207 float curx,cury;
208
209 curx = 0.0;
210 cury = 0.0;
211 NumPoints = 0;
212 type = ID_OPLY;
213
214 for (unsigned int j = 0;
215 j != diagram->shape[i].path_length; ) {
216 switch ((int) diagram->shape[i].path[j]) {
217 case svgtiny_PATH_MOVE:
218 if(j != 0)
219 {
220 poly[NumPoints*2].val = INDICATOR;
221 poly[(NumPoints*2)+1].val = IND_MOVETO;
222 NumPoints++;
223 }
224 poly[(NumPoints*2)].PolyPoints = diagram->shape[i].path[j + 1];
225 poly[(NumPoints*2)+1].PolyPoints = diagram->shape[i].path[j + 2];
226 NumPoints++;
227 curx = (float) diagram->shape[i].path[j + 1];
228 cury = (float) diagram->shape[i].path[j + 2];
229
230 j += 3;
231 break;
232 case svgtiny_PATH_CLOSE:
233 type = ID_CPLY;
234 j += 1;
235 break;
236 case svgtiny_PATH_LINE:
237 poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 1];
238 poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 2];
239 NumPoints++;
240 curx = (float) diagram->shape[i].path[j + 1];
241 cury = (float) diagram->shape[i].path[j + 2];
242 j += 3;
243 break;
244 case svgtiny_PATH_BEZIER:
245 poly[NumPoints*2].val = INDICATOR;
246 poly[(NumPoints*2)+1].val = IND_CURVE;
247 NumPoints++;
248 poly[(NumPoints*2)].PolyPoints = curx;
249 poly[(NumPoints*2)+1].PolyPoints = cury;
250 NumPoints++;
251 poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 1];
252 poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 2];
253 NumPoints++;
254 poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 3];
255 poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 4];
256 NumPoints++;
257 poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 5];
258 poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 6];
259 curx = poly[(NumPoints*2)].PolyPoints;
260 cury = poly[(NumPoints*2)+1].PolyPoints;
261 NumPoints++;
262 j += 7;
263 break;
264 default:
265 printf("error\n");
266 j += 1;
267 }
268 }
269 if(!(PushChunk(iffh,0,type,IFFSIZE_UNKNOWN)))
270 {
271 WriteChunkBytes(iffh,&NumPoints,sizeof(USHORT));
272 WriteChunkBytes(iffh,poly,NumPoints*2*4);
273 PopChunk(iffh);
274 }
275 } else if (diagram->shape[i].text) {
276 stxt = calloc(1, sizeof(struct stxt_struct));
277 stxt->BaseX = diagram->shape[i].text_x;
278 stxt->BaseY = diagram->shape[i].text_y;
279 stxt->NumChars = strlen(diagram->shape[i].text);
280 if(!fons_written)
281 {
282 fons = calloc(1, sizeof(struct fons_struct));
283 if(!(PushChunk(iffh, 0, ID_FONS, IFFSIZE_UNKNOWN)))
284 {
285 WriteChunkBytes(iffh, fons, sizeof(struct fons_struct));
286 WriteChunkBytes(iffh, "Helvetica\0", 10);
287 PopChunk(iffh);
288 }
289 free(fons);
290 fons_written = TRUE;
291 }
292
293 if(!(PushChunk(iffh, 0, ID_STXT, IFFSIZE_UNKNOWN)))
294 {
295 WriteChunkBytes(iffh, stxt, 26);
296 WriteChunkBytes(iffh, diagram->shape[i].text, strlen(diagram->shape[i].text));
297 PopChunk(iffh);
298 }
299 free(stxt);
300 }
301 }
302
303 PopChunk(iffh);
304 }
305
306 svgtiny_free(diagram);
307
308 return 0;
309}
310
311#ifndef AMIGA_DR2D_STANDALONE
312bool ami_save_svg(struct hlcache_handle *c,char *filename)
313{
314 struct IFFHandle *iffh;
315 const uint8_t *source_data;
316 size_t source_size;
317
318 if (!ami_download_check_overwrite(filename, NULL, 0)) return false;
319
320 if ((iffh = AllocIFF())) {
321 if ((iffh->iff_Stream = Open(filename,MODE_NEWFILE))) {
322 InitIFFasDOS(iffh);
323 }
324 else return false;
325 }
326
327 if ((OpenIFF(iffh,IFFF_WRITE))) return false;
328
329 source_data = content_get_source_data(c, &source_size);
330 if (source_data != NULL) {
331 ami_svg_to_dr2d(iffh,
332 (const char *)source_data,
333 source_size,
335 }
336
337 if(iffh) CloseIFF(iffh);
338 if(iffh->iff_Stream) Close((BPTR)iffh->iff_Stream);
339 if(iffh) FreeIFF(iffh);
340
341 return true;
342}
343#else
344/*
345 * This code can be compiled as a standalone program for testing etc.
346 * Use something like the following line:
347 * gcc -o svg2dr2d iff_dr2d.c -lauto -lsvgtiny -lpthread -lsvgtiny
348 * -ldom -lwapcaplet -lexpat -lparserutils
349 * -DWITH_NS_SVG -DAMIGA_DR2D_STANDALONE -D__USE_INLINE__ -D__NOLIBBASE__
350 */
351
352const char __attribute__((used)) ver[] = "\0$VER: svg2dr2d 1.2 (05.01.2015)\0";
353
354int main(int argc, char **argv)
355{
356 BPTR fh = 0;
357 char *buffer;
358 struct IFFHandle *iffh = NULL;
359 int64_t size;
360 LONG rarray[] = {0,0};
361 struct RDArgs *args;
362 STRPTR template = "SVG=INPUT/A,DR2D=OUTPUT/A";
363 enum
364 {
365 A_SVG,
366 A_DR2D
367 };
368
369#ifndef __amigaos4__
370 DOSBase = OpenLibrary("dos.library", 37);
371 if(!DOSBase) return RETURN_FAIL;
372
373 IFFParseBase = OpenLibrary("iffparse.library", 37);
374 if(!IFFParseBase) return RETURN_FAIL;
375#endif
376
377 args = ReadArgs(template,rarray,NULL);
378
379 if(!args)
380 {
381 printf("Required argument missing\n");
382 return 20;
383 }
384
385 if(fh = Open((char *)rarray[A_SVG],MODE_OLDFILE))
386 {
387 size = GetFileSize(fh);
388
389 buffer = malloc((uint32_t)size);
390
391 Read(fh,buffer,(uint32_t)size);
392 Close(fh);
393 }
394 else
395 {
396 printf("Unable to open file\n");
397 return 20;
398 }
399
400 if(iffh = AllocIFF())
401 {
402 if(iffh->iff_Stream = Open((char *)rarray[A_DR2D],MODE_NEWFILE))
403 {
404 InitIFFasDOS(iffh);
405 }
406 else return 20;
407 }
408
409 if((OpenIFF(iffh,IFFF_WRITE))) return 20;
410
411 ami_svg_to_dr2d(iffh,buffer,size,(char *)rarray[A_SVG]);
412
413 free(buffer);
414 if(iffh) CloseIFF(iffh);
415 if(iffh->iff_Stream) Close((BPTR)iffh->iff_Stream);
416 if(iffh) FreeIFF(iffh);
417 FreeArgs(args);
418
419#ifndef __amigaos4__
420 if(DOSBase) CloseLibrary(DOSBase);
421 if(IFFParseBase) CloseLibrary(IFFParseBase);
422#endif
423}
424
425#endif // AMIGA_DR2D_STANDALONE
426#endif // WITH_NS_SVG
427
static struct IFFHandle * iffh
Definition: clipboard.c:53
static const __attribute__((used))
Definition: gui.c:360
int main(int argc, char **argv)
Normal entry point from OS.
Definition: gui.c:6543
static osspriteop_area * buffer
The buffer characteristics.
Definition: buffer.c:55
const char * type
Definition: filetype.cpp:44
BOOL ami_download_check_overwrite(const char *file, struct Window *win, ULONG size)
Definition: download.c:481
Public content interface.
struct nsurl * hlcache_handle_get_url(const struct hlcache_handle *handle)
Retrieve the URL associated with a high level cache handle.
const uint8_t * content_get_source_data(struct hlcache_handle *h, size_t *size)
Retrieve source of content.
Definition: content.c:1209
Netsurf additional integer type formatting macros.
NetSurf URL handling (interface).
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
int64 GetFileSize(BPTR fh)
Definition: os3support.c:337
Minimal compatibility header for AmigaOS 3.
Interface to utility string handling.
High-level cache handle.
Definition: hlcache.c:66