OSDN Git Service

5a408f45e4dd5a64308564a494ae269a818e1c76
[charactermanaj/CharacterManaJ.git] / src / main / java / charactermanaj / model / io / CharacterDataXMLWriter.java
1 package charactermanaj.model.io;
2
3 import java.awt.Color;
4 import java.io.IOException;
5 import java.io.OutputStream;
6 import java.io.OutputStreamWriter;
7 import java.nio.charset.Charset;
8 import java.util.Collection;
9 import java.util.HashMap;
10 import java.util.List;
11 import java.util.Locale;
12 import java.util.Map;
13 import java.util.Set;
14
15 import javax.xml.XMLConstants;
16 import javax.xml.parsers.DocumentBuilder;
17 import javax.xml.parsers.DocumentBuilderFactory;
18 import javax.xml.parsers.ParserConfigurationException;
19 import javax.xml.transform.OutputKeys;
20 import javax.xml.transform.Transformer;
21 import javax.xml.transform.TransformerConfigurationException;
22 import javax.xml.transform.TransformerException;
23 import javax.xml.transform.TransformerFactory;
24 import javax.xml.transform.dom.DOMSource;
25 import javax.xml.transform.stream.StreamResult;
26
27 import org.w3c.dom.Attr;
28 import org.w3c.dom.Document;
29 import org.w3c.dom.Element;
30
31 import charactermanaj.graphics.filters.ColorConv;
32 import charactermanaj.graphics.filters.ColorConvertParameter;
33 import charactermanaj.model.CharacterData;
34 import charactermanaj.model.ColorGroup;
35 import charactermanaj.model.ColorInfo;
36 import charactermanaj.model.Layer;
37 import charactermanaj.model.PartsCategory;
38 import charactermanaj.model.PartsColorInfo;
39 import charactermanaj.model.PartsIdentifier;
40 import charactermanaj.model.PartsSet;
41 import charactermanaj.model.RecommendationURL;
42
43 /**
44  * パーツ管理情報のXMLへの書き込み用クラス.
45  *
46  * @author seraphy
47  */
48 public class CharacterDataXMLWriter {
49
50         /**
51          * キャラクター定義バージョン
52          */
53         private static final String VERSION_SIG_1_0 = "1.0";
54
55         /**
56          * キャラクター定義XMLファイルの名前空間
57          */
58         private static final String DEFAULT_NS = "http://charactermanaj.sourceforge.jp/schema/charactermanaj";
59
60         private final String NS;
61
62         public CharacterDataXMLWriter() {
63                 this(DEFAULT_NS);
64         }
65
66         public CharacterDataXMLWriter(String ns) {
67                 this.NS = ns;
68         }
69
70         /**
71          * キャラクターデータのXMLの書き込み.
72          *
73          * @param characterData
74          * @param outstm
75          * @throws IOException
76          */
77         public void writeXMLCharacterData(CharacterData characterData,
78                         OutputStream outstm) throws IOException {
79                 if (outstm == null || characterData == null) {
80                         throw new IllegalArgumentException();
81                 }
82
83                 Locale locale = Locale.getDefault();
84                 String lang = locale.getLanguage();
85
86                 Document doc;
87                 try {
88                         DocumentBuilderFactory factory = DocumentBuilderFactory
89                                         .newInstance();
90                         factory.setNamespaceAware(true);
91                         DocumentBuilder builder = factory.newDocumentBuilder();
92                         doc = builder.newDocument();
93                 } catch (ParserConfigurationException ex) {
94                         throw new RuntimeException("JAXP Configuration failed.", ex);
95                 }
96
97                 Element root = doc.createElementNS(NS, "character");
98                 root.setAttribute("version", VERSION_SIG_1_0);
99
100                 root.setAttribute("xmlns:xml", XMLConstants.XML_NS_URI);
101                 root.setAttribute("xmlns:xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
102                 root.setAttribute("xsi:schemaLocation", NS + " character.xsd");
103                 root.setAttribute("id", characterData.getId());
104                 root.setAttribute("rev", characterData.getRev());
105                 doc.appendChild(root);
106
107                 // name
108                 Element nodeName = doc.createElementNS(NS, "name");
109                 Attr attrLang = doc.createAttributeNS(XMLConstants.XML_NS_URI, "lang");
110                 attrLang.setValue(lang);
111                 nodeName.setAttributeNodeNS(attrLang);
112                 nodeName.setTextContent(characterData.getName());
113                 root.appendChild(nodeName);
114
115                 // information
116                 String author = characterData.getAuthor();
117                 String description = characterData.getDescription();
118                 if ((author != null && author.length() > 0)
119                                 || (description != null && description.length() > 0)) {
120                         Element nodeInfomation = doc.createElementNS(NS, "information");
121                         if (author != null && author.length() > 0) {
122                                 Element nodeAuthor = doc.createElementNS(NS, "author");
123                                 Attr attrNodeAuthorLang = doc.createAttributeNS(
124                                                 XMLConstants.XML_NS_URI, "lang");
125                                 attrNodeAuthorLang.setValue(lang);
126                                 nodeAuthor.setAttributeNodeNS(attrNodeAuthorLang);
127                                 nodeAuthor.setTextContent(author);
128                                 nodeInfomation.appendChild(nodeAuthor);
129                         }
130                         if (description != null && description.length() > 0) {
131
132                                 // 説明の改行コードはXML上ではLFとする.
133                                 description = description.replace("\r\n", "\n");
134                                 description = description.replace("\r", "\n");
135
136                                 Element nodeDescription = doc
137                                                 .createElementNS(NS, "description");
138                                 Attr attrNodeDescriptionLang = doc.createAttributeNS(
139                                                 XMLConstants.XML_NS_URI, "lang");
140                                 attrNodeDescriptionLang.setValue(lang);
141                                 nodeDescription.setAttributeNodeNS(attrNodeDescriptionLang);
142                                 nodeDescription.setTextContent(description);
143                                 nodeInfomation.appendChild(nodeDescription);
144                         }
145                         root.appendChild(nodeInfomation);
146                 }
147
148                 // size
149                 Element nodeSize = doc.createElementNS(NS, "image-size");
150                 Element nodeWidth = doc.createElementNS(NS, "width");
151                 nodeWidth.setTextContent(Integer.toString((int) characterData
152                                 .getImageSize().getWidth()));
153                 Element nodeHeight = doc.createElementNS(NS, "height");
154                 nodeHeight.setTextContent(Integer.toString((int) characterData
155                                 .getImageSize().getHeight()));
156                 nodeSize.appendChild(nodeWidth);
157                 nodeSize.appendChild(nodeHeight);
158                 root.appendChild(nodeSize);
159
160                 // settings
161                 Element nodeSettings = doc.createElementNS(NS, "settings");
162                 root.appendChild(nodeSettings);
163                 for (String settingsEntryName : characterData.getPropertyNames()) {
164                         String value = characterData.getProperty(settingsEntryName);
165                         if (value != null) {
166                                 Element nodeEntry = doc.createElementNS(NS, "entry");
167                                 nodeEntry.setAttribute("key", settingsEntryName);
168                                 nodeEntry.setTextContent(value);
169                                 nodeSettings.appendChild(nodeEntry);
170                         }
171                 }
172
173                 // categories
174                 Element nodeCategories = doc.createElementNS(NS, "categories");
175                 for (PartsCategory category : characterData.getPartsCategories()) {
176                         // category
177                         Element nodeCategory = doc.createElementNS(NS, "category");
178                         nodeCategory.setAttribute("id", category.getCategoryId());
179
180                         nodeCategory.setAttribute("multipleSelectable",
181                                         category.isMultipleSelectable() ? "true" : "false");
182                         nodeCategory.setAttribute("optional",
183                                         category.isOptional() ? "true" : "false");
184
185                         // visible-rows
186                         Element nodeVisibleRows = doc.createElementNS(NS, "visible-rows");
187                         nodeVisibleRows.setTextContent(Integer.toString(category
188                                         .getVisibleRows()));
189                         nodeCategory.appendChild(nodeVisibleRows);
190
191                         // category name
192                         Element nodeCategoryName = doc.createElementNS(NS, "display-name");
193                         Attr attrCategoryNameLang = doc.createAttributeNS(
194                                         XMLConstants.XML_NS_URI, "lang");
195                         attrCategoryNameLang.setValue(lang);
196                         nodeCategoryName.setAttributeNodeNS(attrCategoryNameLang);
197                         nodeCategoryName
198                                         .setTextContent(category.getLocalizedCategoryName());
199                         nodeCategory.appendChild(nodeCategoryName);
200
201                         // layers
202                         Element nodeLayers = doc.createElementNS(NS, "layers");
203                         for (Layer layer : category.getLayers()) {
204                                 // layer
205                                 Element nodeLayer = doc.createElementNS(NS, "layer");
206                                 nodeLayer.setAttribute("id", layer.getId());
207
208                                 Element nodeLayerName = doc.createElementNS(NS, "display-name");
209                                 Attr attrLayerNameLang = doc.createAttributeNS(
210                                                 XMLConstants.XML_NS_URI, "lang");
211                                 attrLayerNameLang.setValue(lang);
212                                 nodeLayerName.setAttributeNodeNS(attrLayerNameLang);
213                                 nodeLayerName.setTextContent(layer.getLocalizedName());
214                                 nodeLayer.appendChild(nodeLayerName);
215
216                                 Element nodeOrder = doc.createElementNS(NS, "order");
217                                 nodeOrder.setTextContent(Integer.toString(layer.getOrder()));
218                                 nodeLayer.appendChild(nodeOrder);
219
220                                 ColorGroup colorGroup = layer.getColorGroup();
221                                 if (colorGroup != null && colorGroup.isEnabled()) {
222                                         Element nodeColorGroup = doc.createElementNS(NS,
223                                                         "colorGroup");
224                                         nodeColorGroup.setAttribute("refid", colorGroup.getId());
225                                         nodeColorGroup.setAttribute("init-sync", layer.isInitSync()
226                                                         ? "true"
227                                                         : "false");
228                                         nodeLayer.appendChild(nodeColorGroup);
229                                 }
230
231                                 Element nodeDir = doc.createElementNS(NS, "dir");
232                                 nodeDir.setTextContent(layer.getDir());
233                                 nodeLayer.appendChild(nodeDir);
234
235                                 String colorModelName = layer.getColorModelName();
236                                 if (colorModelName != null && colorModelName.length() > 0) {
237                                         Element nodeColorModel = doc.createElementNS(NS,
238                                                         "colorModel");
239                                         nodeColorModel.setTextContent(layer.getColorModelName());
240                                         nodeLayer.appendChild(nodeColorModel);
241                                 }
242
243                                 nodeLayers.appendChild(nodeLayer);
244                         }
245                         nodeCategory.appendChild(nodeLayers);
246
247                         nodeCategories.appendChild(nodeCategory);
248                 }
249                 root.appendChild(nodeCategories);
250
251                 // ColorGroupを構築する
252                 Collection<ColorGroup> colorGroups = characterData.getColorGroups();
253                 if (colorGroups.size() > 0) {
254                         Element nodeColorGroups = doc.createElementNS(NS, "colorGroups");
255                         int colorGroupCount = 0;
256                         for (ColorGroup colorGroup : colorGroups) {
257                                 if (!colorGroup.isEnabled()) {
258                                         continue;
259                                 }
260                                 Element nodeColorGroup = doc.createElementNS(NS, "colorGroup");
261                                 nodeColorGroup.setAttribute("id", colorGroup.getId());
262                                 Element nodeColorGroupName = doc.createElementNS(NS,
263                                                 "display-name");
264                                 Attr attrColorGroupNameLang = doc.createAttributeNS(
265                                                 XMLConstants.XML_NS_URI, "lang");
266                                 attrColorGroupNameLang.setValue(lang);
267                                 nodeColorGroupName.setAttributeNodeNS(attrColorGroupNameLang);
268                                 nodeColorGroupName
269                                                 .setTextContent(colorGroup.getLocalizedName());
270                                 nodeColorGroup.appendChild(nodeColorGroupName);
271                                 nodeColorGroups.appendChild(nodeColorGroup);
272                                 colorGroupCount++;
273                         }
274                         if (colorGroupCount > 0) {
275                                 root.appendChild(nodeColorGroups);
276                         }
277                 }
278
279                 // Recommendations
280                 List<RecommendationURL> recommendations = characterData
281                                 .getRecommendationURLList();
282                 if (recommendations != null) {
283                         Element nodeRecommendations = doc.createElementNS(NS,
284                                         "recommendations");
285                         for (RecommendationURL recommendation : recommendations) {
286                                 Element nodeRecommendation = doc.createElementNS(NS,
287                                                 "recommendation");
288                                 String displayName = recommendation.getDisplayName();
289                                 String url = recommendation.getUrl();
290
291                                 Element nodeDescription = doc
292                                                 .createElementNS(NS, "description");
293                                 Attr attrRecommendationDescriptionLang = doc.createAttributeNS(
294                                                 XMLConstants.XML_NS_URI, "lang");
295                                 attrRecommendationDescriptionLang.setValue(lang);
296                                 nodeDescription
297                                                 .setAttributeNodeNS(attrRecommendationDescriptionLang);
298                                 nodeDescription.setTextContent(displayName);
299
300                                 Element nodeURL = doc.createElementNS(NS, "URL");
301                                 Attr attrRecommendationURLLang = doc.createAttributeNS(
302                                                 XMLConstants.XML_NS_URI, "lang");
303                                 attrRecommendationURLLang.setValue(lang);
304                                 nodeURL.setAttributeNodeNS(attrRecommendationURLLang);
305                                 nodeURL.setTextContent(url);
306
307                                 nodeRecommendation.appendChild(nodeDescription);
308                                 nodeRecommendation.appendChild(nodeURL);
309
310                                 nodeRecommendations.appendChild(nodeRecommendation);
311                         }
312                         root.appendChild(nodeRecommendations);
313                 }
314
315                 // presetsのelementを構築する.
316                 Element nodePresets = doc.createElementNS(NS, "presets");
317                 if (writePartsSetElements(doc, nodePresets, characterData, true, false) > 0) {
318                         root.appendChild(nodePresets);
319                 }
320
321                 // output xml
322                 TransformerFactory txFactory = TransformerFactory.newInstance();
323                 txFactory.setAttribute("indent-number", Integer.valueOf(4));
324                 Transformer tfmr;
325                 try {
326                         tfmr = txFactory.newTransformer();
327                 } catch (TransformerConfigurationException ex) {
328                         throw new RuntimeException("JAXP Configuration Failed.", ex);
329                 }
330                 tfmr.setOutputProperty(OutputKeys.INDENT, "yes");
331
332                 // JDK-4504745 : javax.xml.transform.Transformer encoding does not work properly
333                 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4504745
334                 final String encoding = "UTF-8";
335                 tfmr.setOutputProperty("encoding", encoding);
336                 try {
337                         tfmr.transform(new DOMSource(doc), new StreamResult(
338                                         new OutputStreamWriter(outstm, Charset.forName(encoding))));
339
340                 } catch (TransformerException ex) {
341                         IOException ex2 = new IOException("XML Convert failed.");
342                         ex2.initCause(ex);
343                         throw ex2;
344                 }
345         }
346
347         /**
348          * キャラクターデータ内のPresetおよびFavotiesのPartssetの双方共通のパーツセット要素のリストを構築する.
349          *
350          * @param doc
351          *            ドキュメントオブジェクト(createElementNS用)
352          * @param baseElement
353          *            親要素、キャラクターデータの場合はPreset、Favoritesの場合はPartssetを示す要素
354          * @param characterData
355          *            キャラクターデータ
356          * @param writePresets
357          *            Preset属性のパーツセットを登録する場合はtrue、Preset属性時はデフォルトプリセット属性も(あれば)登録される
358          * @param writeFavorites
359          *            Preset属性のないパーツセットを登録する場合はtrue
360          * @return 登録したパーツセットの個数
361          */
362         protected int writePartsSetElements(Document doc, Element baseElement,
363                         CharacterData characterData, boolean writePresets,
364                         boolean writeFavorites) {
365                 Map<String, PartsSet> partsSetMap = characterData.getPartsSets();
366
367                 Locale locale = Locale.getDefault();
368                 String lang = locale.getLanguage();
369
370                 HashMap<String, PartsSet> registeredPartsSetMap = new HashMap<String, PartsSet>();
371
372                 for (Map.Entry<String, PartsSet> partsSetsEntry : partsSetMap
373                                 .entrySet()) {
374                         PartsSet partsSet = partsSetsEntry.getValue();
375                         if (partsSet.isPresetParts() && !writePresets) {
376                                 continue;
377                         }
378                         if (!partsSet.isPresetParts() && !writeFavorites) {
379                                 continue;
380                         }
381
382                         if (partsSet.isEmpty()) {
383                                 // 空のパーツセットは登録しない.
384                                 continue;
385                         }
386
387                         Element nodePreset = createPartsSetXML(doc, lang, partsSet);
388                         baseElement.appendChild(nodePreset);
389                         registeredPartsSetMap.put(partsSet.getPartsSetId(), partsSet);
390                 }
391
392                 // プリセット登録時はデフォルトのプリセットIDがあれば、それも登録する.
393                 // (ただし、該当パーツセットが書き込み済みである場合のみ)
394                 if (writePresets) {
395                         String defaultPresetId = characterData.getDefaultPartsSetId();
396                         if (defaultPresetId != null && defaultPresetId.length() > 0) {
397                                 PartsSet defaultPartsSet = registeredPartsSetMap
398                                                 .get(defaultPresetId);
399                                 if (defaultPartsSet != null && defaultPartsSet.isPresetParts()) {
400                                         baseElement.setAttribute("default-preset", defaultPresetId);
401                                 }
402                         }
403                 }
404
405                 return registeredPartsSetMap.size();
406         }
407
408         /**
409          * パーツセットのXM要素を生成して返す.
410          *
411          * @param doc
412          *            ノードを生成するためのファクトリ
413          * @param lang
414          *            言語識別用(パーツセット名などの登録時のlang属性に必要)
415          * @param partsSet
416          *            パーツセット、nullの場合はxsi:nul="true"が返される.
417          * @return パーツセット1つ分のXML要素
418          */
419         public Element createPartsSetXML(Document doc, String lang, PartsSet partsSet) {
420                 if (doc == null || lang == null) {
421                         throw new IllegalArgumentException();
422                 }
423
424                 String partsSetId = partsSet.getPartsSetId();
425                 String localizedName = partsSet.getLocalizedName();
426
427                 Element nodePreset = doc.createElementNS(NS, "preset");
428                 if (partsSet == null || partsSet.isEmpty()) {
429                         // 指定されていないか有効でない場合は無しとみなす.
430                         nodePreset.setAttributeNS(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:nil", "true");
431                         return nodePreset;
432                 }
433
434                 nodePreset.setAttribute("id", partsSetId);
435
436                 // display-name
437                 Element nodeName = doc.createElementNS(NS, "display-name");
438                 Attr attrLang = doc.createAttributeNS(XMLConstants.XML_NS_URI,
439                                 "lang");
440                 attrLang.setValue(lang);
441                 nodeName.setAttributeNode(attrLang);
442                 nodeName.setTextContent(localizedName);
443                 nodePreset.appendChild(nodeName);
444
445                 // bgColor
446                 Color bgColor = partsSet.getBgColor();
447                 if (bgColor != null) {
448                         Element nodeBgColor = doc.createElementNS(NS,
449                                         "background-color");
450                         nodeBgColor.setAttribute("color",
451                                         "#" + Integer.toHexString(bgColor.getRGB() & 0xffffff));
452                         nodePreset.appendChild(nodeBgColor);
453                 }
454
455                 // affine transform parameter
456                 double[] affineTransformParameter = partsSet
457                                 .getAffineTransformParameter();
458                 if (affineTransformParameter != null) {
459                         Element nodeAffineTransform = doc.createElementNS(NS,
460                                         "affine-transform-parameter");
461                         StringBuilder tmp = new StringBuilder();
462                         for (double affineItem : affineTransformParameter) {
463                                 if (tmp.length() > 0) {
464                                         tmp.append(" ");
465                                 }
466                                 tmp.append(Double.toString(affineItem));
467                         }
468                         nodeAffineTransform.setTextContent(tmp.toString());
469                         nodePreset.appendChild(nodeAffineTransform);
470                 }
471
472                 // categories
473                 for (Map.Entry<PartsCategory, List<PartsIdentifier>> entry : partsSet
474                                 .entrySet()) {
475                         PartsCategory partsCategory = entry.getKey();
476
477                         // category
478                         Element nodeCategory = doc.createElementNS(NS, "category");
479                         nodeCategory.setAttribute("refid",
480                                         partsCategory.getCategoryId());
481                         nodePreset.appendChild(nodeCategory);
482
483                         List<PartsIdentifier> partsIdentifiers = entry.getValue();
484                         for (PartsIdentifier partsIdentifier : partsIdentifiers) {
485                                 String partsName = partsIdentifier.getPartsName();
486                                 Element nodeParts = doc.createElementNS(NS, "parts");
487                                 nodeParts.setAttribute("name", partsName);
488                                 nodeCategory.appendChild(nodeParts);
489
490                                 PartsColorInfo partsColorInfo = partsSet
491                                                 .getColorInfo(partsIdentifier);
492                                 if (partsColorInfo != null) {
493                                         Element nodeColor = createPartsColorInfoXML(doc, partsColorInfo);
494                                         nodeParts.appendChild(nodeColor);
495                                 }
496                         }
497                 }
498
499                 // アクティブなレイヤーパターン
500                 Set<String> patternIds = partsSet.getActiveCustomLayerPatternIds();
501                 if (patternIds != null) {
502                         Element patternsElm = doc.createElementNS(NS, "active-custom-layer-patterns");
503                         for (String patternId : patternIds) {
504                                 Element patElm = doc.createElementNS(NS, "pattern");
505                                 patElm.setAttribute("id", patternId);
506                                 patternsElm.appendChild(patElm);
507                         }
508                         nodePreset.appendChild(patternsElm);
509                 }
510
511                 return nodePreset;
512         }
513
514         /**
515          * パーツカラー情報のXML要素を生成して返す.<br>
516          *
517          * @param doc
518          *            要素を作成するためのファクトリ
519          * @param partsColorInfo
520          *            パーツカラー情報
521          * @return パーツカラー情報の要素
522          */
523         public Element createPartsColorInfoXML(Document doc, PartsColorInfo partsColorInfo) {
524                 if (doc == null || partsColorInfo == null) {
525                         throw new IllegalArgumentException();
526                 }
527
528                 Element nodeColor = doc.createElementNS(NS, "color");
529
530                 for (Map.Entry<Layer, ColorInfo> colorInfoEntry : partsColorInfo
531                                 .entrySet()) {
532                         Layer layer = colorInfoEntry.getKey();
533                         ColorInfo colorInfo = colorInfoEntry.getValue();
534
535                         Element nodeLayer = doc
536                                         .createElementNS(NS, "layer");
537                         nodeLayer.setAttribute("refid", layer.getId());
538                         nodeColor.appendChild(nodeLayer);
539
540                         // ColorGroup
541                         ColorGroup colorGroup = colorInfo.getColorGroup();
542                         boolean colorSync = colorInfo.isSyncColorGroup();
543
544                         if (colorGroup.isEnabled()) {
545                                 Element nodeColorGroup = doc.createElementNS(
546                                                 NS, "color-group");
547                                 nodeColorGroup.setAttribute("group",
548                                                 colorGroup.getId());
549                                 nodeColorGroup.setAttribute("synchronized",
550                                                 colorSync ? "true" : "false");
551                                 nodeLayer.appendChild(nodeColorGroup);
552                         }
553
554                         // RGB
555                         ColorConvertParameter param = colorInfo
556                                         .getColorParameter();
557
558                         Element nodeRGB = doc.createElementNS(NS, "rgb");
559                         Object[][] rgbArgss = {
560                                         {"red", param.getOffsetR(),
561                                                         param.getFactorR(),
562                                                         param.getGammaR()},
563                                         {"green", param.getOffsetG(),
564                                                         param.getFactorG(),
565                                                         param.getGammaG()},
566                                         {"blue", param.getOffsetB(),
567                                                         param.getFactorB(),
568                                                         param.getGammaB()},
569                                         {"alpha", param.getOffsetA(),
570                                                         param.getFactorA(),
571                                                         param.getGammaA()},};
572                         for (Object[] rgbArgs : rgbArgss) {
573                                 Element nodeRGBItem = doc.createElementNS(NS,
574                                                 rgbArgs[0].toString());
575                                 nodeRGBItem.setAttribute("offset",
576                                                 rgbArgs[1].toString());
577                                 nodeRGBItem.setAttribute("factor",
578                                                 rgbArgs[2].toString());
579                                 nodeRGBItem.setAttribute("gamma",
580                                                 rgbArgs[3].toString());
581                                 nodeRGB.appendChild(nodeRGBItem);
582                         }
583                         nodeLayer.appendChild(nodeRGB);
584
585                         // HSB
586                         Element nodeHSB = doc.createElementNS(NS, "hsb");
587                         nodeHSB.setAttribute("hue",
588                                         Float.toString(param.getHue()));
589                         nodeHSB.setAttribute("saturation",
590                                         Float.toString(param.getSaturation()));
591                         nodeHSB.setAttribute("brightness",
592                                         Float.toString(param.getBrightness()));
593                         if (param.getContrast() != 0.f) {
594                                 // ver0.96追加、optional
595                                 // ぴったり0.0fだったら省略する.
596                                 nodeHSB.setAttribute("contrast",
597                                                 Float.toString(param.getContrast()));
598                         }
599                         nodeLayer.appendChild(nodeHSB);
600
601                         // RGB Replace
602                         Element nodeRGBReplace = doc.createElementNS(NS,
603                                         "rgb-replace");
604                         ColorConv colorConv = param.getColorReplace();
605                         if (colorConv == null) {
606                                 colorConv = ColorConv.NONE;
607                         }
608                         nodeRGBReplace.setAttribute("replace-type",
609                                         colorConv.name());
610                         nodeRGBReplace.setAttribute("gray",
611                                         Float.toString(param.getGrayLevel()));
612                         nodeLayer.appendChild(nodeRGBReplace);
613                 }
614
615                 return nodeColor;
616         }
617
618         public void saveFavorites(CharacterData characterData,
619                         OutputStream outstm) throws IOException {
620                 if (characterData == null || outstm == null) {
621                         throw new IllegalArgumentException();
622                 }
623
624                 Document doc;
625                 try {
626                         DocumentBuilderFactory factory = DocumentBuilderFactory
627                                         .newInstance();
628                         factory.setNamespaceAware(true);
629                         DocumentBuilder builder = factory.newDocumentBuilder();
630                         doc = builder.newDocument();
631
632                 } catch (ParserConfigurationException ex) {
633                         throw new RuntimeException("JAXP Configuration Exception.", ex);
634                 }
635
636                 Element root = doc.createElementNS(NS, "partssets");
637
638                 root.setAttribute("xmlns:xml", XMLConstants.XML_NS_URI);
639                 root.setAttribute("xmlns:xsi",
640                                 "http://www.w3.org/2001/XMLSchema-instance");
641                 root.setAttribute("xsi:schemaLocation", NS + " partsset.xsd");
642                 doc.appendChild(root);
643
644                 // presetsのelementを構築する.(Presetは除く)
645                 writePartsSetElements(doc, root, characterData, false, true);
646
647                 // output xml
648                 TransformerFactory txFactory = TransformerFactory.newInstance();
649                 txFactory.setAttribute("indent-number", Integer.valueOf(4));
650                 Transformer tfmr;
651                 try {
652                         tfmr = txFactory.newTransformer();
653                 } catch (TransformerConfigurationException ex) {
654                         throw new RuntimeException("JAXP Configuration Failed.", ex);
655                 }
656                 tfmr.setOutputProperty(OutputKeys.INDENT, "yes");
657
658                 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4504745
659                 final String encoding = "UTF-8";
660                 tfmr.setOutputProperty("encoding", encoding);
661                 try {
662                         tfmr.transform(new DOMSource(doc), new StreamResult(
663                                         new OutputStreamWriter(outstm, Charset.forName(encoding))));
664
665                 } catch (TransformerException ex) {
666                         IOException ex2 = new IOException("XML Convert failed.");
667                         ex2.initCause(ex);
668                         throw ex2;
669                 }
670         }
671 }