OSDN Git Service

mavenによるビルドに変更
[charactermanaj/CharacterManaJ.git] / src / main / java / charactermanaj / graphics / ImageBuilder.java
1 package charactermanaj.graphics;\r
2 \r
3 import java.awt.Color;\r
4 import java.awt.Dimension;\r
5 import java.awt.Graphics2D;\r
6 import java.awt.Rectangle;\r
7 import java.awt.RenderingHints;\r
8 import java.awt.geom.AffineTransform;\r
9 import java.awt.image.AffineTransformOp;\r
10 import java.awt.image.BufferedImage;\r
11 import java.io.IOException;\r
12 import java.util.ArrayList;\r
13 import java.util.Arrays;\r
14 import java.util.Collections;\r
15 import java.util.List;\r
16 import java.util.concurrent.Semaphore;\r
17 import java.util.concurrent.TimeUnit;\r
18 \r
19 import charactermanaj.graphics.colormodel.ColorModel;\r
20 import charactermanaj.graphics.colormodel.ColorModels;\r
21 import charactermanaj.graphics.filters.ColorConvertParameter;\r
22 import charactermanaj.graphics.io.ImageResource;\r
23 import charactermanaj.graphics.io.LoadedImage;\r
24 import charactermanaj.model.AppConfig;\r
25 import charactermanaj.model.Layer;\r
26 \r
27 /**\r
28  * 各パーツの各レイヤーごとの画像を色変換したのちレイヤーの順序に従い重ね合わせ合成する。\r
29  * \r
30  * @author seraphy\r
31  */\r
32 public class ImageBuilder {\r
33 \r
34         /**\r
35          * 各パーツ情報の読み取りタイムアウト\r
36          */\r
37         private static final int MAX_TIMEOUT = 20; // Secs\r
38 \r
39         /**\r
40          * 各パーツ情報を設定するためのインターフェイス.<br>\r
41          * パーツ登録が完了したら、{@link #setComplite()}を呼び出す必要がある.<br>\r
42          * \r
43          * @author seraphy\r
44          * \r
45          */\r
46         public interface ImageSourceCollector {\r
47                 \r
48                 /**\r
49                  * 画像サイズを設定する.<br>\r
50                  * \r
51                  * @param size\r
52                  *            サイズ\r
53                  */\r
54                 void setSize(Dimension size);\r
55                 \r
56                 /**\r
57                  * 画像の背景色を設定する.<br>\r
58                  * 画像生成処理そのものは背景色を使用しないが、画像の生成完了と同じタイミングで背景色を変えるために ホルダーとして用いることを想定している.<br>\r
59                  * \r
60                  * @param color\r
61                  */\r
62                 void setImageBgColor(Color color);\r
63                 \r
64                 /**\r
65                  * アフィン変換処理のためのパラメータを指定する.<br>\r
66                  * 配列サイズは4または6でなければならない.<br>\r
67                  * \r
68                  * @param param\r
69                  *            パラメータ、変換しない場合はnull\r
70                  */\r
71                 void setAffineTramsform(double[] param);\r
72 \r
73                 /**\r
74                  * 各パーツを登録する.<br>\r
75                  * 複数パーツある場合は、これを繰り返し呼び出す.<br>\r
76                  * すべて呼び出したらsetCompliteを呼び出す.<br>\r
77                  * \r
78                  * @param layer\r
79                  *            レイヤー\r
80                  * @param imageResource\r
81                  *            イメージソース\r
82                  * @param param\r
83                  *            色変換情報\r
84                  */\r
85                 void setImageSource(Layer layer, ImageResource imageResource, ColorConvertParameter param);\r
86 \r
87                 /**\r
88                  * パーツの登録が完了したことを通知する。\r
89                  */\r
90                 void setComplite();\r
91         }\r
92 \r
93         /**\r
94          * 合成が完了した画像を通知するインターフェイス\r
95          * \r
96          * @author seraphy\r
97          */\r
98         public interface ImageOutput {\r
99                 \r
100                 /**\r
101                  * 画像の背景色を取得する.\r
102                  * \r
103                  * @return 背景色\r
104                  */\r
105                 Color getImageBgColor();\r
106                 \r
107                 /**\r
108                  *  画像を取得する.\r
109                  * \r
110                  * @return 画像\r
111                  */\r
112                 BufferedImage getImageOutput();\r
113                 \r
114         }\r
115 \r
116         /**\r
117          * イメージを構築するためのジョブ定義.<br>\r
118          * イメージを構築するためのパーツを登録するハンドラと、合成されたイメージを取り出すハンドラ、および エラーハンドラからなる.<br>\r
119          * \r
120          * @author seraphy\r
121          */\r
122         public interface ImageBuildJob {\r
123 \r
124                 /**\r
125                  * 合成する、各パーツを登録するためのハンドラ.<br>\r
126                  * \r
127                  * @param collector\r
128                  *            登録するためのインターフェイス\r
129                  */\r
130                 void loadParts(ImageSourceCollector collector) throws IOException;\r
131                 \r
132                 /**\r
133                  * 合成されたイメージを取得するハンドラ\r
134                  * \r
135                  * @param output\r
136                  *            イメージを取得するためのインターフェイス\r
137                  */\r
138                 void buildImage(ImageOutput output);\r
139 \r
140                 /**\r
141                  * 例外ハンドラ\r
142                  * \r
143                  * @param ex\r
144                  *            例外\r
145                  */\r
146                 void handleException(Throwable ex);\r
147         }\r
148         \r
149         /**\r
150          * イメージ構築に使用したパーツ情報\r
151          * \r
152          * @author seraphy\r
153          */\r
154         private static final class BuildedPartsInfo {\r
155                 \r
156                 private final ImageBuildPartsInfo partsInfo;\r
157                 \r
158                 private final long lastModified;\r
159                 \r
160                 public BuildedPartsInfo(ImageBuildPartsInfo partsInfo, LoadedImage loadedImage) {\r
161                         this.partsInfo = partsInfo;\r
162                         this.lastModified = loadedImage.getLastModified();\r
163                 }\r
164                 \r
165                 public ImageBuildPartsInfo getPartsInfo() {\r
166                         return partsInfo;\r
167                 }\r
168                 \r
169                 public long getLastModified() {\r
170                         return lastModified;\r
171                 }\r
172         }\r
173         \r
174         /**\r
175          * イメージ構築用情報.<br>\r
176          * イメージ構築結果も格納される.<br>\r
177          * \r
178          * @author seraphy\r
179          */\r
180         private static final class ImageBuildInfo {\r
181                 \r
182                 private ArrayList<ImageBuildPartsInfo> partsInfos = new ArrayList<ImageBuildPartsInfo>();\r
183                 \r
184                 private ArrayList<BuildedPartsInfo> buildPartsInfos = new ArrayList<BuildedPartsInfo>(); \r
185                 \r
186                 private BufferedImage canvas;\r
187 \r
188                 private Rectangle rct = new Rectangle(0, 0, 0, 0);\r
189                 \r
190                 private Color imageBgColor;\r
191                 \r
192                 private double[] affineParamHolder;\r
193                 \r
194                 private boolean sorted;\r
195                 \r
196                 @Override\r
197                 public int hashCode() {\r
198                         return partsInfos.hashCode();\r
199                 }\r
200                 \r
201                 @Override\r
202                 public boolean equals(Object obj) {\r
203                         if (obj != null && obj instanceof ImageBuildInfo) {\r
204                                 ImageBuildInfo other = (ImageBuildInfo) obj;\r
205                                 \r
206                                 if (!getPartsInfos().equals(other.getPartsInfos())) {\r
207                                         // パーツ情報を重ね順をあわせて比較している.\r
208                                         return false;\r
209                                 }\r
210                                 if (!rct.equals(other.rct)) {\r
211                                         return false;\r
212                                 }\r
213                                 if (!(imageBgColor == null ? other.imageBgColor == null\r
214                                                 : imageBgColor.equals(other.imageBgColor))) {\r
215                                         return false;\r
216                                 }\r
217                                 if (!(affineParamHolder == null ? other.affineParamHolder == null\r
218                                                 : Arrays.equals(affineParamHolder, other.affineParamHolder))) {\r
219                                         return false;\r
220                                 }\r
221                                 return true;\r
222                         }\r
223                         return false;\r
224                 }\r
225                 \r
226                 /**\r
227                  * このイメージ構築情報と、すでに構築したイメージ情報を比較し、 同一であるか判定する.<br>\r
228                  * 引数に指定したイメージ構築情報が、まだ構築されていない場合は常にfalseとなる.<br>\r
229                  * イメージリソースが更新されていれば同一構成であってもfalseとなる.<br>\r
230                  * \r
231                  * @param usedInfo\r
232                  *            すでに構築済みのイメージ情報(結果が入っているもの)\r
233                  * @return 同一であればtrue、そうでなければfalse\r
234                  */\r
235                 public boolean isAlreadyLoaded(ImageBuildInfo usedInfo) {\r
236                         if (usedInfo == null || usedInfo.getCanvas() == null) {\r
237                                 return false;\r
238                         }\r
239                         if ( !usedInfo.equals(this)) {\r
240                                 // 構成が違うのでfalse\r
241                                 return false;\r
242                         }\r
243 \r
244                         // 要求されているパーツ情報と、読み込み済みのパーツ情報が同一であるか判定する.\r
245                         int mx = partsInfos.size();\r
246                         int mxUsed = usedInfo.buildPartsInfos.size();\r
247                         if (mx != mxUsed) {\r
248                                 return false; // 念のため\r
249                         }\r
250                         for (int idx = 0; idx < mx; idx++) {\r
251                                 ImageBuildPartsInfo partsInfo = partsInfos.get(idx);\r
252                                 BuildedPartsInfo buildedPartsInfo = usedInfo.buildPartsInfos.get(idx);\r
253                                 if ( !partsInfo.equals(buildedPartsInfo.getPartsInfo())) {\r
254                                         // パーツ構成が一致しない.(念のため)\r
255                                         return false;\r
256                                 }\r
257                                 long lastModified = partsInfo.getFile().lastModified();\r
258                                 if (lastModified != buildedPartsInfo.getLastModified()) {\r
259                                         // 画像ファイルが更新されている.\r
260                                         return false;\r
261                                 }\r
262                         }\r
263                         \r
264                         return true;\r
265                 }\r
266                 \r
267                 /**\r
268                  * イメージ構築に使用したパーツ情報を記録する.\r
269                  * \r
270                  * @param partsInfo\r
271                  *            パーツ情報\r
272                  * @param loadedImage\r
273                  *            イメージ\r
274                  */\r
275                 public void addUsedPartsInfo(ImageBuildPartsInfo partsInfo, LoadedImage loadedImage) {\r
276                         buildPartsInfos.add(new BuildedPartsInfo(partsInfo, loadedImage));\r
277                 }\r
278                 \r
279                 /**\r
280                  * イメージ構築結果を取得する.\r
281                  * \r
282                  * @return イメージ構築結果\r
283                  */\r
284                 public BufferedImage getCanvas() {\r
285                         return canvas;\r
286                 }\r
287                 \r
288                 /**\r
289                  * イメージ構築結果を格納する.\r
290                  * \r
291                  * @param canvas\r
292                  *            イメージ構築結果\r
293                  */\r
294                 public void setCanvas(BufferedImage canvas) {\r
295                         this.canvas = canvas;\r
296                 }\r
297                 \r
298                 public double[] getAffineParamHolder() {\r
299                         return affineParamHolder;\r
300                 }\r
301                 \r
302                 public void setAffineParamHolder(double[] affineParamHolder) {\r
303                         this.affineParamHolder = affineParamHolder;\r
304                 }\r
305                 \r
306                 public Color getImageBgColor() {\r
307                         return imageBgColor;\r
308                 }\r
309                 \r
310                 public void setImageBgColor(Color imageBgColor) {\r
311                         this.imageBgColor = imageBgColor;\r
312                 }\r
313                 \r
314                 public Rectangle getRct() {\r
315                         return rct;\r
316                 }\r
317                 \r
318                 public void setRect(int w, int h) {\r
319                         rct.width = w;\r
320                         rct.height = h;\r
321                 }\r
322                 \r
323                 /**\r
324                  * パーツのリストを取得する.<Br>\r
325                  * 取得された時点で、パーツ情報は重ね合わせ順にソートされている.<br>\r
326                  * リストは変更不可です.<br>\r
327                  * \r
328                  * @return パーツ情報のリスト\r
329                  */\r
330                 public List<ImageBuildPartsInfo> getPartsInfos() {\r
331                         if ( !sorted) {\r
332                                 Collections.sort(partsInfos);\r
333                                 sorted = true;\r
334                         }\r
335                         return Collections.unmodifiableList(partsInfos);\r
336                 }\r
337                 \r
338                 public void add(ImageBuildPartsInfo imageBuildPartsInfo) {\r
339                         sorted = false;\r
340                         partsInfos.add(imageBuildPartsInfo);\r
341                 }\r
342                 \r
343                 public int getPartsCount() {\r
344                         return partsInfos.size();\r
345                 }\r
346         }\r
347         \r
348 \r
349         /**\r
350          * イメージのローダー\r
351          */\r
352         private ColorConvertedImageCachedLoader imageLoader;\r
353         \r
354         /**\r
355          * 最後に使用したイメージビルド情報.(初回ならばnull)\r
356          */\r
357         private ImageBuildInfo lastUsedImageBuildInfo;\r
358         \r
359         /**\r
360          * イメージのローダーを指定して構築します.<br>\r
361          * \r
362          * @param imageLoader\r
363          *            イメージローダー\r
364          */\r
365         public ImageBuilder(ColorConvertedImageCachedLoader imageLoader) {\r
366                 if (imageLoader == null) {\r
367                         throw new IllegalArgumentException();\r
368                 }\r
369                 this.imageLoader = imageLoader;\r
370         }\r
371 \r
372         \r
373         /**\r
374          * イメージビルドジョブより、構築すべきイメージの情報を取得する.\r
375          * \r
376          * @param imageBuildJob\r
377          *            イメージビルドジョブ\r
378          * @return 取得されたイメージ構築情報\r
379          * @throws IOException\r
380          *             失敗\r
381          * @throws InterruptedException\r
382          *             割り込み\r
383          */\r
384         protected ImageBuildInfo getPartsInfo(ImageBuildJob imageBuildJob) throws IOException, InterruptedException {\r
385                 final ImageBuildInfo imageBuildInfo = new ImageBuildInfo();\r
386                 final Semaphore compliteLock = new Semaphore(0);\r
387                 // ジョブリクエスト側に合成するイメージの情報を引き渡すように要求する.\r
388                 // loadPartsが非同期に行われる場合、すぐに制御を戻す.\r
389                 imageBuildJob.loadParts(new ImageSourceCollector() {\r
390                         // ジョブリクエスト側よりイメージサイズの設定として呼び出される\r
391                         public void setSize(Dimension size) {\r
392                                 synchronized (imageBuildInfo) {\r
393                                         imageBuildInfo.setRect(size.width, size.height);\r
394                                 }\r
395                         }\r
396                         public void setImageBgColor(Color color) {\r
397                                 synchronized (imageBuildInfo) {\r
398                                         imageBuildInfo.setImageBgColor(color);\r
399                                 }\r
400                         }\r
401                         public void setAffineTramsform(double[] param) {\r
402                                 if (param != null && !(param.length == 4 || param.length == 6)) {\r
403                                         throw new IllegalArgumentException("affineTransformParameter invalid length.");\r
404                                 }\r
405                                 synchronized (imageBuildInfo) {\r
406                                         imageBuildInfo.setAffineParamHolder(param);\r
407                                 }\r
408                         }\r
409                         // ジョブリクエスト側よりパーツの登録として呼び出される\r
410                         public void setImageSource(Layer layer, ImageResource imageResource, ColorConvertParameter param) {\r
411                                 synchronized (imageBuildInfo) {\r
412                                         imageBuildInfo.add(new ImageBuildPartsInfo(\r
413                                                         imageBuildInfo.getPartsCount(), layer, imageResource, param));\r
414                                 }\r
415                         }\r
416                         // ジョブリクエスト側よりイメージサイズとパーツの登録が完了したことを通知される.\r
417                         public void setComplite() {\r
418                                 compliteLock.release();\r
419                         }\r
420                 });\r
421 \r
422                 // ImageCollectorは非同期に呼び出されても良いことを想定している.\r
423                 // MAX_TIMEOUTを経過してもsetCompliteが呼び出されない場合、処理を放棄する.\r
424                 if (!compliteLock.tryAcquire(MAX_TIMEOUT, TimeUnit.SECONDS)) {\r
425                         throw new RuntimeException("ImageCollector Timeout.");\r
426                 }\r
427                 return imageBuildInfo;\r
428         }\r
429         \r
430         /**\r
431          * イメージビルド情報をもとにイメージを構築して返す.\r
432          * \r
433          * @param imageBuildInfo\r
434          *            イメージビルド情報と、その結果\r
435          * @throws IOException\r
436          *             失敗\r
437          */\r
438         protected void buildImage(ImageBuildInfo imageBuildInfo) throws IOException {\r
439 \r
440                 // 出力画像のカンバスを作成\r
441                 int w = imageBuildInfo.getRct().width;\r
442                 int h = imageBuildInfo.getRct().height;\r
443 \r
444                 final BufferedImage canvas = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);\r
445                 Graphics2D g = (Graphics2D) canvas.getGraphics();\r
446                 try {\r
447                         // レンダリングヒント\r
448                         AppConfig appConfig = AppConfig.getInstance();\r
449                         if (appConfig.isEnableRenderingHints()) {\r
450                                 g.setRenderingHint(\r
451                                                 RenderingHints.KEY_ALPHA_INTERPOLATION,\r
452                                                 RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);\r
453                                 g.setRenderingHint(\r
454                                                 RenderingHints.KEY_COLOR_RENDERING,\r
455                                                 RenderingHints.VALUE_COLOR_RENDER_QUALITY);\r
456                                 g.setRenderingHint(\r
457                                                 RenderingHints.KEY_RENDERING,\r
458                                                 RenderingHints.VALUE_RENDER_QUALITY);\r
459                         }\r
460 \r
461                         // 各パーツを重ね合わせ順にカンバスに描画する\r
462                         imageLoader.unlockImages();\r
463                         for (ImageBuildPartsInfo partsInfo : imageBuildInfo.getPartsInfos()) {\r
464                                 ImageResource imageFile = partsInfo.getFile();\r
465                                 ColorConvertParameter colorConvParam = partsInfo.getColorParam();\r
466                                 // カラーモデル\r
467                                 Layer layer = partsInfo.getLayer();\r
468                                 String colorModelName = layer.getColorModelName();\r
469                                 ColorModel colorModel = ColorModels.safeValueOf(colorModelName);\r
470 \r
471                                 LoadedImage loadedImage = imageLoader.load(imageFile,\r
472                                                 colorConvParam, colorModel);\r
473 \r
474                                 // イメージ構築に使用した各パーツの結果を格納する.\r
475                                 imageBuildInfo.addUsedPartsInfo(partsInfo, loadedImage);\r
476 \r
477                                 // イメージをキャンバスに重ねる.\r
478                                 BufferedImage img = loadedImage.getImage();\r
479                                 g.drawImage(img, 0, 0, w, h, 0, 0, w, h, null);\r
480                         }\r
481                 \r
482                 } finally {\r
483                         g.dispose();\r
484                 }\r
485         \r
486                 // アフィン処理を行う.(パラメータが指定されていれば)\r
487                 final BufferedImage affineTransformedCanvas;\r
488                 double[] affineTransformParameter = imageBuildInfo.getAffineParamHolder();\r
489                 if (affineTransformParameter == null || affineTransformParameter.length != 6) {\r
490                         affineTransformedCanvas = canvas;\r
491 \r
492                 } else {\r
493                         AffineTransform affineTransform = new AffineTransform(affineTransformParameter);\r
494                         AffineTransformOp affineTransformOp = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);\r
495                         affineTransformedCanvas = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);\r
496                         affineTransformOp.filter(canvas, affineTransformedCanvas);\r
497                 }\r
498 \r
499                 // 最終的にできあがったキャンバスを結果として格納する.\r
500                 imageBuildInfo.setCanvas(affineTransformedCanvas);\r
501         }\r
502         \r
503         /**\r
504          * イメージ構築ジョブを要求します.<br>\r
505          * 戻り値がtrueである場合は、ただちに完了したことを示します.<br>\r
506          * \r
507          * @param imageBuildJob\r
508          *            イメージを構築するジョブ\r
509          * @return 画像がただちに得られた場合はtrue、そうでなければfalse\r
510          */\r
511         public boolean requestJob(final ImageBuildJob imageBuildJob) {\r
512                 if (imageBuildJob == null) {\r
513                         throw new IllegalArgumentException();\r
514                 }\r
515                 \r
516                 // 合成する画像パーツの取得処理\r
517                 final ImageBuildInfo imageBuildInfo;\r
518                 try {\r
519                         imageBuildInfo = getPartsInfo(imageBuildJob);\r
520 \r
521                 } catch (Throwable ex) {\r
522                         // 予期せぬ例外の通知\r
523                         imageBuildJob.handleException(ex);\r
524                         return false;\r
525                 }\r
526                 \r
527                 try {\r
528                         synchronized (imageBuildInfo) {\r
529 \r
530                                 final BufferedImage canvas;\r
531                                 \r
532                                 // 前回構築したパーツと同じであれば再構築せず、以前のものを使う\r
533                                 if (imageBuildInfo.isAlreadyLoaded(lastUsedImageBuildInfo)) {\r
534                                         canvas = lastUsedImageBuildInfo.getCanvas();\r
535 \r
536                                 } else {\r
537                                         // パーツの合成処理\r
538                                         buildImage(imageBuildInfo);\r
539                                         canvas = imageBuildInfo.getCanvas();\r
540                                         lastUsedImageBuildInfo = imageBuildInfo;\r
541                                 }\r
542                                 \r
543                                 // 完成したカンバスを合成結果として通知する.\r
544                                 imageBuildJob.buildImage(new ImageOutput() {\r
545                                         public BufferedImage getImageOutput() {\r
546                                                 return canvas;\r
547                                         }\r
548                                         public Color getImageBgColor() {\r
549                                                 return imageBuildInfo.getImageBgColor();\r
550                                         }\r
551                                 });\r
552                         }\r
553 \r
554                 } catch (Throwable ex) {\r
555                         // 予期せぬ例外の通知\r
556                         imageBuildJob.handleException(ex);\r
557                         return false;\r
558                 }\r
559 \r
560                 // 完了\r
561                 return true;\r
562         }\r
563 }\r
564 \r
565 /**\r
566  * 合成する個々のイメージ情報 .<br>\r
567  * レイヤー順に順序づけられており、同一レイヤーであればOrder順に順序づけられます.<br>\r
568  * \r
569  * @author seraphy\r
570  */\r
571 final class ImageBuildPartsInfo implements Comparable<ImageBuildPartsInfo> {\r
572 \r
573         private int order;\r
574         \r
575         private Layer layer;\r
576         \r
577         private ImageResource imageResource;\r
578         \r
579         private ColorConvertParameter colorParam;\r
580 \r
581         public ImageBuildPartsInfo(int order, Layer layer, ImageResource imageResource, ColorConvertParameter colorParam) {\r
582                 this.order = order;\r
583                 this.layer = layer;\r
584                 this.imageResource = imageResource;\r
585                 this.colorParam = colorParam;\r
586         }\r
587         \r
588         @Override\r
589         public int hashCode() {\r
590                 return order ^ layer.hashCode() ^ imageResource.hashCode();\r
591         }\r
592         \r
593         @Override\r
594         public boolean equals(Object obj) {\r
595                 if (obj == this) {\r
596                         return true;\r
597                 }\r
598                 if (obj != null && obj instanceof ImageBuildPartsInfo) {\r
599                         ImageBuildPartsInfo o = (ImageBuildPartsInfo) obj;\r
600                         return order == o.order && layer.equals(o.layer)\r
601                                         && imageResource.equals(o.imageResource) && colorParam.equals(o.colorParam);\r
602                 }\r
603                 return false;\r
604         }\r
605         \r
606         public int compareTo(ImageBuildPartsInfo o) {\r
607                 // レイヤー順\r
608                 int ret = layer.compareTo(o.layer);\r
609                 if (ret == 0) {\r
610                         // 同一レイヤーであれば定義順\r
611                         ret = order - o.order;\r
612                 }\r
613                 if (ret == 0) {\r
614                         // それでも同じであればイメージソースの固有の順序\r
615                         ret = imageResource.compareTo(o.imageResource);\r
616                 }\r
617                 return ret;\r
618         }\r
619 \r
620         public int getOrder() {\r
621                 return order;\r
622         }\r
623         \r
624         public Layer getLayer() {\r
625                 return layer;\r
626         }\r
627         \r
628         public ColorConvertParameter getColorParam() {\r
629                 return colorParam;\r
630         }\r
631         \r
632         public ImageResource getFile() {\r
633                 return imageResource;\r
634         }\r
635 }\r