diff --git a/com.wudsn.ide.gfx/.classpath b/com.wudsn.ide.gfx/.classpath new file mode 100644 index 00000000..688cd937 --- /dev/null +++ b/com.wudsn.ide.gfx/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/com.wudsn.ide.gfx/.project b/com.wudsn.ide.gfx/.project new file mode 100644 index 00000000..58ae691f --- /dev/null +++ b/com.wudsn.ide.gfx/.project @@ -0,0 +1,28 @@ + + + com.wudsn.ide.gfx + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/com.wudsn.ide.gfx/.settings/org.eclipse.jdt.core.prefs b/com.wudsn.ide.gfx/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..f287d53c --- /dev/null +++ b/com.wudsn.ide.gfx/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/com.wudsn.ide.gfx/META-INF/MANIFEST.MF b/com.wudsn.ide.gfx/META-INF/MANIFEST.MF new file mode 100644 index 00000000..8f5a93a3 --- /dev/null +++ b/com.wudsn.ide.gfx/META-INF/MANIFEST.MF @@ -0,0 +1,20 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: WUDSN IDE Graphics Plug-in +Bundle-SymbolicName: com.wudsn.ide.gfx;singleton:=true +Bundle-Version: 1.7.0.qualifier +Bundle-Activator: com.wudsn.ide.gfx.GraphicsPlugin +Bundle-Vendor: Peter Dell +Require-Bundle: com.wudsn.ide.base, + org.eclipse.core.runtime, + org.eclipse.core.resources, + org.eclipse.ui, + org.eclipse.ui.editors, + org.eclipse.ui.ide, + org.eclipse.ui.console +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Bundle-Localization: plugin +Export-Package: com.wudsn.ide.gfx.editor +Bundle-ClassPath: lib/js.jar, + . diff --git a/com.wudsn.ide.gfx/Scrapbook.jpage b/com.wudsn.ide.gfx/Scrapbook.jpage new file mode 100644 index 00000000..8bb588a4 --- /dev/null +++ b/com.wudsn.ide.gfx/Scrapbook.jpage @@ -0,0 +1 @@ +The method getAtariRGBColor(int) is undefined for the type PaletteTypeUtility com.wudsn.ide.base.common.HexUtility.getLongValueHexString( com.wudsn.ide.gfx.model.PaletteTypeUtility.getAtariRGBColor(0xff)); diff --git a/com.wudsn.ide.gfx/bin/.gitignore b/com.wudsn.ide.gfx/bin/.gitignore new file mode 100644 index 00000000..78ec4cc4 --- /dev/null +++ b/com.wudsn.ide.gfx/bin/.gitignore @@ -0,0 +1,2 @@ +/com +/palettes diff --git a/com.wudsn.ide.gfx/build.properties b/com.wudsn.ide.gfx/build.properties new file mode 100644 index 00000000..3172fd22 --- /dev/null +++ b/com.wudsn.ide.gfx/build.properties @@ -0,0 +1,15 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + plugin.properties,\ + src/,\ + schema/,\ + icons/,\ + build.properties,\ + .project,\ + .classpath,\ + lib/js.jar,\ + plugin_de_DE.properties + diff --git a/com.wudsn.ide.gfx/icons/Thumbs.db b/com.wudsn.ide.gfx/icons/Thumbs.db new file mode 100644 index 00000000..49544ea9 Binary files /dev/null and b/com.wudsn.ide.gfx/icons/Thumbs.db differ diff --git a/com.wudsn.ide.gfx/icons/file-type-charset.gif b/com.wudsn.ide.gfx/icons/file-type-charset.gif new file mode 100644 index 00000000..54fd583b Binary files /dev/null and b/com.wudsn.ide.gfx/icons/file-type-charset.gif differ diff --git a/com.wudsn.ide.gfx/icons/file-type-picture.gif b/com.wudsn.ide.gfx/icons/file-type-picture.gif new file mode 100644 index 00000000..a8955c86 Binary files /dev/null and b/com.wudsn.ide.gfx/icons/file-type-picture.gif differ diff --git a/com.wudsn.ide.gfx/icons/graphics-editor-16x16.gif b/com.wudsn.ide.gfx/icons/graphics-editor-16x16.gif new file mode 100644 index 00000000..f7b9d198 Binary files /dev/null and b/com.wudsn.ide.gfx/icons/graphics-editor-16x16.gif differ diff --git a/com.wudsn.ide.gfx/icons/occ_write.gif b/com.wudsn.ide.gfx/icons/occ_write.gif new file mode 100644 index 00000000..18576d47 Binary files /dev/null and b/com.wudsn.ide.gfx/icons/occ_write.gif differ diff --git a/com.wudsn.ide.gfx/icons/refresh.gif b/com.wudsn.ide.gfx/icons/refresh.gif new file mode 100644 index 00000000..3ca04d06 Binary files /dev/null and b/com.wudsn.ide.gfx/icons/refresh.gif differ diff --git a/com.wudsn.ide.gfx/icons/save_edit.gif b/com.wudsn.ide.gfx/icons/save_edit.gif new file mode 100644 index 00000000..499dd0ca Binary files /dev/null and b/com.wudsn.ide.gfx/icons/save_edit.gif differ diff --git a/com.wudsn.ide.gfx/icons/saveall_edit.gif b/com.wudsn.ide.gfx/icons/saveall_edit.gif new file mode 100644 index 00000000..ef0eab5b Binary files /dev/null and b/com.wudsn.ide.gfx/icons/saveall_edit.gif differ diff --git a/com.wudsn.ide.gfx/icons/search_ref_obj.gif b/com.wudsn.ide.gfx/icons/search_ref_obj.gif new file mode 100644 index 00000000..f8f0ce5a Binary files /dev/null and b/com.wudsn.ide.gfx/icons/search_ref_obj.gif differ diff --git a/com.wudsn.ide.gfx/icons/searchm_obj.gif b/com.wudsn.ide.gfx/icons/searchm_obj.gif new file mode 100644 index 00000000..7b1efa54 Binary files /dev/null and b/com.wudsn.ide.gfx/icons/searchm_obj.gif differ diff --git a/com.wudsn.ide.gfx/icons/smartmode_co.gif b/com.wudsn.ide.gfx/icons/smartmode_co.gif new file mode 100644 index 00000000..542dddca Binary files /dev/null and b/com.wudsn.ide.gfx/icons/smartmode_co.gif differ diff --git a/com.wudsn.ide.gfx/icons/zoom-disabled.gif b/com.wudsn.ide.gfx/icons/zoom-disabled.gif new file mode 100644 index 00000000..d460ddda Binary files /dev/null and b/com.wudsn.ide.gfx/icons/zoom-disabled.gif differ diff --git a/com.wudsn.ide.gfx/icons/zoom.gif b/com.wudsn.ide.gfx/icons/zoom.gif new file mode 100644 index 00000000..d8d7fad3 Binary files /dev/null and b/com.wudsn.ide.gfx/icons/zoom.gif differ diff --git a/com.wudsn.ide.gfx/lib/js-src.zip b/com.wudsn.ide.gfx/lib/js-src.zip new file mode 100644 index 00000000..d4187d59 Binary files /dev/null and b/com.wudsn.ide.gfx/lib/js-src.zip differ diff --git a/com.wudsn.ide.gfx/lib/js.jar b/com.wudsn.ide.gfx/lib/js.jar new file mode 100644 index 00000000..6f0dafbb Binary files /dev/null and b/com.wudsn.ide.gfx/lib/js.jar differ diff --git a/com.wudsn.ide.gfx/plugin.properties b/com.wudsn.ide.gfx/plugin.properties new file mode 100644 index 00000000..f8677508 --- /dev/null +++ b/com.wudsn.ide.gfx/plugin.properties @@ -0,0 +1,60 @@ +#Properties file for com.wudsn.ide.gfx +com.wudsn.ide.gfx.converter.GraphicsFile.name=Graphics File +com.wudsn.ide.gfx.converter.apple2.AppleIIGraphicsFile.name=Apple II Graphics File +com.wudsn.ide.gfx.converter.atari8.Atari8GraphicsFile.name=Atari 8-bit Graphics File +com.wudsn.ide.gfx.converter.c64.C64GraphicsFile.name=C64 Graphics File + +com.wudsn.ide.gfx.editor.GraphicsEditor.name=Graphics Editor +com.wudsn.ide.gfx.editor.GraphicsEditorOpenCommand.name=Open With Graphics Editor +com.wudsn.ide.gfx.editor.GraphicsCategory.name=Graphics +com.wudsn.ide.gfx.editor.ImageView.name=Image +com.wudsn.ide.gfx.editor.ImageViewShrinkToFit.name=Shrink +com.wudsn.ide.gfx.editor.ImageViewZoomToFit.name=Zoom +com.wudsn.ide.gfx.editor.ImagePaletteView.name=Image Palette + +com.wudsn.ide.gfx.model.ConverterMode.RAW=Raw +com.wudsn.ide.gfx.model.ConverterMode.CNV=Conversion + +com.wudsn.ide.gfx.model.ConverterDirection.FILES_TO_IMAGE=Files to Image +com.wudsn.ide.gfx.model.ConverterDirection.IMAGE_TO_FILES=Image to Files + +com.wudsn.ide.gfx.model.Palette.TRUE_COLOR=True Color +com.wudsn.ide.gfx.model.Palette.HIRES_1=Hires (1) +com.wudsn.ide.gfx.model.Palette.HIRES_2=Hires (2) +com.wudsn.ide.gfx.model.Palette.HIRES_MANUAL=Hires (manual) +com.wudsn.ide.gfx.model.Palette.MULTI_1=Multi (1) +com.wudsn.ide.gfx.model.Palette.MULTI_2=Multi (2) +com.wudsn.ide.gfx.model.Palette.MULTI_3=Multi (3) +com.wudsn.ide.gfx.model.Palette.MULTI_4=Multi (4) +com.wudsn.ide.gfx.model.Palette.MULTI_5=Multi (5) +com.wudsn.ide.gfx.model.Palette.MULTI_6=Multi (6) +com.wudsn.ide.gfx.model.Palette.MULTI_MANUAL=Multi (manual) +com.wudsn.ide.gfx.model.Palette.GTIA_GREY_1=GITA grey (1) +com.wudsn.ide.gfx.model.Palette.GTIA_GREY_2=GITA grey (2) +com.wudsn.ide.gfx.model.Palette.GTIA_GREY_MANUAL=GTIA grey (manual) + +com.wudsn.ide.gfx.model.PaletteType.FIXED=Fixed +com.wudsn.ide.gfx.model.PaletteType.TRUE_COLOR=True Color +com.wudsn.ide.gfx.model.PaletteType.ATARI_DEFAULT=ATARI (default) +com.wudsn.ide.gfx.model.PaletteType.ATARI_REAL=ATARI (real) +com.wudsn.ide.gfx.model.PaletteType.ATARI_XFORMER=ATARI (XFormer) +com.wudsn.ide.gfx.model.PaletteType.C64_NORMAL=C64 (normal) +com.wudsn.ide.gfx.model.PaletteType.C64_PAL=C64 (PAL) + +com.wudsn.ide.gfx.converter.XYFactorDefaults.FACTOR_1_1=1 x 1 +com.wudsn.ide.gfx.converter.XYFactorDefaults.FACTOR_2_1=2 x 1 +com.wudsn.ide.gfx.converter.XYFactorDefaults.FACTOR_2_2=2 x 2 +com.wudsn.ide.gfx.converter.XYFactorDefaults.FACTOR_4_2=4 x 2 +com.wudsn.ide.gfx.converter.XYFactorDefaults.FACTOR_4_4=4 x 4 + +com.wudsn.ide.gfx.model.PixelType.HIRES=Hires +com.wudsn.ide.gfx.model.PixelType.MULTI=Multicolor +com.wudsn.ide.gfx.model.PixelType.GTIA_GREY=GTIA (grey) + +com.wudsn.ide.gfx.converter.generic.CharSetConverter.CHAR_SET_FILE=Char Set File +com.wudsn.ide.gfx.converter.generic.CharMapConverter.CHAR_SET_FILE=Char Set File +com.wudsn.ide.gfx.converter.generic.CharMapConverter.CHAR_MAP_FILE=Char Map File +com.wudsn.ide.gfx.converter.generic.BitMapConverter.BIT_MAP_FILE=Bit Map File +com.wudsn.ide.gfx.converter.generic.TiledBitMapConverter.VIDEO_RAM_FILE=Video RAM File +com.wudsn.ide.gfx.converter.generic.TiledBitMapConverter.COLOR_RAM_FILE=Color RAM File +com.wudsn.ide.gfx.converter.c64.SpriteHiresConverter.SPRITE_FILE=Sprite File \ No newline at end of file diff --git a/com.wudsn.ide.gfx/plugin.xml b/com.wudsn.ide.gfx/plugin.xml new file mode 100644 index 00000000..0b2bf510 --- /dev/null +++ b/com.wudsn.ide.gfx/plugin.xml @@ -0,0 +1,567 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/com.wudsn.ide.gfx/plugin_de_DE.properties b/com.wudsn.ide.gfx/plugin_de_DE.properties new file mode 100644 index 00000000..dd5d3d2d --- /dev/null +++ b/com.wudsn.ide.gfx/plugin_de_DE.properties @@ -0,0 +1,60 @@ +#Properties file for com.wudsn.ide.gfx +com.wudsn.ide.gfx.converter.GraphicsFile.name=Grafik-Datei +com.wudsn.ide.gfx.converter.apple2.AppleIIGraphicsFile.name=Apple II Grafik-Datei +com.wudsn.ide.gfx.converter.atari8.Atari8GraphicsFile.name=Atari 8-bit Grafik-Datei +com.wudsn.ide.gfx.converter.c64.C64GraphicsFile.name=C64 Grafik-Datei + +com.wudsn.ide.gfx.editor.GraphicsEditor.name=Grafik Editor +com.wudsn.ide.gfx.editor.GraphicsEditorOpenCommand.name=Öffnen mit Grafik Editor +com.wudsn.ide.gfx.editor.GraphicsCategory.name=Grafik +com.wudsn.ide.gfx.editor.ImageView.name=Bild +com.wudsn.ide.gfx.editor.ImageViewShrinkToFit.name=Verkleinern +com.wudsn.ide.gfx.editor.ImageViewZoomToFit.name=Vergrößern +com.wudsn.ide.gfx.editor.ImagePaletteView.name=Bildpalette + +com.wudsn.ide.gfx.model.ConverterMode.RAW=Rohdaten +com.wudsn.ide.gfx.model.ConverterMode.CNV=Konverterieung + +com.wudsn.ide.gfx.model.ConverterDirection.FILES_TO_IMAGE=Dateien zu Bild +com.wudsn.ide.gfx.model.ConverterDirection.IMAGE_TO_FILES=Bild zu Dateien + +com.wudsn.ide.gfx.model.Palette.TRUE_COLOR=True Color +com.wudsn.ide.gfx.model.Palette.HIRES_1=Hires (1) +com.wudsn.ide.gfx.model.Palette.HIRES_2=Hires (2) +com.wudsn.ide.gfx.model.Palette.HIRES_MANUAL=Hires (manuell) +com.wudsn.ide.gfx.model.Palette.MULTI_1=Multi (1) +com.wudsn.ide.gfx.model.Palette.MULTI_2=Multi (2) +com.wudsn.ide.gfx.model.Palette.MULTI_3=Multi (3) +com.wudsn.ide.gfx.model.Palette.MULTI_4=Multi (4) +com.wudsn.ide.gfx.model.Palette.MULTI_5=Multi (5) +com.wudsn.ide.gfx.model.Palette.MULTI_6=Multi (6) +com.wudsn.ide.gfx.model.Palette.MULTI_MANUAL=Multi (manuell) +com.wudsn.ide.gfx.model.Palette.GTIA_GREY_1=GITA grau (1) +com.wudsn.ide.gfx.model.Palette.GTIA_GREY_2=GITA grau (2) +com.wudsn.ide.gfx.model.Palette.GTIA_GREY_MANUAL=GTIA grau (manuell) + +com.wudsn.ide.gfx.model.PaletteType.FIXED=Fest +com.wudsn.ide.gfx.model.PaletteType.TRUE_COLOR=True Color +com.wudsn.ide.gfx.model.PaletteType.ATARI_DEFAULT=ATARI (standard) +com.wudsn.ide.gfx.model.PaletteType.ATARI_REAL=ATARI (real) +com.wudsn.ide.gfx.model.PaletteType.ATARI_XFORMER=ATARI (XFormer) +com.wudsn.ide.gfx.model.PaletteType.C64_NORMAL=C64 (normal) +com.wudsn.ide.gfx.model.PaletteType.C64_PAL=C64 (PAL) + +com.wudsn.ide.gfx.converter.XYFactorDefaults.FACTOR_1_1=1 x 1 +com.wudsn.ide.gfx.converter.XYFactorDefaults.FACTOR_2_1=2 x 1 +com.wudsn.ide.gfx.converter.XYFactorDefaults.FACTOR_2_2=2 x 2 +com.wudsn.ide.gfx.converter.XYFactorDefaults.FACTOR_4_2=4 x 2 +com.wudsn.ide.gfx.converter.XYFactorDefaults.FACTOR_4_4=4 x 4 + +com.wudsn.ide.gfx.model.PixelType.HIRES=Hires +com.wudsn.ide.gfx.model.PixelType.MULTI=Multicolor +com.wudsn.ide.gfx.model.PixelType.GTIA_GREY=GTIA (grau) + +com.wudsn.ide.gfx.converter.generic.CharSetConverter.CHAR_SET_FILE=Zeichensatz-Datei +com.wudsn.ide.gfx.converter.generic.CharMapConverter.CHAR_SET_FILE=Zeichensatz-Datei +com.wudsn.ide.gfx.converter.generic.CharMapConverter.CHAR_MAP_FILE=Char Map-Datei +com.wudsn.ide.gfx.converter.generic.BitMapConverter.BIT_MAP_FILE=Bit Map-Datei +com.wudsn.ide.gfx.converter.generic.TiledBitMapConverter.VIDEO_RAM_FILE=Video RAM-Datei +com.wudsn.ide.gfx.converter.generic.TiledBitMapConverter.COLOR_RAM_FILE=Color RAM-Datei +com.wudsn.ide.gfx.converter.c64.SpriteHiresConverter.SPRITE_FILE=Sprite-Datei diff --git a/com.wudsn.ide.gfx/schema/com.wudsn.ide.gfx.converters.exsd b/com.wudsn.ide.gfx/schema/com.wudsn.ide.gfx.converters.exsd new file mode 100644 index 00000000..86c5b8c1 --- /dev/null +++ b/com.wudsn.ide.gfx/schema/com.wudsn.ide.gfx.converters.exsd @@ -0,0 +1,183 @@ + + + + + + + + + [Enter description of this extension point.] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The id of the converter. Must be requal to its class name. + + + + + + + + + + The displayed name of the converter. + + + + + + + Possibly empty sequence of file extensions which are recognized by the converter. Entries must be lower case without leading dot. Multiple entries are separated with comma. + + + + + + + Size of the target image palette. Must be 0 for a direct palette or a power of 2 for an indexed palette. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Enter the first release in which this extension point appears.] + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/GraphicsPlugin.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/GraphicsPlugin.java new file mode 100644 index 00000000..8a4ccbe6 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/GraphicsPlugin.java @@ -0,0 +1,124 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx; + +import org.osgi.framework.BundleContext; + +import com.wudsn.ide.base.common.AbstractIDEPlugin; +import com.wudsn.ide.gfx.converter.ConverterConsole; +import com.wudsn.ide.gfx.converter.ConverterRegistry; +import com.wudsn.ide.gfx.converter.ConverterScript; +import com.wudsn.ide.gfx.converter.ImageConverterData; + +/** + * The activator class controls the plug-in life cycle. This plugin uses classes + * from the Mozilla Rhino in the classes {@link ConverterScript} and + * {@link ImageConverterData}. See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/ + * Download_Rhino". + */ +public final class GraphicsPlugin extends AbstractIDEPlugin { + + /** + * The plugin id. + */ + public static final String ID = "com.wudsn.ide.gfx"; + + /** + * Creates a new instance. Must be public for dynamic instantiation. + */ + private static GraphicsPlugin plugin; + + /** + * The converter registry. + */ + private ConverterRegistry converterRegistry; + + /** + * The converter console. + */ + private ConverterConsole converterConsole; + + /** + * The constructor + */ + public GraphicsPlugin() { + converterRegistry = new ConverterRegistry(); + } + + @Override + protected String getPluginId() { + return ID; + } + + /** + * {@inheritDoc} + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + converterRegistry.init(); + converterConsole = new ConverterConsole(); + } + + /** + * {@inheritDoc} + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Gets the shared plugin instance + * + * @return The plug-in, not null. + */ + public static GraphicsPlugin getInstance() { + if (plugin == null) { + throw new IllegalStateException("Plugin not initialized or already stopped"); + } + return plugin; + } + + /** + * Gets the converter registry for this plugin. + * + * @return The converter registry, not null. + */ + public ConverterRegistry getConverterRegistry() { + if (converterRegistry == null) { + throw new IllegalStateException("Field 'converterRegistry' must not be null."); + } + return converterRegistry; + } + + /** + * Gets the converter console for this plugin. + * + * @return The converter console, not null. + */ + public ConverterConsole getConverterConsole() { + return converterConsole; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/Texts.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/Texts.java new file mode 100644 index 00000000..868106c0 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/Texts.java @@ -0,0 +1,110 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx; + +import org.eclipse.osgi.util.NLS; + +import com.wudsn.ide.gfx.editor.GraphicsEditor; + +/** + * Class which holds the localized text constants. + * + * @author Peter Dell + */ +public final class Texts extends NLS { + + public static String FILE_SECTION_FIELD_SIZE_LABEL; + public static String FILE_SECTION_FIELD_SIZE_NO_DATA; + public static String FILE_SECTION_FIELD_OFFSET_LABEL; + + public static String FIND_DEFAULT_FILE_CONVERTER_BUTTON_TOOLTIP; + public static String CREATE_CONVERSION_BUTTON_TOOLTIP; + + public static String FILES_CONVERTER_DATA_VIEW_TAB; + public static String IMAGE_CONVERTER_DATA_VIEW_TAB; + + public static String CONVERTER_PARAMETERS_CONVERTER_ID_LABEL; + public static String REFRESH_BUTTON_TOOLTIP; + public static String SAVE_IMAGE_BUTTON_TOOLTIP; + public static String SAVE_FILES_BUTTON_TOOLTIP; + + public static String CONVERTER_PARAMETERS_BIT_MAP_FILE_PATH_LABEL; + public static String CONVERTER_PARAMETERS_BIT_MAP_FILE_SECTION_LABEL; + public static String CONVERTER_PARAMETERS_CHAR_SET_FILE_PATH_LABEL; + public static String CONVERTER_PARAMETERS_CHAR_SET_FILE_SECTION_LABEL; + public static String CONVERTER_PARAMETERS_CHAR_MAP_FILE_PATH_LABEL; + public static String CONVERTER_PARAMETERS_CHAR_MAP_FILE_SECTION_LABEL; + public static String CONVERTER_PARAMETERS_COLOR_MAP_FILE_PATH_LABEL; + public static String CONVERTER_PARAMETERS_COLOR_MAP_FILE_SECTION_LABEL; + public static String CONVERTER_PARAMETERS_IMAGE_FILE_PATH_LABEL; + + // Files to image texts + public static String CONVERTER_PARAMETERS_COLUMNS_LABEL; + public static String CONVERTER_PARAMETERS_ROWS_LABEL; + + public static String CONVERTER_PARAMETERS_SPACING_COLOR_LABEL; + public static String CONVERTER_PARAMETERS_SPACING_WIDTH_LABEL; + + // Image to Files texts + public static String CONVERTER_PARAMETERS_USE_DEFAULT_SCRIPT_LABEL; + public static String CONVERTER_PARAMETERS_SCRIPT_LABEL; + + public static String CONVERTER_DATA_IMAGE_DATA_WIDTH_LABEL; + public static String CONVERTER_DATA_IMAGE_DATA_HEIGHT_LABEL; + + public static String CONVERTER_PARAMETERS_IMAGE_ASPECT_LABEL; + + public static String CREATE_CONVERSION_DIALOG_TITLE; + public static String CREATE_CONVERSION_DIALOG_MESSAGE; + public static String SAVE_AS_DIALOG_TITLE; + public static String SAVE_AS_DIALOG_MESSAGE; + + public static String CONVERTER_CONSOLE_TITLE; + + public static String IMAGE_VIEW_ASPECT_LABEL; + + public static String IMAGE_PALETTE_VIEW_EDIT_COLOR_ACTION_LABEL; + public static String IMAGE_PALETTE_VIEW_EDIT_COLOR_ACTION_TOOLTIP; + public static String IMAGE_PALETTE_VIEW_UNUSED_COLORS_ACTION_LABEL; + public static String IMAGE_PALETTE_VIEW_UNUSED_COLORS_ACTION_TOOLTIP; + public static String IMAGE_PALETTE_VIEW_INFO_NO_IMAGE; + public static String IMAGE_PALETTE_VIEW_INFO_INDEXED_PALETTE_IMAGE; + public static String IMAGE_PALETTE_VIEW_INFO_DIRECT_PALETTE_IMAGE; + + public static String IMAGE_PALETTE_VIEW_COLUMN_INDEX_TEXT; + public static String IMAGE_PALETTE_VIEW_COLUMN_COLOR_HEX_TEXT; + public static String IMAGE_PALETTE_VIEW_COLUMN_COLOR_BINARY_TEXT; + public static String IMAGE_PALETTE_VIEW_COLUMN_RGB_COLOR_TEXT; + public static String IMAGE_PALETTE_VIEW_COLUMN_COLOR_COUNT_TEXT; + public static String IMAGE_PALETTE_VIEW_COLUMN_COLOR_COUNT_PERCENT_TEXT; + + /** + * Messages for {@link GraphicsEditor}. + */ + public static String MESSAGE_S100 = "Source files loaded and converted in {0} ms"; + public static String MESSAGE_E400; + + /** + * Initializes the constants. + */ + static { + NLS.initializeMessages(Texts.class.getName(), Texts.class); + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/Texts.properties b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/Texts.properties new file mode 100644 index 00000000..58da2f61 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/Texts.properties @@ -0,0 +1,73 @@ +FILE_SECTION_FIELD_SIZE_LABEL=Size +FILE_SECTION_FIELD_SIZE_NO_DATA=No data +FILE_SECTION_FIELD_OFFSET_LABEL=Offset + +FIND_DEFAULT_FILE_CONVERTER_BUTTON_TOOLTIP=Find Converter +CREATE_CONVERSION_BUTTON_TOOLTIP=Create Conversion... + +# Tabs. +FILES_CONVERTER_DATA_VIEW_TAB=Files to Image +IMAGE_CONVERTER_DATA_VIEW_TAB=Image to Files + +# Tab content +CONVERTER_PARAMETERS_CONVERTER_ID_LABEL=Converter +REFRESH_BUTTON_TOOLTIP=Refresh +SAVE_IMAGE_BUTTON_TOOLTIP=Save Image +SAVE_FILES_BUTTON_TOOLTIP=Save Files + +CONVERTER_PARAMETERS_BIT_MAP_FILE_PATH_LABEL=Bit Map +CONVERTER_PARAMETERS_BIT_MAP_FILE_SECTION_LABEL=Bit Map +CONVERTER_PARAMETERS_CHAR_SET_FILE_PATH_LABEL=Char Set +CONVERTER_PARAMETERS_CHAR_SET_FILE_SECTION_LABEL=Char Set +CONVERTER_PARAMETERS_CHAR_MAP_FILE_PATH_LABEL=Char Map +CONVERTER_PARAMETERS_CHAR_MAP_FILE_SECTION_LABEL=Char Map +CONVERTER_PARAMETERS_COLOR_MAP_FILE_PATH_LABEL=Color Map +CONVERTER_PARAMETERS_COLOR_MAP_FILE_SECTION_LABEL=Color Map +CONVERTER_PARAMETERS_IMAGE_FILE_PATH_LABEL=Image + +CONVERTER_PARAMETERS_COLUMNS_LABEL=Columns +CONVERTER_PARAMETERS_ROWS_LABEL=Rows + +CONVERTER_PARAMETERS_SPACING_COLOR_LABEL=Spacing Color +CONVERTER_PARAMETERS_SPACING_WIDTH_LABEL=Spacing Width + +CONVERTER_PARAMETERS_USE_DEFAULT_SCRIPT_LABEL=Use Default Script +CONVERTER_PARAMETERS_SCRIPT_LABEL=Script + +CONVERTER_DATA_IMAGE_DATA_WIDTH_LABEL=Width +CONVERTER_DATA_IMAGE_DATA_HEIGHT_LABEL=Height +CONVERTER_PARAMETERS_IMAGE_ASPECT_LABEL=Aspect + +# Dialogs. + +CREATE_CONVERSION_DIALOG_TITLE=Create Conversion +CREATE_CONVERSION_DIALOG_MESSAGE=Creates a conversion file with the current settings, closes the current editor and opens the file a a new editor + +SAVE_AS_DIALOG_TITLE=Save As +SAVE_AS_DIALOG_MESSAGE=Save the current conversion file to another location + +# Converter Console +CONVERTER_CONSOLE_TITLE=Converter Console + +# Image View. +IMAGE_VIEW_ASPECT_LABEL=Aspect + +# Image Palette View. +IMAGE_PALETTE_VIEW_EDIT_COLOR_ACTION_LABEL=Edit +IMAGE_PALETTE_VIEW_EDIT_COLOR_ACTION_TOOLTIP=Edit the color of the currently selected table entry or select presets +IMAGE_PALETTE_VIEW_UNUSED_COLORS_ACTION_LABEL=Unused +IMAGE_PALETTE_VIEW_UNUSED_COLORS_ACTION_TOOLTIP=Toggle the display of the used colors in the indexed palette +IMAGE_PALETTE_VIEW_INFO_NO_IMAGE=No image +IMAGE_PALETTE_VIEW_INFO_INDEXED_PALETTE_IMAGE={0} bit indexed palette. {1} out of {2} colors used. +IMAGE_PALETTE_VIEW_INFO_DIRECT_PALETTE_IMAGE={0} bit direct palette. {1} colors used. + +IMAGE_PALETTE_VIEW_COLUMN_INDEX_TEXT=Index +IMAGE_PALETTE_VIEW_COLUMN_COLOR_HEX_TEXT=Hex +IMAGE_PALETTE_VIEW_COLUMN_COLOR_BINARY_TEXT=Binary +IMAGE_PALETTE_VIEW_COLUMN_RGB_COLOR_TEXT=Color +IMAGE_PALETTE_VIEW_COLUMN_COLOR_COUNT_TEXT=Count +IMAGE_PALETTE_VIEW_COLUMN_COLOR_COUNT_PERCENT_TEXT=Percent + +# Messages +MESSAGE_E400=Unused +MESSAGE_S100=Source files loaded and converted in {0} ms \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/Texts_de_DE.properties b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/Texts_de_DE.properties new file mode 100644 index 00000000..805482f2 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/Texts_de_DE.properties @@ -0,0 +1,72 @@ +FILE_SECTION_FIELD_SIZE_LABEL=Größe +FILE_SECTION_FIELD_SIZE_NO_DATA=Keine Daten +FILE_SECTION_FIELD_OFFSET_LABEL=Offset + +FIND_DEFAULT_FILE_CONVERTER_BUTTON_TOOLTIP=Finde Konverter +CREATE_CONVERSION_BUTTON_TOOLTIP=Konvertierung anlegen... + +# Tabs. +FILES_CONVERTER_DATA_VIEW_TAB=Datei nach Bild +IMAGE_CONVERTER_DATA_VIEW_TAB=Bild nach Datei + +# Tab content +CONVERTER_PARAMETERS_CONVERTER_ID_LABEL=Konverter +REFRESH_BUTTON_TOOLTIP=Aktualisieren +SAVE_IMAGE_BUTTON_TOOLTIP=Bild speichern +SAVE_FILES_BUTTON_TOOLTIP=Dateien speichern + +CONVERTER_PARAMETERS_BIT_MAP_FILE_PATH_LABEL=Bit Map +CONVERTER_PARAMETERS_BIT_MAP_FILE_SECTION_LABEL=Bit Map +CONVERTER_PARAMETERS_CHAR_SET_FILE_PATH_LABEL=Zeichensatz +CONVERTER_PARAMETERS_CHAR_SET_FILE_SECTION_LABEL=Zeichensatz +CONVERTER_PARAMETERS_CHAR_MAP_FILE_PATH_LABEL=Char Map +CONVERTER_PARAMETERS_CHAR_MAP_FILE_SECTION_LABEL=Char Map +CONVERTER_PARAMETERS_COLOR_MAP_FILE_PATH_LABEL=Color Map +CONVERTER_PARAMETERS_COLOR_MAP_FILE_SECTION_LABEL=Color Map +CONVERTER_PARAMETERS_IMAGE_FILE_PATH_LABEL=Bild + +CONVERTER_PARAMETERS_COLUMNS_LABEL=Spalten +CONVERTER_PARAMETERS_ROWS_LABEL=Zeilen + +CONVERTER_PARAMETERS_SPACING_COLOR_LABEL=Freiraumfarbe +CONVERTER_PARAMETERS_SPACING_WIDTH_LABEL=Freiraumbreite + +CONVERTER_PARAMETERS_USE_DEFAULT_SCRIPT_LABEL=Standard Skript verwenden +CONVERTER_PARAMETERS_SCRIPT_LABEL=Skript + +CONVERTER_DATA_IMAGE_DATA_WIDTH_LABEL=Breite +CONVERTER_DATA_IMAGE_DATA_HEIGHT_LABEL=Höhe +CONVERTER_PARAMETERS_IMAGE_ASPECT_LABEL=Seitenverhältnis + +# Dialogs. + +CREATE_CONVERSION_DIALOG_TITLE=Konvertierung anlegen +CREATE_CONVERSION_DIALOG_MESSAGE=Legt eine Konvertierungs-Datei mit den aktuellen Einstellungen an, schließt den aktuellen Editor und öffnet die neue Datei in einem neuen Editor + +SAVE_AS_DIALOG_TITLE=Speichern unter +SAVE_AS_DIALOG_MESSAGE=Speicher die aktuelle Konvertierungs-Datei an einen anderen Ort + +# Converter Console +CONVERTER_CONSOLE_TITLE=Konverter Konsole + +# Image View. +IMAGE_VIEW_ASPECT_LABEL=Seitenverhältnis + +# Image Palette View. +IMAGE_PALETTE_VIEW_EDIT_COLOR_ACTION_LABEL=Bearbeiten +IMAGE_PALETTE_VIEW_EDIT_COLOR_ACTION_TOOLTIP=Bearbeitet die Farbe des aktuelle ausgewählten Tabelleneintrages oder wählt eine der Voreinstellungen aus +IMAGE_PALETTE_VIEW_UNUSED_COLORS_ACTION_LABEL=Nicht verwendet +IMAGE_PALETTE_VIEW_UNUSED_COLORS_ACTION_TOOLTIP=Schaltet die Anzeige der nicht verwendeten Farben in der Index-Palette um +IMAGE_PALETTE_VIEW_INFO_NO_IMAGE=Kein Bild +IMAGE_PALETTE_VIEW_INFO_INDEXED_PALETTE_IMAGE={0} Bit Index-Palette. {1} von {2} Farben verwendet. +IMAGE_PALETTE_VIEW_INFO_DIRECT_PALETTE_IMAGE={0} Bit Direkt-Palette. {1} Farben verwendent. + +IMAGE_PALETTE_VIEW_COLUMN_INDEX_TEXT=Index +IMAGE_PALETTE_VIEW_COLUMN_COLOR_HEX_TEXT=Hex +IMAGE_PALETTE_VIEW_COLUMN_COLOR_BINARY_TEXT=Binär +IMAGE_PALETTE_VIEW_COLUMN_RGB_COLOR_TEXT=Farbe +IMAGE_PALETTE_VIEW_COLUMN_COLOR_COUNT_TEXT=Anzahl +IMAGE_PALETTE_VIEW_COLUMN_COLOR_COUNT_PERCENT_TEXT=Prozent + +# Messages +MESSAGE_E400=Nicht verwendet \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/Converter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/Converter.java new file mode 100644 index 00000000..0bb40db7 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/Converter.java @@ -0,0 +1,182 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.model.Palette; + +public abstract class Converter { + + private ConverterDefinition definition; + + /** + * Constants for 1 bit pixels. Constants are defined as int to ensure no + * sign extension takes place when anding with byte values. + */ + protected static final int[] mask_1bit = new int[] { 0x80, 0x40, 0x20, + 0x10, 0x08, 0x04, 0x02, 0x01 }; + protected static final int[] shift_1bit = new int[] { 7, 6, 5, 4, 3, 2, 1, + 0 }; + + /** + * Constants for 2 bit pixels.Constants are defined as int to ensure no sign + * extension takes place when anding with byte values. + */ + protected static final int[] mask_2bit = new int[] { 0xc0, 0x30, 0x0c, 0x03 }; + protected static final int[] shift_2bit = new int[] { 6, 4, 2, 0 }; + + /** + * Constants for 4 bit pixels.Constants are defined as int to ensure no sign + * extension takes place when anding with byte values. + */ + protected static final int[] mask_4bit = new int[] { 0xf0, 0x0f }; + protected static final int[] shift_4bit = new int[] { 4, 0 }; + + /** + * Creation is protected. + */ + protected Converter() { + } + + /** + * Sets the definition of the Converter. Called by {@link ConverterRegistry} + * only. + * + * @param definition + * The definition if the Converter, not null. + */ + final void setDefinition(ConverterDefinition definition) { + if (definition == null) { + throw new IllegalArgumentException( + "Parameter 'type' must not be null."); + } + this.definition = definition; + } + + /** + * Gets the definition of the Converter. + * + * @return The definition of the Converter, not null. + */ + public final ConverterDefinition getDefinition() { + if (definition == null) { + throw new IllegalStateException( + "Field 'definition' must not be null."); + } + return definition; + } + + /** + * Determines if the given byte array can be converted to an image by this + * converter. + * + * @param bytes + * The byte array, not empty and not null. + * + * @return true if the given byte array can be converted to an + * image by this converter, false otherwise. + * + * @since 1.6.0 + */ + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return false; + } + + /** + * Converts the byte array content to image size and palette. Implementation + * shall call + * {@link #setImageSizeAndPalette(FilesConverterData, int, int, Palette, RGB[])} + * to set the corresponding values. + * + * @param data + * The file converter data container to be filled, not + * null. + * @param bytes + * The byte array, not empty and not null. + * + * @since 1.6.0 + */ + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + throw new UnsupportedOperationException(); + } + + /** + * Sets the current converter, applies its defaults and then sets the image + * size and palette. + * + * @param data + * The file converter data container to be filled, not + * null. + * @param columns + * The number of columns. + * @param rows + * The number of rows. + * @param palette + * The palette, not null. + * @param paletteColors + * The palette colors or not null if palette is + * {@link Palette#TRUE_COLOR}. + */ + protected final void setImageSizeAndPalette(FilesConverterData data, + int columns, int rows, Palette palette, RGB[] paletteColors) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (palette == null) { + throw new IllegalArgumentException( + "Parameter 'palette' must not be null."); + } + if (paletteColors == null) { + if (!palette.equals(Palette.TRUE_COLOR)) { + throw new IllegalArgumentException( + "Parameter 'paletteColors' must not be null if palette is not TRUE_COLOR."); + } + paletteColors = new RGB[0]; + } + FilesConverterParameters parameters; + parameters = data.getParameters(); + parameters.setConverterId(this.getClass().getName()); + parameters.setDisplayAspect(getDefinition() + .getTargetImageDisplayAspect()); + parameters.setColumns(columns); + parameters.setRows(rows); + parameters.setPalette(palette); + parameters.setPaletteRGBs(paletteColors); + } + + public abstract void convertToImageDataSize(FilesConverterData data); + + /** + * Converts the files to an image. + * + * @param data + * The data, not null. + * @return true if an image was created and can be saved (i.e. + * pixels set), false if not. + */ + public abstract boolean convertToImageData(FilesConverterData data); +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterCommonData.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterCommonData.java new file mode 100644 index 00000000..40cea8d7 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterCommonData.java @@ -0,0 +1,131 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.swt.graphics.ImageData; + +/** + * Base class for {@link FilesConverterData} and {@link ImageConverterData}. + * + * @author Peter Dell + * + */ +public abstract class ConverterCommonData { + + protected final ConverterData converterData; + + private int imageDataWidth; + private int imageDataHeight; + protected ImageData imageData; + private ImageColorHistogram imageColorHistogram; + + ConverterCommonData(ConverterData converterData) { + if (converterData == null) { + throw new IllegalArgumentException( + "Parameter 'converterData' must not be null."); + } + + this.converterData = converterData; + imageData = null; + imageColorHistogram = new ImageColorHistogram(); + } + + public final IPath getFilePathPrefix() { + IPath result; + if (converterData.isValid()) { + result = converterData.getFile().getFullPath() + .removeLastSegments(1); + } else { + result = new Path(""); + + } + return result; + } + + public abstract boolean isCreateConversionEnabled(); + + public abstract boolean isValid(); + + public abstract boolean isRefreshEnabled(); + + protected void clear() { + imageData = null; + imageColorHistogram.clear(); + } + + public final void setImageDataWidth(int width) { + this.imageDataWidth = width; + } + + public final int getImageDataWidth() { + return imageDataWidth; + } + + public final void setImageDataHeight(int height) { + this.imageDataHeight = height; + } + + public final int getImageDataHeight() { + return imageDataHeight; + } + + /** + * Sets the image data. + * + * @param imageData + * The image data, may be null. + */ + final void setImageData(ImageData imageData) { + this.imageData = imageData; + imageColorHistogram = null; + } + + /** + * Gets the image data. + * + * @return The image data or null. + */ + public final ImageData getImageData() { + return imageData; + } + + /** + * Sets the image color histogram. + * + * @param imageColorHistogram + * The image color histogram, may be null. + * + * @since 1.6.0 + */ + final void setImageColorHistogram(ImageColorHistogram imageColorHistogram) { + this.imageColorHistogram = imageColorHistogram; + } + + /** + * Gets the image color histogram. + * + * @return The image color histogram, not null. + */ + public final ImageColorHistogram getImageColorHistogram() { + return imageColorHistogram; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterCommonParameters.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterCommonParameters.java new file mode 100644 index 00000000..c9ff02b9 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterCommonParameters.java @@ -0,0 +1,234 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import com.wudsn.ide.gfx.model.Aspect; +import com.wudsn.ide.gfx.model.GraphicsPropertiesSerializer; + +public abstract class ConverterCommonParameters { + + /** + * Names of the attributes. + * + * @author Peter Dell + * + */ + public static final class Attributes { + + /** + * Creation is private. + */ + private Attributes() { + } + + public static final String CONVERTER_ID = "converterId"; + + public static final String IMAGE_ASPECT = "imageAspect"; + + // Display attributes. + public static final String DISPLAY_ASPECT = "displayAspect"; + public static final String DISPLAY_SHRINK_TO_FIT = "displayShrinkToFit"; + public static final String DISPLAY_ZOOM_TO_FIT = "displayZoomToFit"; + } + + /** + * Defaults of the attributes. + * + * @author Peter Dell + * + */ + private static final class Defaults { + + /** + * Creation is protected. + */ + private Defaults() { + } + + public static final String CONVERTER_ID = ""; + + public static final Aspect IMAGE_ASPECT = new Aspect(1, 1); + public static final Aspect DISPLAY_ASPECT = new Aspect(1, 1); + public static final boolean DISPLAY_SHRINK_TO_FIT = false; + public static final boolean DISPLAY_ZOOM_TO_FIT = true; + } + + /** + * Message ids of the attributes. + * + * @author Peter Dell + * + */ + public static final class MessageIds { + + /** + * Creation is private. + */ + private MessageIds() { + } + + public static final int CONVERTER_ID = 1000; + public static final int IMAGE_ASPECT = 1001; + public static final int DISPLAY_ASPECT = 1002; + } + + protected String converterId; + + private Aspect imageAspect; + private Aspect displayAspect; + private boolean displayShrinkToFit; + private boolean displayZoomToFit; + + ConverterCommonParameters() { + } + + protected void setDefaults() { + converterId = Defaults.CONVERTER_ID; + imageAspect = Defaults.IMAGE_ASPECT; + displayAspect = Defaults.DISPLAY_ASPECT; + displayShrinkToFit = Defaults.DISPLAY_SHRINK_TO_FIT; + displayZoomToFit = Defaults.DISPLAY_ZOOM_TO_FIT; + } + + public abstract void setConverterId(String value); + + + public final String getConverterId() { + return converterId; + } + + public final void setImageAspect(Aspect value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.imageAspect = value; + } + + public final Aspect getImageAspect() { + return imageAspect; + } + + public final void setDisplayAspect(Aspect value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.displayAspect = value; + } + + public final Aspect getDisplayAspect() { + return displayAspect; + } + + public final void setDisplayShrinkToFit(boolean displayShrinkToFit) { + this.displayShrinkToFit = displayShrinkToFit; + } + + public final boolean isDisplayShrinkToFit() { + return displayShrinkToFit; + } + + public final void setDisplayZoomToFit(boolean displayZoomToFit) { + this.displayZoomToFit = displayZoomToFit; + } + + public final boolean isDisplayZoomToFit() { + return displayZoomToFit; + } + + protected void copyTo(ConverterCommonParameters target) { + if (target == null) { + throw new IllegalArgumentException( + "Parameter 'target' must not be null."); + } + + target.setConverterId(converterId); + target.setImageAspect(imageAspect); + target.setDisplayAspect(displayAspect); + target.setDisplayShrinkToFit(displayShrinkToFit); + target.setDisplayZoomToFit(displayZoomToFit); + } + + protected boolean equals(ConverterCommonParameters target) { + if (target == null) { + throw new IllegalArgumentException( + "Parameter 'target' must not be null."); + } + boolean result; + + result = target.getImageAspect().equals(imageAspect); + result = result && target.getDisplayAspect().equals(displayAspect); + result = result && target.isDisplayShrinkToFit() == displayShrinkToFit; + result = result && target.isDisplayZoomToFit() == displayZoomToFit; + return result; + } + + protected void serialize(GraphicsPropertiesSerializer serializer, String key) { + if (serializer == null) { + throw new IllegalArgumentException( + "Parameter 'serializer' must not be null."); + } + if (key == null) { + throw new IllegalArgumentException( + "Parameter 'key' must not be null."); + } + GraphicsPropertiesSerializer ownSerializer; + + ownSerializer = new GraphicsPropertiesSerializer(); + ownSerializer.writeString(Attributes.CONVERTER_ID, converterId); + ownSerializer.writeAspect(Attributes.IMAGE_ASPECT, imageAspect); + ownSerializer.writeAspect(Attributes.DISPLAY_ASPECT, displayAspect); + ownSerializer.writeBoolean(Attributes.DISPLAY_SHRINK_TO_FIT, + displayShrinkToFit); + ownSerializer.writeBoolean(Attributes.DISPLAY_ZOOM_TO_FIT, + displayZoomToFit); + + serializer.writeProperties(key, ownSerializer); + } + + protected void deserialize(GraphicsPropertiesSerializer serializer, + String key) { + if (serializer == null) { + throw new IllegalArgumentException( + "Parameter 'serializer' must not be null."); + } + if (key == null) { + throw new IllegalArgumentException(); + } + + GraphicsPropertiesSerializer ownSerializer; + ownSerializer = new GraphicsPropertiesSerializer(); + serializer.readProperties(key, ownSerializer); + + setConverterId(ownSerializer.readString(Attributes.CONVERTER_ID, + Defaults.CONVERTER_ID)); + + imageAspect = ownSerializer.readXYFactor(Attributes.DISPLAY_ASPECT, + Defaults.IMAGE_ASPECT); + displayAspect = ownSerializer.readXYFactor(Attributes.DISPLAY_ASPECT, + Defaults.DISPLAY_ASPECT); + displayShrinkToFit = ownSerializer.readBoolean( + Attributes.DISPLAY_SHRINK_TO_FIT, + Defaults.DISPLAY_SHRINK_TO_FIT); + displayZoomToFit = ownSerializer.readBoolean( + Attributes.DISPLAY_ZOOM_TO_FIT, Defaults.DISPLAY_ZOOM_TO_FIT); + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterConsole.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterConsole.java new file mode 100644 index 00000000..7a45874f --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterConsole.java @@ -0,0 +1,101 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.io.PrintStream; + +import org.eclipse.ui.console.ConsolePlugin; +import org.eclipse.ui.console.IConsole; +import org.eclipse.ui.console.IConsoleManager; +import org.eclipse.ui.console.IConsoleView; +import org.eclipse.ui.console.MessageConsole; +import org.eclipse.ui.console.MessageConsoleStream; + +import com.wudsn.ide.gfx.Texts; + +/** + * The console to show the user the output from the converter. + * + * @author Peter Dell + */ +public final class ConverterConsole { + + private IConsoleManager consoleManager; + public MessageConsole console; + + private MessageConsoleStream messageStream; + private PrintStream printStream; + + /** + * Create a new console-window. + * + */ + public ConverterConsole() { + consoleManager = ConsolePlugin.getDefault().getConsoleManager(); + console = new MessageConsole(Texts.CONVERTER_CONSOLE_TITLE, null); + consoleManager.addConsoles(new IConsole[] { console }); + + messageStream = console.newMessageStream(); + messageStream.setActivateOnWrite(false); + messageStream.print(""); + printStream = new PrintStream(messageStream); + } + + /** + * Brings this console view instance to front in the console view editor + * part. + * + * @param consoleView + * The console view editor part, not null. + */ + + public void display(IConsoleView consoleView) { + if (consoleView == null) { + throw new IllegalArgumentException( + "Parameter 'consoleView' must not be null."); + } + consoleView.display(console); + + } + + /** + * Add a line to console. + * + * @param message + * The message to print, not null. + */ + public void println(String message) { + if (message == null) { + throw new IllegalArgumentException( + "Parameter 'message' must not be null."); + } + messageStream.println(message); + } + + /** + * Gets a print messageStream to write to this console. + * + * @return The print messageStream, not null. + */ + public PrintStream getPrintStream() { + return printStream; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterData.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterData.java new file mode 100644 index 00000000..8064d094 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterData.java @@ -0,0 +1,161 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IPath; + +import com.wudsn.ide.base.common.IPathUtility; +import com.wudsn.ide.gfx.model.ConverterDirection; +import com.wudsn.ide.gfx.model.ConverterMode; + +public final class ConverterData { + + private static final class Defaults { + + /** + * Creation is private. + */ + private Defaults() { + } + + public static final ConverterMode CONVERTER_MODE = ConverterMode.NONE; + } + + private IFile file; + private IPath filePathPrefix; + + private ConverterMode converterMode; + private ConverterParameters parameters; + private ConverterParameters parametersBackup; + + private FilesConverterData filesConverterData; + private ImageConverterData imageConverterData; + + ConverterData() { + parameters = new ConverterParameters(); + parametersBackup = new ConverterParameters(); + filesConverterData = new FilesConverterData(this); + imageConverterData = new ImageConverterData(this); + clear(); + } + + public void setFile(IFile file) { + this.file = file; + if (file != null) { + filePathPrefix = file.getFullPath().removeLastSegments(1); + } else { + filePathPrefix = IPathUtility.createEmptyPath(); + + } + } + + public IFile getFile() { + return file; + } + + public IPath getFilePathPrefix() { + return filePathPrefix; + } + + public boolean isValid() { + return file != null; + } + + public void setConverterMode(ConverterMode value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.converterMode = value; + } + + public ConverterMode getConverterMode() { + return converterMode; + } + + public boolean isValidFile() { + return isValid() + && (converterMode == ConverterMode.RAW_FILE || converterMode == ConverterMode.CNV); + } + + public boolean isValidImage() { + return isValid() + && (converterMode == ConverterMode.RAW_IMAGE || converterMode == ConverterMode.CNV); + } + + public boolean isValidConversion() { + return isValid() && converterMode == ConverterMode.CNV; + } + + public ConverterDirection getConverterDirection() { + + return parameters.getConverterDirection(); + } + + public ConverterParameters getParameters() { + return parameters; + } + + public ConverterCommonData getConverterCommonData() { + switch (parameters.getConverterDirection()) { + case FILES_TO_IMAGE: + return filesConverterData; + case IMAGE_TO_FILES: + return imageConverterData; + default: + throw new IllegalStateException("Unknown converter direction " + + parameters.getConverterDirection() + "."); + } + } + + public FilesConverterData getFilesConverterData() { + return filesConverterData; + } + + public ImageConverterData getImageConverterData() { + return imageConverterData; + } + + public void clear() { + file = null; + clearContent(); + } + + public void clearContent() { + converterMode = Defaults.CONVERTER_MODE; + parameters.setDefaults(); + filesConverterData.clear(); + imageConverterData.clear(); + + } + + final void copyParametersToBackup() { + parametersBackup.setDefaults(); + parameters.copyTo(parametersBackup); + } + + public boolean isChanged() { + boolean result; + result = !parameters.equals(parametersBackup); + return result; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterDataLogic.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterDataLogic.java new file mode 100644 index 00000000..e3f04abb --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterDataLogic.java @@ -0,0 +1,787 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.base.BasePlugin; +import com.wudsn.ide.base.common.FileUtility; +import com.wudsn.ide.base.common.HexUtility; +import com.wudsn.ide.base.common.IPathUtility; +import com.wudsn.ide.base.common.StringUtility; +import com.wudsn.ide.base.gui.MessageManager; +import com.wudsn.ide.gfx.GraphicsPlugin; +import com.wudsn.ide.gfx.converter.FilesConverterParameters.SourceFile; +import com.wudsn.ide.gfx.converter.ImageConverterParameters.TargetFile; +import com.wudsn.ide.gfx.converter.atari8bit.LinearBitMapGraphics8Converter; +import com.wudsn.ide.gfx.model.ConverterDirection; +import com.wudsn.ide.gfx.model.ConverterMode; + +public final class ConverterDataLogic { + private MessageManager messageManager; + private FilesConverterDataLogic filesConverterDataLogic; + + /** + * Helper class to detect the support image file formats by their extension. + * + * @author Peter Dell + */ + private static final class ImageExtensions { + public static final String CNV = "cnv"; + public static final String BMP = "bmp"; + public static final String ICO = "ico"; + public static final String GIF = "gif"; + public static final String JPG = "jpg"; + public static final String PNG = "png"; + + public static final int UNKNOWN_FORMAT = -1; + + public static int getImageFormat(IPath filePath) { + int result; + + String fileExtension = filePath.getFileExtension(); + if (fileExtension == null) { + result = UNKNOWN_FORMAT; + } else if (fileExtension.equalsIgnoreCase(BMP)) { + result = SWT.IMAGE_BMP; + } else if (fileExtension.equalsIgnoreCase(ICO)) { + result = SWT.IMAGE_ICO; + } else if (fileExtension.equalsIgnoreCase(GIF)) { + result = SWT.IMAGE_GIF; + } else if (fileExtension.equalsIgnoreCase(JPG)) { + result = SWT.IMAGE_JPEG; + } else if (fileExtension.equalsIgnoreCase(PNG)) { + result = SWT.IMAGE_PNG; + } else { + result = UNKNOWN_FORMAT; + } + return result; + } + } + + public ConverterDataLogic(MessageManager messageManager) { + if (messageManager == null) { + throw new IllegalArgumentException("Parameter 'messageManager' must not be null."); + } + this.messageManager = messageManager; + filesConverterDataLogic = new FilesConverterDataLogic(); + } + + public ConverterData createData() { + return new ConverterData(); + } + + public void load(ConverterData data) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + + data.clearContent(); + + IFile file = data.getFile(); + String fileName = file.getFullPath().lastSegment(); + String extension = file.getFileExtension(); + if (extension == null) { + extension = ""; + } else { + extension = extension.toLowerCase(); + } + + if (extension.equals(ImageExtensions.CNV)) { + data.setConverterMode(ConverterMode.CNV); + try { + + data.getParameters().read(file); + + } catch (CoreException ex) { + messageManager.sendMessage(0, ex); + } + loadSources(data, true); + } else { + int imageFormat = ImageExtensions.getImageFormat(file.getFullPath()); + if (imageFormat != ImageExtensions.UNKNOWN_FORMAT) { + data.setConverterMode(ConverterMode.RAW_IMAGE); + data.getParameters().setConverterDirection(ConverterDirection.IMAGE_TO_FILES); + data.getImageConverterData().getParameters().setImageFilePath(fileName); + data.getImageConverterData().getParameters() + .setConverterId(LinearBitMapGraphics8Converter.class.getName()); + loadSources(data, true); + + } else { + data.setConverterMode(ConverterMode.RAW_FILE); + data.getParameters().setConverterDirection(ConverterDirection.FILES_TO_IMAGE); + data.getFilesConverterData().getParameters().setDefaultSourceFilePath(fileName); + data.getFilesConverterData().getParameters().setImageFilePath(fileName + "." + ImageExtensions.PNG); + findDefaultFileConverter(data); + loadSources(data, true); + } + + } + + } + + public void findDefaultFileConverter(ConverterData data) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + FilesConverterData filesConverterData; + filesConverterData = data.getFilesConverterData(); + FilesConverterParameters fileConverterParameters = filesConverterData.getParameters(); + + IPath filePathPrefix = filesConverterData.getFilePathPrefix(); + + SourceFile sourceFile = fileConverterParameters.getSourceFile(0); + IPath filePath = Path.fromPortableString(sourceFile.getPath()); + filePath = IPathUtility.makeAbsolute(filePath, filePathPrefix, false); + byte[] bytes = loadSourceFile(sourceFile.getPathMessageId(), filePath); + + // TODO: If bytes is null or length is 0, an error message should be displayed instead. + if (bytes != null) { + String fileExtension = filePath.getFileExtension(); + if (fileExtension != null) { + fileExtension = fileExtension.toLowerCase(); + } else { + fileExtension = ""; + } + filesConverterDataLogic.findDefaultFileConverter(filesConverterData, bytes, fileExtension); + + } + } + + public boolean loadSources(ConverterData data, boolean copyToBackup) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + boolean success; + + success = true; + switch (data.getConverterDirection()) { + case FILES_TO_IMAGE: + + FilesConverterData filesConverterData; + filesConverterData = data.getFilesConverterData(); + FilesConverterParameters fileConverterParameters = filesConverterData.getParameters(); + + IPath filePathPrefix = filesConverterData.getFilePathPrefix(); + for (int i = 0; i < fileConverterParameters.getSourceFilesSize(); i++) { + SourceFile sourceFile = fileConverterParameters.getSourceFile(i); + IPath filePath = Path.fromPortableString(sourceFile.getPath()); + filePath = IPathUtility.makeAbsolute(filePath, filePathPrefix, false); + byte[] bytes = loadSourceFile(sourceFile.getPathMessageId(), filePath); + filesConverterData.setSourceFileBytes(sourceFile.getId(), bytes); + if (bytes == null) { + success = false; + } + } + + break; + case IMAGE_TO_FILES: + ImageConverterData imageConverterData; + imageConverterData = data.getImageConverterData(); + + filePathPrefix = imageConverterData.getFilePathPrefix(); + IPath filePath = Path.fromPortableString(imageConverterData.getParameters().getImageFilePath()); + filePath = IPathUtility.makeAbsolute(filePath, filePathPrefix, false); + ImageData imageData = loadSourceImage(ImageConverterParameters.MessageIds.IMAGE_FILE_PATH, filePath); + imageConverterData.setImageData(imageData); + if (imageData != null) { + // Remember last loaded state. + success = true; + + } else { + success = false; + } + break; + default: + throw new RuntimeException("Unknown converter direction '" + data.getConverterDirection() + "'."); + + } + + // Remember last loaded state. + if (success && copyToBackup) { + data.copyParametersToBackup(); + } + + return success; + } + + /** + * Applies the converter based default values after the converter has been + * selected. + * + * @param data + * The converter data, not null. + */ + public void applyDefaults(ConverterData data) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + + switch (data.getConverterDirection()) { + case FILES_TO_IMAGE: + filesConverterDataLogic.applyDefaults(data.getFilesConverterData()); + + break; + case IMAGE_TO_FILES: + + break; + default: + throw new RuntimeException("Unknown converter direction '" + data.getConverterDirection() + "'."); + } + } + + public ConverterData createConversion(ConverterData data) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + if (!data.isValid()) { + throw new IllegalStateException("Converter data is not valid."); + } + if (data.getConverterMode() != ConverterMode.RAW_FILE && data.getConverterMode() != ConverterMode.RAW_IMAGE) { + throw new IllegalStateException("Converter data is not in mode RAW_FILE or RAW_IMAGE."); + } + + // Compute new file name. + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + IPath saveAsPath = data.getFile().getFullPath().addFileExtension(ImageExtensions.CNV); + IFile saveAsFile = workspaceRoot.getFile(saveAsPath); + + // Compute new content. + ConverterData newConverterData = new ConverterData(); + newConverterData.setConverterMode(ConverterMode.CNV); + newConverterData.setFile(saveAsFile); + data.getParameters().copyTo(newConverterData.getParameters()); + + return newConverterData; + } + + public IFile saveConversion(ConverterData data, IProgressMonitor monitor) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + + IFile saveFile; + String saveFilePath; + saveFile = data.getFile(); + saveFilePath = saveFile.getFullPath().toString(); + + try { + InputStream inputStream; + inputStream = data.getParameters().getContents(saveFilePath); + if (saveFile.exists()) { + saveFile.setContents(inputStream, false, false, monitor); + } else { + saveFile.create(inputStream, true, monitor); + } + // Remember last saved state. + data.copyParametersToBackup(); + + } catch (CoreException ex) { + messageManager.sendMessage(0, ex); + saveFile = null; + } + return saveFile; + } + + public void saveTargets(ConverterData data) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + IPath filePathPrefix; + IPath filePath; + if (convert(data)) { + switch (data.getConverterDirection()) { + case FILES_TO_IMAGE: + + FilesConverterData filesConverterData; + filesConverterData = data.getFilesConverterData(); + + filePathPrefix = filesConverterData.getFilePathPrefix(); + filePath = Path.fromPortableString(filesConverterData.getParameters().getImageFilePath()); + filePath = IPathUtility.makeAbsolute(filePath, filePathPrefix, false); + saveTargetImage(FilesConverterParameters.MessageIds.IMAGE_FILE_PATH, filePath, + filesConverterData.getImageData()); + break; + case IMAGE_TO_FILES: + ImageConverterData imageConverterData; + ImageConverterParameters imageConverterParameters; + imageConverterData = data.getImageConverterData(); + imageConverterParameters = imageConverterData.getParameters(); + + filePathPrefix = imageConverterData.getFilePathPrefix(); + int size = imageConverterData.getConverter().getDefinition().getTargetFileDefinitions().size(); + int minSize = Math.min(size, imageConverterParameters.getTargetFilesSize()); + boolean saved = true; + for (int i = 0; i < minSize; i++) { + TargetFile targetFile = imageConverterParameters.getTargetFile(i); + filePath = Path.fromPortableString(targetFile.getPath()); + filePath = IPathUtility.makeAbsolute(filePath, filePathPrefix, false); + saved &= saveTargetFile(targetFile.getPathMessageId(), filePath, + imageConverterData.getTargetFileBytes(targetFile.getId())); + } + if (!saved) { + for (int i = 0; i < minSize; i++) { + TargetFile targetFile = imageConverterParameters.getTargetFile(i); + messageManager.sendMessage(targetFile.getPathMessageId(), IStatus.ERROR, + "No target file with file path and content present"); + } + + } + break; + default: + throw new RuntimeException("Unknown converter direction '" + data.getConverterDirection() + "'."); + + } + } + } + + /** + * Saves a target file, if path and content are present. Empty content is + * allowed, null content is interpreted as missing file. + * + * @param messageId + * The message id. + * @param filePath + * The target file path, may be empty, not null. + * @param bytes + * The target file content, may be empty or null. + * + * @return true if the file was save, false + * otherwise. + */ + private boolean saveTargetFile(int messageId, IPath filePath, byte[] bytes) { + if (filePath == null) { + throw new IllegalArgumentException("Parameter 'filePath' must not be null."); + } + boolean result; + + if (filePath.isEmpty()) { + messageManager.sendMessage(messageId, IStatus.WARNING, "No target file path specified"); + return false; + } + if (bytes == null) { + messageManager.sendMessage(messageId, IStatus.INFO, "File {0} not saved as there is no data for this file", + filePath.toPortableString()); + return false; + } + + IWorkspaceRoot workspaceRoot; + IFile saveFile; + IProgressMonitor monitor; + + result = false; + workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + saveFile = workspaceRoot.getFile(filePath); + monitor = null; + + try { + InputStream inputStream; + inputStream = new ByteArrayInputStream(bytes); + if (saveFile.exists()) { + saveFile.setContents(inputStream, false, false, monitor); + } else { + saveFile.create(inputStream, true, monitor); + } + + } catch (CoreException ex) { + messageManager.sendMessage(0, ex); + saveFile = null; + } + + if (saveFile != null) { + messageManager.sendMessage(messageId, IStatus.INFO, "File {0} saved with ${1} bytes", + filePath.toPortableString(), HexUtility.getLongValueHexString(bytes.length)); + result = true; + } + return result; + } + + private void saveTargetImage(int messageId, IPath filePath, ImageData imageData) { + if (filePath == null) { + throw new IllegalArgumentException("Parameter 'filePath' must not be null."); + } + if (filePath.isEmpty()) { + messageManager.sendMessage(messageId, IStatus.ERROR, "No image path specified"); + return; + } + if (imageData == null) { + messageManager.sendMessage(messageId, IStatus.ERROR, + "Image {0} not saved as there is no data for this image", filePath.toPortableString()); + return; + } + + ImageLoader imageLoader = new ImageLoader(); + imageLoader.data = new ImageData[] { imageData }; + int format = ImageExtensions.getImageFormat(filePath); + if (format == ImageExtensions.UNKNOWN_FORMAT) { + messageManager.sendMessage(messageId, IStatus.ERROR, + "Image {0} not saved as there is the extension cannot be mapped to a supported image format", + filePath.toPortableString()); + return; + } + + boolean success = false; + IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(filePath); + try { + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + imageLoader.save(bos, format); + bos.close(); + ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); + if (!file.exists()) { + file.create(bis, IResource.FORCE, null); + } else { + file.setContents(bis, IResource.FORCE, null); + } + success = true; + } catch (Exception ex) { + messageManager.sendMessage(messageId, IStatus.ERROR, "Image {0} not saved. {1}", + filePath.toPortableString(), ex.getMessage()); + } + // file.refreshLocal(IResource.DEPTH_ZERO, null); + + if (success) { + messageManager.sendMessage(messageId, IStatus.INFO, "Image {0} saved", filePath.toPortableString()); + } + } + + private ImageData loadSourceImage(int messageId, IPath filePath) { + if (filePath == null) { + throw new IllegalArgumentException("Parameter 'fileSection' must not be null."); + } + ImageData imageData = null; + if (!filePath.isEmpty()) { + IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(filePath); + + InputStream is; + try { + is = file.getContents(true); + } catch (CoreException ex) { + messageManager.sendMessage(messageId, ex); + is = null; + } + + if (is != null) { + try { + try { + imageData = new ImageData(is); + + } catch (SWTException ex) { + messageManager.sendMessage(messageId, IStatus.ERROR, + "Cannot open image file. " + ex.getMessage()); + + } + } finally { + try { + is.close(); + } catch (IOException ex) { + BasePlugin.getInstance().logError("Cannot close input stream for {0}", + new Object[] { filePath }, ex); + } + } + } + + } + return imageData; + } + + private byte[] loadSourceFile(int messageId, IPath filePath) { + if (filePath == null) { + throw new IllegalArgumentException("Parameter 'filePath' must not be null."); + } + byte[] result; + + if (!filePath.isEmpty()) { + try { + IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(filePath); + + result = FileUtility.readBytes(file, FileUtility.MAX_SIZE_1MB, true); + } catch (CoreException ex) { + messageManager.sendMessage(messageId, ex); + result = null; + } catch (IllegalArgumentException ex) { + messageManager.sendMessage(messageId, IStatus.ERROR, ex.getMessage()); + result = null; + } + + } else { + result = null; + } + return result; + } + + public boolean convert(ConverterData data) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + ConverterDirection converterDirection; + converterDirection = data.getConverterDirection(); + boolean result; + switch (converterDirection) { + + case FILES_TO_IMAGE: + result = convertFilesToImage(data); + break; + + case IMAGE_TO_FILES: + result = convertImageToFiles(data); + break; + + default: + throw new RuntimeException("Unknown converter direction '" + converterDirection + "'."); + } + return result; + } + + private boolean convertImageToFiles(ConverterData data) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + if (!data.isValidImage()) { + return false; + } + + ImageConverterData imageConverterData; + imageConverterData = data.getImageConverterData(); + + ImageConverterParameters imageConverterParameters; + imageConverterParameters = imageConverterData.getParameters(); + + // Setup image data fields. + if (imageConverterData.getImageData() == null) { + + // Create empty image data. + PaletteData palette = new PaletteData(255, 255, 255); + data.getImageConverterData().setImageData(new ImageData(320, 256, 8, palette)); + imageConverterData.setImageColorHistogram(null); + + } else { + ImageColorHistogram imageColorHistogram = new ImageColorHistogram(); + imageColorHistogram.analyze(imageConverterData.getImageData()); + imageConverterData.setImageColorHistogram(imageColorHistogram); + + } + + imageConverterData.setImageDataWidth(imageConverterData.getImageData().width); + imageConverterData.setImageDataHeight(imageConverterData.getImageData().height); + imageConverterData.clearTargetFileBytes(); + + Converter converter; + + if (StringUtility.isEmpty(imageConverterParameters.getConverterId())) { + messageManager.sendMessage(ConverterCommonParameters.MessageIds.CONVERTER_ID, IStatus.ERROR, + "No converter selected"); + return false; + } + converter = imageConverterData.getConverter(); + if (converter == null) { + messageManager.sendMessage(ConverterCommonParameters.MessageIds.CONVERTER_ID, IStatus.ERROR, + "Converter '{0}' is not registered", String.valueOf(imageConverterParameters.getConverterId())); + return false; + } + + if (messageManager.containsError()) { + return false; + } + + // Default the script if none is specified. + if (StringUtility.isEmpty(imageConverterParameters.getScript())) { + try { + imageConverterParameters.setScript(ConverterScript.getScript(converter.getClass())); + } catch (CoreException ex) { + messageManager.sendMessage(ImageConverterParameters.MessageIds.SCRIPT, ex); + return false; + } + } + + try { + // Apply default to conversion parameters. + if (imageConverterParameters.isUseDefaultScript() + || StringUtility.isEmpty(imageConverterParameters.getScript())) { + String script = ConverterScript.getScript(converter.getClass()); + imageConverterParameters.setScript(script); + } + + ConverterScript.convertToFileData(converter, imageConverterData); + } catch (CoreException ex) { + messageManager.sendMessage(ConverterCommonParameters.MessageIds.CONVERTER_ID, ex); + return false; + } catch (RuntimeException ex) { + String message = ex.getMessage(); + if (message == null) { + message = ex.getClass().getName(); + } + messageManager.sendMessage(ImageConverterParameters.MessageIds.SCRIPT, IStatus.ERROR, message); + return false; + } + + return true; + } + + private boolean convertFilesToImage(ConverterData data) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + if (!data.isValidFile()) { + return false; + } + + FilesConverterData filesConverterData; + filesConverterData = data.getFilesConverterData(); + + filesConverterData.setImageDataValid(false); + filesConverterData.setImageDataWidth(0); + filesConverterData.setImageDataHeight(0); + filesConverterData.setImageData(null); + + FilesConverterParameters filesConverterParameters; + filesConverterParameters = filesConverterData.getParameters(); + + if (filesConverterParameters.getSpacingWidth() < 0) { + messageManager.sendMessage(FilesConverterParameters.MessageIds.SPACING_WIDTH, IStatus.ERROR, + "Spacing width must not be negative. Current value is {0}", + String.valueOf(filesConverterParameters.getSpacingWidth())); + } + + if (filesConverterParameters.getColumns() <= 0) { + messageManager.sendMessage(FilesConverterParameters.MessageIds.COLUMNS, IStatus.ERROR, + "Columns count must be positive. Current value is {0}", + String.valueOf(filesConverterParameters.getColumns())); + } + if (filesConverterParameters.getRows() <= 0) { + messageManager.sendMessage(FilesConverterParameters.MessageIds.ROWS, IStatus.ERROR, + "Rows count must be positive. Current value is {0}", + String.valueOf(filesConverterParameters.getRows())); + } + + Converter converter; + + if (StringUtility.isEmpty(filesConverterParameters.getConverterId())) { + messageManager.sendMessage(ConverterCommonParameters.MessageIds.CONVERTER_ID, IStatus.ERROR, + "No converter selected"); + return false; + } + converter = filesConverterData.getConverter(); + if (converter == null) { + messageManager.sendMessage(ConverterCommonParameters.MessageIds.CONVERTER_ID, IStatus.ERROR, + "Converter '{0}' is not registered", String.valueOf(filesConverterParameters.getConverterId())); + return false; + } + + if (messageManager.containsError()) { + return false; + } + converter.convertToImageDataSize(filesConverterData); + if (filesConverterData.getImageDataWidth() <= 0) { + messageManager.sendMessage(FilesConverterParameters.MessageIds.COLUMNS, IStatus.ERROR, + "Resulting image data with '{0}' is not positive", + String.valueOf(filesConverterData.getImageDataWidth())); + } + if (filesConverterData.getImageDataHeight() <= 0) { + messageManager.sendMessage(FilesConverterParameters.MessageIds.ROWS, IStatus.ERROR, + "Resulting image data height '{0}' is not positive", + String.valueOf(filesConverterData.getImageDataWidth())); + } + + int MAX_PIXELS = 1000 * 1000; + int pixels = filesConverterData.getImageDataWidth() * filesConverterData.getImageDataHeight(); + if (pixels > MAX_PIXELS) { + messageManager.sendMessage(FilesConverterParameters.MessageIds.ROWS, IStatus.ERROR, + "Resulting image would have {0} pixels and exceed the memory limit of {1} pixels", + String.valueOf(pixels), String.valueOf(MAX_PIXELS)); + } + + if (messageManager.containsError()) { + return false; + } + + // Create index or direct palette and image data. + PaletteData paletteData; + ImageData imageData; + int paletteSize; + paletteSize = filesConverterData.getConverter().getDefinition().getTargetImagePaletteSize(); + if (paletteSize > 0) { + // Create 8 bit index palette. + RGB[] paletteColors = new RGB[paletteSize]; + RGB[] currentPaletteColors = filesConverterParameters.getPaletteRGBs(); + for (int i = 0; i < paletteColors.length; i++) { + if (i < currentPaletteColors.length) { + paletteColors[i] = currentPaletteColors[i]; + } else { + paletteColors[i] = new RGB(0, 0, 0); + } + } + filesConverterParameters.setPaletteRGBs(paletteColors); + + RGB[] actualPaletteColors = new RGB[paletteColors.length + 1]; + System.arraycopy(paletteColors, 0, actualPaletteColors, 0, paletteColors.length); + // The color at index actualPaletteColors.length is used as spacing + // color in order to keep the original palette index order + int spacingColorIndex = paletteColors.length; + actualPaletteColors[spacingColorIndex] = filesConverterParameters.getSpacingColor(); + paletteData = new PaletteData(actualPaletteColors); + imageData = new ImageData(filesConverterData.getImageDataWidth(), filesConverterData.getImageDataHeight(), + 8, paletteData); + for (int y = 0; y < filesConverterData.getImageDataHeight(); y++) { + for (int x = 0; x < filesConverterData.getImageDataWidth(); x++) { + imageData.setPixel(x, y, spacingColorIndex); + } + } + } else { + // Create 24 bit direct palette. + paletteData = new PaletteData(0xFF0000, 0xFF00, 0xFF); + imageData = new ImageData(filesConverterData.getImageDataWidth(), filesConverterData.getImageDataHeight(), + 24, paletteData); + } + filesConverterData.setImageData(imageData); + boolean conversionResult; + try { + conversionResult = converter.convertToImageData(filesConverterData); + } catch (RuntimeException ex) { + GraphicsPlugin.getInstance().logError("Runtime exception during convertFilesToImage()", null, ex); + conversionResult = false; + } + filesConverterData.setImageDataValid(conversionResult); + + ImageColorHistogram imageColorHistogram = new ImageColorHistogram(); + imageColorHistogram.analyze(imageData); + filesConverterData.setImageColorHistogram(imageColorHistogram); + return conversionResult; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterDefinition.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterDefinition.java new file mode 100644 index 00000000..19aab325 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterDefinition.java @@ -0,0 +1,285 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.StringTokenizer; + +import com.wudsn.ide.gfx.model.Aspect; + +/** + * Definition of a converter. The definition contains all static meta + * information about the converter. It is normally defined via an extension. + * + * + * For launching application under MacOS see + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=82155 and + * http://www.coderanch.com/t/111494/Mac-OS/launching-Safari-from-Java-App. + * + * @author Peter Dell + */ +public final class ConverterDefinition implements + Comparable { + + // Id + private String id; + private String name; + private List sourceFileExtensions; + private int targetImagePaletteSize; + private Aspect targetImageDisplayAspect; + + private List sourceFileDefinitions; + private List targetFileDefinitions; + + /** + * Creates an instance. Called by {@link ConverterRegistry} only. + */ + ConverterDefinition() { + sourceFileExtensions = new ArrayList(1); + sourceFileDefinitions = new ArrayList(); + targetFileDefinitions = new ArrayList(); + + } + + /** + * Sets the id of the converter. Called by {@link ConverterRegistry} only. + * + * @param id + * The id of the converter, not empty and not null. + */ + final void setId(String id) { + if (id == null) { + throw new IllegalArgumentException( + "Parameter 'id' must not be null."); + } + this.id = id; + } + + /** + * Gets the id of the converter. + * + * @return The id of the converter, not empty and not null. + */ + public final String getId() { + if (id == null) { + throw new IllegalStateException("Field 'id' must not be null."); + } + return id; + } + + /** + * Sets the name of the converter. Called by {@link ConverterRegistry} only. + * + * @param name + * The name of the converter, not empty and not null + * . + */ + final void setName(String name) { + if (name == null) { + throw new IllegalArgumentException( + "Parameter 'name' must not be null."); + } + this.name = name; + } + + /** + * Gets the name of the converter. + * + * @return The name of the converter, not empty and not null. + */ + public final String getName() { + if (name == null) { + throw new IllegalStateException("Field 'name' must not be null."); + } + return name; + } + + /** + * Sets the supported source file extensions the converter. Called by + * {@link ConverterRegistry} only. + * + * @param sourceFileExtensions + * The comma separated list of source file extensions in lower + * case characters, may be empty or null. + * + * @since 1.6.0 + */ + final void setSourceFileExtensions(String sourceFileExtensions) { + if (sourceFileExtensions == null) { + sourceFileExtensions = ""; + } + StringTokenizer st = new StringTokenizer(sourceFileExtensions, ","); + while (st.hasMoreTokens()) { + this.sourceFileExtensions.add(st.nextToken().trim()); + } + } + + /** + * Determines if a given file extension is supported. + * + * @param fileExtension + * The file extension in lower case letters, may be empty, not + * null. + * @return true if the file extension is supported, + * false otherwise. + * + * @since V1.6.0 + */ + public final boolean isSourceFileExtensionSupported(String fileExtension) { + if (fileExtension == null) { + throw new IllegalArgumentException( + "Parameter 'fileExtension' must not be null."); + } + + return sourceFileExtensions.contains(fileExtension); + } + + /** + * Sets the palette size of the converter. Called by + * {@link ConverterRegistry} only. + * + * @param targetImagePaletteSize + * The palette size of the converter, a positive number if a + * palette is used, 0 for a direct palette. + */ + final void setTargetImagePaletteSize(int targetImagePaletteSize) { + if (targetImagePaletteSize < 0) { + throw new IllegalArgumentException( + "Parameter 'targetImagePaletteSize' must not be negative. Specified value is " + + targetImagePaletteSize + "."); + } + this.targetImagePaletteSize = targetImagePaletteSize; + } + + /** + * Gets the palette size of the target image. + * + * @return The palette size of the target image, a positive number if a + * palette is used, 0 for direct palette. + */ + public final int getTargetImagePaletteSize() { + if (targetImagePaletteSize < 0) { + throw new IllegalStateException( + "Field 'targetImagePaletteSize' must not be negative. Specified value is " + + targetImagePaletteSize + "."); + } + return targetImagePaletteSize; + } + + /** + * Sets the zoom factor of the target image. + * + * @param targetImageDisplayAspect + * The target image zoom factor, not null. + */ + final void setTargetImageDisplayAspect(Aspect targetImageDisplayAspect) { + if (targetImageDisplayAspect == null) { + throw new IllegalArgumentException( + "Parameter 'targetImageDisplayAspect' must not be null."); + } + if (!targetImageDisplayAspect.isValid()) { + throw new IllegalArgumentException( + "Parameter 'targetImageDisplayAspect' must not be invalid."); + } + this.targetImageDisplayAspect = targetImageDisplayAspect; + } + + /** + * Gets the zoom factor of the target image. + * + * @return The zoom factor of the target image. + */ + public final Aspect getTargetImageDisplayAspect() { + if (targetImageDisplayAspect == null) { + throw new IllegalStateException( + "Field 'targetImageDisplayAspect' must not be empty."); + } + return targetImageDisplayAspect; + } + + /** + * Adds a source file definition. Called by {@link ConverterRegistry} only. + * + * @param sourceFileDefinition + * The source file definition, not null. + */ + final void addSourceFileDefinition( + ConverterSourceFileDefinition sourceFileDefinition) { + if (sourceFileDefinition == null) { + throw new IllegalArgumentException( + "Parameter 'sourceFileDefinition' must not be null."); + } + sourceFileDefinitions.add(sourceFileDefinition); + } + + /** + * Gets the unmodifiable list of source file definitions. + * + * @return The unmodifiable list of source file definitions, may be empty, + * not null. + */ + public final List getSourceFileDefinitions() { + return Collections.unmodifiableList(sourceFileDefinitions); + } + + /** + * Adds a target file definition. Called by {@link ConverterRegistry} only. + * + * @param targetFileDefinition + * The target file definition, not null. + */ + final void addTargetFileDefinition( + ConverterTargetFileDefinition targetFileDefinition) { + if (targetFileDefinition == null) { + throw new IllegalArgumentException( + "Parameter 'targetFileDefinition' must not be null."); + } + targetFileDefinitions.add(targetFileDefinition); + } + + /** + * Gets the unmodifiable list of target file definitions. + * + * @return The unmodifiable list of target file definitions, may be empty, + * not null. + */ + public final List getTargetFileDefinitions() { + + return Collections.unmodifiableList(targetFileDefinitions); + } + + @Override + public final int compareTo(ConverterDefinition o) { + if (o == null) { + throw new IllegalArgumentException( + "Parameter 'o' must not be null."); + } + if (name == null || o.name == null) { + if (name == null) { + throw new IllegalStateException( + "Field 'name' must not be null for this or for argument."); + } + } + return name.compareTo(o.name); + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterParameters.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterParameters.java new file mode 100644 index 00000000..61ecf8ff --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterParameters.java @@ -0,0 +1,270 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +import com.wudsn.ide.base.Texts; +import com.wudsn.ide.base.common.FileUtility; +import com.wudsn.ide.base.common.SequencedProperties; +import com.wudsn.ide.base.common.TextUtility; +import com.wudsn.ide.gfx.GraphicsPlugin; +import com.wudsn.ide.gfx.model.ConverterDirection; +import com.wudsn.ide.gfx.model.GraphicsPropertiesSerializer; + +public final class ConverterParameters { + + private static final class Attributes { + + /** + * Creation is private. + */ + private Attributes() { + } + + public static final String CONVERTER_DIRECTION = "converterDirection"; + public static final String FILES_CONVERTER_PARAMETERS = "filesConverterParameters"; + public static final String IMAGE_CONVERTER_PARAMETERS = "imageConverterParameters"; + + } + + private static final class Defaults { + + /** + * Creation is private. + */ + private Defaults() { + } + + public static final ConverterDirection CONVERTER_DIRECTION = ConverterDirection.FILES_TO_IMAGE; + } + + private ConverterDirection converterDirection; + private FilesConverterParameters filesConverterParameters; + private ImageConverterParameters imageConverterParameters; + + public ConverterParameters() { + + filesConverterParameters = new FilesConverterParameters(); + imageConverterParameters = new ImageConverterParameters(); + setDefaults(); + } + + public void setDefaults() { + + converterDirection = Defaults.CONVERTER_DIRECTION; + filesConverterParameters.setDefaults(); + imageConverterParameters.setDefaults(); + } + + public void setConverterDirection(ConverterDirection value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.converterDirection = value; + } + + public ConverterDirection getConverterDirection() { + return converterDirection; + } + + public ConverterCommonParameters getConverterCommonParameters() { + switch (getConverterDirection()) { + case FILES_TO_IMAGE: + return filesConverterParameters; + case IMAGE_TO_FILES: + return imageConverterParameters; + default: + throw new IllegalStateException("Unknown converter direction " + + getConverterDirection() + "."); + } + } + + public FilesConverterParameters getFilesConverterParameters() { + return filesConverterParameters; + } + + public ImageConverterParameters getImageConverterParameters() { + return imageConverterParameters; + } + + public void copyTo(ConverterParameters target) { + if (target == null) { + throw new IllegalArgumentException( + "Parameter 'target' must not be null."); + } + target.setConverterDirection(converterDirection); + filesConverterParameters.copyTo(target.getFilesConverterParameters()); + imageConverterParameters.copyTo(target.getImageConverterParameters()); + } + + public boolean equals(ConverterParameters target) { + if (target == null) { + throw new IllegalArgumentException( + "Parameter 'target' must not be null."); + } + boolean result; + result = target.getConverterDirection().equals(converterDirection); + result = result + && target.getFilesConverterParameters().equals( + filesConverterParameters); + result = result + && target.getImageConverterParameters().equals( + imageConverterParameters); + return result; + } + + public InputStream getContents(String filePath) throws CoreException { + if (filePath == null) { + throw new IllegalArgumentException( + "Parameter 'filePath' must not be null."); + } + + GraphicsPropertiesSerializer serializer; + Properties properties; + + serializer = new GraphicsPropertiesSerializer(); + serialize(serializer); + properties = serializer.getProperties(); + ByteArrayOutputStream propertiesStream = new ByteArrayOutputStream(); + + try { + // ByteArrayOutputStream propertiesStream = new + // ByteArrayOutputStream(); + properties + .store(propertiesStream, "WUDSN IDE Converter Parameters"); + propertiesStream.close(); + + // Iterator iterator = ImageIO + // .getImageWritersBySuffix("png"); + // + // if (!iterator.hasNext()) { + // throw new RuntimeException("No image writer for suffix 'png'"); + // } + // + // ImageWriter imagewriter = iterator.next(); + // imagewriter.setOutput(ImageIO + // .createImageOutputStream(resourceStream)); + // + // // Create & populate metadata + // PNGMetadata metadata = new PNGMetadata(); + // metadata.tEXt_keyword.add("WUDSN"); + // metadata.tEXt_text.add(new + // String(propertiesStream.toByteArray()));// + // + // // Render the PNG to memory + // BufferedImage bufferedImage = new BufferedImage(imageData.width, + // imageData.height, BufferedImage.TYPE_INT_RGB); + // for (int y = 0; y < imageData.height; y++) { + // for (int x = 0; x < imageData.width; x++) { + // int pixel; + // RGB rgb; + // + // pixel = imageData.getPixel(x, y); + // rgb = imageData.palette.getRGB(pixel); + // bufferedImage.setRGB(x, y, rgb.red << 16 | rgb.green << 8 + // | rgb.blue); + // } + // } + // + // // Build the image container, set the metadata and write the + // // container. + // IIOImage iioImage = new IIOImage(bufferedImage, null, null); + // iioImage.setMetadata(metadata); // Attach the metadata + // imagewriter.write(null, iioImage, null); + + } catch (IOException ex) { + // ERROR: Cannot write content of file '{0}'. + throw new CoreException(new Status(IStatus.ERROR, GraphicsPlugin.ID, + TextUtility.format(Texts.MESSAGE_E212, filePath), ex)); + + } + + return new ByteArrayInputStream(propertiesStream.toByteArray()); + } + + private void serialize(GraphicsPropertiesSerializer serializer) { + if (serializer == null) { + throw new IllegalArgumentException( + "Parameter 'serializer' must not be null."); + } + serializer + .writeEnum(Attributes.CONVERTER_DIRECTION, converterDirection); + filesConverterParameters.serialize(serializer, + Attributes.FILES_CONVERTER_PARAMETERS); + imageConverterParameters.serialize(serializer, + Attributes.IMAGE_CONVERTER_PARAMETERS); + } + + public void read(IFile file) throws CoreException { + if (file == null) { + throw new IllegalArgumentException( + "Parameter 'file' must not be null."); + } + + byte[] content; + content = FileUtility.readBytes(file, FileUtility.MAX_SIZE_UNLIMITED, + false); + SequencedProperties properties = new SequencedProperties(); + + try { + properties.load(new ByteArrayInputStream(content)); + } catch (IOException ex) { + // ERROR: Cannot read content of file '{0}'. + throw new CoreException(new Status(IStatus.ERROR, GraphicsPlugin.ID, + TextUtility.format(Texts.MESSAGE_E206, file.getFullPath() + .toOSString()), ex)); + + } + GraphicsPropertiesSerializer serializer; + + serializer = new GraphicsPropertiesSerializer(); + serializer.getProperties().putAll(properties); + deserialize(serializer); + + GraphicsPlugin.getInstance().log("ConverterParameters.read({0}):{1}", + new Object[] { file, serializer.getProperties() }); + + } + + private void deserialize(GraphicsPropertiesSerializer serializer) { + if (serializer == null) { + throw new IllegalArgumentException( + "Parameter 'serializer' must not be null."); + } + converterDirection = serializer.readEnum( + Attributes.CONVERTER_DIRECTION, Defaults.CONVERTER_DIRECTION, + ConverterDirection.class); + filesConverterParameters.deserialize(serializer, + Attributes.FILES_CONVERTER_PARAMETERS); + imageConverterParameters.deserialize(serializer, + Attributes.IMAGE_CONVERTER_PARAMETERS); + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterRegistry.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterRegistry.java new file mode 100644 index 00000000..b34260a6 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterRegistry.java @@ -0,0 +1,305 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.Platform; + +import com.wudsn.ide.gfx.model.AspectUtility; +import com.wudsn.ide.gfx.model.ConverterDirection; + +/** + * Registry for converters, based on the extension points + * {@value ConverterRegistry#CONVERTERS}. + * + * @author Peter Dell + * + */ +public final class ConverterRegistry { + + /** + * The id of the extension point which provides the converters. + */ + private static final String CONVERTERS = "com.wudsn.ide.gfx.converters"; + + /** + * Maximum number of source files. + */ + public static final int MAX_SOURCE_FILES = 10; + + /** + * Maximum number of target files. + */ + public static final int MAX_TARGET_FILES = 10; + + /** + * The registered converter definitions. + */ + private List filesToImageConverterDefinitionList; + private List imageToFilesConverterDefinitionList; + + /** + * The cached map of converter instances. + */ + private Map converterMap; + + /** + * Creation is public. + */ + public ConverterRegistry() { + filesToImageConverterDefinitionList = Collections.emptyList(); + imageToFilesConverterDefinitionList = Collections.emptyList(); + converterMap = Collections.emptyMap(); + + } + + /** + * Initializes the list of available converters. + */ + public void init() { + + filesToImageConverterDefinitionList = new ArrayList(); + imageToFilesConverterDefinitionList = new ArrayList(); + converterMap = new TreeMap(); + + IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); + IExtensionPoint extensionPoint = extensionRegistry + .getExtensionPoint(CONVERTERS); + if (extensionPoint == null) { + throw new IllegalStateException("Extension point '" + CONVERTERS + + "' is not defined."); + } + + IExtension[] extensions = extensionPoint.getExtensions(); + + for (IExtension extension : extensions) { + IConfigurationElement[] converterGroupElements = extension + .getConfigurationElements(); + for (IConfigurationElement converterGroupElement : converterGroupElements) { + IConfigurationElement[] converterElements = converterGroupElement + .getChildren("converter"); + for (IConfigurationElement converterElement : converterElements) { + + ConverterDefinition converterDefinition; + converterDefinition = new ConverterDefinition(); + converterDefinition.setId(converterElement + .getAttribute("id")); + converterDefinition.setName(converterElement + .getAttribute("name")); + converterDefinition + .setSourceFileExtensions(converterElement + .getAttribute("sourceFileExtensions")); + converterDefinition.setTargetImagePaletteSize(Integer + .parseInt(converterElement + .getAttribute("targetImagePaletteSize"))); + converterDefinition + .setTargetImageDisplayAspect(AspectUtility.fromString(converterElement + .getAttribute("targetImageDisplayAspect"))); + IConfigurationElement[] sourceFileElements = converterElement + .getChildren("sourceFile"); + int i = 0; + for (IConfigurationElement sourceFileElement : sourceFileElements) { + ConverterSourceFileDefinition sourceFileDefinition; + sourceFileDefinition = new ConverterSourceFileDefinition(); + sourceFileDefinition.setSourceFileId(i); + sourceFileDefinition.setLabel(sourceFileElement + .getAttribute("label")); + converterDefinition + .addSourceFileDefinition(sourceFileDefinition); + i++; + } + + IConfigurationElement[] targetFileElements = converterElement + .getChildren("targetFile"); + i = 0; + for (IConfigurationElement targetFileElement : targetFileElements) { + ConverterTargetFileDefinition targetFileDefinition; + targetFileDefinition = new ConverterTargetFileDefinition(); + targetFileDefinition.setSourceFileId(i); + targetFileDefinition.setLabel(targetFileElement + .getAttribute("label")); + converterDefinition + .addTargetFileDefinition(targetFileDefinition); + i++; + } + + // If there is a source file, it is a files to image + // converter. + if (!converterDefinition.getSourceFileDefinitions() + .isEmpty()) { + filesToImageConverterDefinitionList + .add(converterDefinition); + + } + // If there is a target file, it is a files to image + // converter. + if (!converterDefinition.getTargetFileDefinitions() + .isEmpty()) { + imageToFilesConverterDefinitionList + .add(converterDefinition); + + } + addConverter(converterElement, converterDefinition); + } + } + } + + // Create a sorted, unmodifiable copy. + filesToImageConverterDefinitionList = new ArrayList( + filesToImageConverterDefinitionList); + Collections.sort(filesToImageConverterDefinitionList); + filesToImageConverterDefinitionList = Collections + .unmodifiableList(filesToImageConverterDefinitionList); + + // Create a sorted, unmodifiable copy. + imageToFilesConverterDefinitionList = new ArrayList( + imageToFilesConverterDefinitionList); + Collections.sort(imageToFilesConverterDefinitionList); + imageToFilesConverterDefinitionList = Collections + .unmodifiableList(imageToFilesConverterDefinitionList); + + // Create an unmodifiable copy. + converterMap = Collections.unmodifiableMap(converterMap); + } + + /** + * Adds a new converter. + * + * @param configurationElement + * The configuration element used as class instance factory, not + * null. + * + * @param converterDefinition + * The converter definition, not null. + */ + private void addConverter(IConfigurationElement configurationElement, + ConverterDefinition converterDefinition) { + if (configurationElement == null) { + throw new IllegalArgumentException( + "Parameter 'configurationElement' must not be null."); + } + if (converterDefinition == null) { + throw new IllegalArgumentException( + "Parameter 'converterDefinition' must not be null."); + } + + String id = converterDefinition.getId(); + Converter converter; + try { + converter = (Converter) configurationElement + .createExecutableExtension("id"); + } catch (CoreException ex) { + throw new RuntimeException("Cannot instantiate converter '" + id + + "'.", ex); + } + converter.setDefinition(converterDefinition); + converter = converterMap.put(id, converter); + if (converter != null) { + throw new RuntimeException("Converter id '" + id + + "' is already registered to class '" + + converter.getClass().getName() + "'."); + } + + } + + /** + * Gets the unmodifiable list of converter definitions, sorted by their id. + * + * @param converterDirection + * The converter direction, not null. + * + * @return The unmodifiable list of converter definitions, sorted by their + * id, not empty and not null. + */ + public List getDefinitions( + ConverterDirection converterDirection) { + if (converterDirection == null) { + throw new IllegalArgumentException( + "Parameter 'converterDirection' must not be null."); + } + switch (converterDirection) { + case FILES_TO_IMAGE: + return filesToImageConverterDefinitionList; + case IMAGE_TO_FILES: + return imageToFilesConverterDefinitionList; + default: + throw new IllegalArgumentException("Unknown converter directtion " + + converterDirection + "."); + } + } + + /** + * Gets the converter definition for an id. + * + * @param converterId + * The converter id, may be empty, not null. + * @param converterDirection + * The direction of the converter, not null. + * + * @return The converter definition or null. + */ + public ConverterDefinition getDefinition(String converterId, + ConverterDirection converterDirection) { + if (converterId == null) { + throw new IllegalArgumentException( + "Parameter 'converterId' must not be null."); + } + List converterDefinitionList = getDefinitions(converterDirection); + for (ConverterDefinition converterDefinition : converterDefinitionList) { + if (converterDefinition.getId().equals(converterId)) { + return converterDefinition; + } + } + return null; + } + + /** + * Gets the converter for a given id. Instances of {@link Converter} are + * stateless singletons within the plugin. + * + * @param converterId + * The converter id, not null. + * + * @return The converter or null. + */ + public Converter getConverter(String converterId) { + if (converterId == null) { + throw new IllegalArgumentException( + "Parameter 'converterId' must not be null."); + } + Converter result; + synchronized (converterMap) { + + result = converterMap.get(converterId); + } + + return result; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterScript.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterScript.java new file mode 100644 index 00000000..9b0855d1 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterScript.java @@ -0,0 +1,162 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.io.InputStream; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ContextFactory; +import org.mozilla.javascript.Function; +import org.mozilla.javascript.RhinoException; +import org.mozilla.javascript.Scriptable; + +import com.wudsn.ide.base.common.FileUtility; +import com.wudsn.ide.gfx.GraphicsPlugin; + +/** + * Converter script utility class. + * + * @author Peter Dell + * + * @since 1.6.0 + */ +public final class ConverterScript { + + public static void convertToFileData(Converter converter, ImageConverterData data) throws CoreException { + + // Collect the arguments into a single string. + String script = data.getParameters().getScript(); + ConverterScriptData converterScriptData = data.getConverterScriptData(); + ContextFactory contextFactory = ContextFactory.getGlobal(); + Context context = null; + Scriptable scope = null; + + try { + if (!script.equals(converterScriptData.getCompiledScript())) { + + if (converterScriptData.getCompiledContext() != null && Context.getCurrentContext() != null) { + Context.exit(); + } + // Creates and enters a new Context. The Context stores + // information + // about the execution environment of a script. + context = contextFactory.enterContext(); + scope = context.initStandardObjects(); + context.setOptimizationLevel(9); + context.evaluateString(scope, script, "Line ", 1, null); + // Initialize the standard objects (Object, Function, etc.) + // This must be done before scripts can be executed. Returns + // a scope object that we use in later calls. + converterScriptData.setCompiledScript(script); + converterScriptData.setCompiledContext(context); + converterScriptData.setCompiledScope(scope); + } else { + // Restore the previous context. + context = converterScriptData.getCompiledContext(); + contextFactory.enterContext(context); + scope = converterScriptData.getCompiledScope(); + } + + // Set global variables. + ConverterConsole converterConsole = GraphicsPlugin.getInstance().getConverterConsole(); + scope.put("Console", scope, Context.toObject(converterConsole, scope)); + + // Call function + converterScriptData.setErrorLineNumber(-1); + String functionName = "convertToFileData"; + Object functionObject = scope.get(functionName, scope); + if (functionObject == null) { + throw new CoreException(new Status(IStatus.ERROR, GraphicsPlugin.ID, "'" + functionName + + "' is undefined.")); + } + if (!(functionObject instanceof Function)) { + throw new CoreException(new Status(IStatus.ERROR, GraphicsPlugin.ID, "'" + functionName + + "' is not a function.")); + } + + Object functionArgs[] = { Context.toObject(data, scope) }; + Function function = (Function) functionObject; + function.call(context, scope, scope, functionArgs); + + } catch (RhinoException ex) { + converterScriptData.setErrorLineNumber(ex.lineNumber()); + String message = getMessageString(ex.details()); + String lineSource = getMessageString(ex.lineSource()); + throw new CoreException(new Status(IStatus.ERROR, GraphicsPlugin.ID, "Error in script line " + + ex.lineNumber() + ": " + message + " " + lineSource, ex)); + + } finally { + + // Exit from the context. Remove the context association to the + // current thread. + if (Context.getCurrentContext() != null) { + Context.exit(); + } + } + } + + /** + * Converts a string to message format (not null, no tabs). + * + * @param string + * The string, or null. + * @return The message string, may be empty, not null. + */ + private static String getMessageString(String string) { + String result; + if (string != null) { + result = string.replace('\t', ' '); + } else { + result = ""; + } + return result; + } + + /** + * Gets the script associated with a compiler class. + * + * @param converterClass + * The of the converter, not null. + * @return The script for the converter, may be empty, not null + * . + * @throws CoreException + * In case there is an error while reading an existing script. + */ + public static String getScript(Class converterClass) throws CoreException { + if (converterClass == null) { + throw new IllegalArgumentException("Parameter 'converterClass' must not be null."); + } + String result; + + String converterScriptFileName = "/" + converterClass.getName().replace('.', '/') + ".js"; + InputStream inputStream = converterClass.getResourceAsStream(converterScriptFileName); + + if (inputStream != null) { + result = FileUtility.readString(converterScriptFileName, inputStream, FileUtility.MAX_SIZE_UNLIMITED); + } else { + result = ""; + } + + return result; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterScriptData.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterScriptData.java new file mode 100644 index 00000000..13e425c6 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterScriptData.java @@ -0,0 +1,121 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Scriptable; + +/** + * Container for a compiled converter scripts and its context. + * + * @author Peter Dell + * @since 1.6.6 + */ +public final class ConverterScriptData { + private String compiledScript; + private Context compiledContext; + private Scriptable compiledScope; + private int errorLineNumber; + + /** + * Gets the compiled script for which the compiled context and scope are + * cached. + * + * @return The compiled script, maybe be empty, not null. + */ + public String getCompiledScript() { + return compiledScript; + } + + /** + * Sets the compiled script for which the compiled context and scope are + * cached. + * + * @param compiledScript + * The compiled script, may be empty, not null. + */ + public void setCompiledScript(String compiledScript) { + if (compiledScript == null) { + throw new IllegalArgumentException("Parameter 'compiledScript' must not be null."); + } + this.compiledScript = compiledScript; + } + + /** + * Gets the compiled context which was created for the compiled script. + * + * @return The compiled context or null. + */ + public Context getCompiledContext() { + return compiledContext; + } + + /** + * Sets the compiled context which was created for the compiled script. + * + * @param compiledContext + * The compiled context or null. + */ + public void setCompiledContext(Context compiledContext) { + this.compiledContext = compiledContext; + + } + + /** + * Gets the compiled scope which was created for the compiled script. + * + * @return The compiled context or null. + */ + public Scriptable getCompiledScope() { + return compiledScope; + } + + /** + * Sets the compiled scope which was created for the compiled script. + * + * @param compiledScope + * The compiled scope or null. + */ + public void setCompiledScope(Scriptable compiledScope) { + this.compiledScope = compiledScope; + } + + /** + * Set the line number of the first error that occurred in the script. + * + * @param errorLineNumber + * The line number of the first error that occurred in the + * script, a positive integer or -1 if there is + * no error. + */ + public void setErrorLineNumber(int errorLineNumber) { + this.errorLineNumber = errorLineNumber; + } + + /** + * Gets the line number of the first error that occurred in the script. + * + * @return The line number of the first error that occurred in the script,a + * positive integer or -1 if there is no error. + */ + public int geErrorLineNumber() { + return errorLineNumber; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterSourceFileDefinition.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterSourceFileDefinition.java new file mode 100644 index 00000000..740df4b0 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterSourceFileDefinition.java @@ -0,0 +1,45 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ +package com.wudsn.ide.gfx.converter; + +public final class ConverterSourceFileDefinition { + private int sourceFileId; + private String label; + + ConverterSourceFileDefinition() { + + } + + public int getSourceFileId() { + return sourceFileId; + } + + final void setSourceFileId(int sourceFileId) { + this.sourceFileId = sourceFileId; + } + + public String getLabel() { + return label; + } + + final void setLabel(String label) { + this.label = label; + } + +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterTargetFileDefinition.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterTargetFileDefinition.java new file mode 100644 index 00000000..9fd7d56d --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ConverterTargetFileDefinition.java @@ -0,0 +1,46 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +public final class ConverterTargetFileDefinition { + private int sourceFileId; + private String label; + + ConverterTargetFileDefinition() { + + } + + public int getSourceFileId() { + return sourceFileId; + } + + final void setSourceFileId(int sourceFileId) { + this.sourceFileId = sourceFileId; + } + + public String getLabel() { + return label; + } + + final void setLabel(String label) { + this.label = label; + } + +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/FilesConverterData.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/FilesConverterData.java new file mode 100644 index 00000000..2583cbbf --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/FilesConverterData.java @@ -0,0 +1,212 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.util.ArrayList; +import java.util.List; + +import com.wudsn.ide.base.common.HexUtility; +import com.wudsn.ide.base.common.NumberUtility; +import com.wudsn.ide.gfx.GraphicsPlugin; +import com.wudsn.ide.gfx.model.ConverterDirection; +import com.wudsn.ide.gfx.model.ConverterMode; + +public final class FilesConverterData extends ConverterCommonData { + + private FilesConverterParameters parameters; + + private List sourceFilesBytes; + + private boolean imageDataValid; + + FilesConverterData(ConverterData converterData) { + super(converterData); + + this.parameters = converterData.getParameters() + .getFilesConverterParameters(); + sourceFilesBytes = new ArrayList(0); + } + + public FilesConverterParameters getParameters() { + return parameters; + } + + /** + * Gets the converter for a converter id specified in the parameters. + * Instances of {@link Converter} are stateless singletons within the + * plugin. + * + * @return The converter or null. + */ + public Converter getConverter() { + ConverterRegistry converterRegistry; + Converter converter; + converterRegistry = GraphicsPlugin.getInstance().getConverterRegistry(); + converter = converterRegistry.getConverter(parameters.getConverterId()); + return converter; + } + + public int getTargetImagePaletteSize() { + ConverterRegistry converterRegistry; + ConverterDefinition converterDefinition; + int result; + + converterRegistry = GraphicsPlugin.getInstance().getConverterRegistry(); + converterDefinition = converterRegistry.getDefinition( + parameters.getConverterId(), ConverterDirection.FILES_TO_IMAGE); + if (converterDefinition != null) { + result = converterDefinition.getTargetImagePaletteSize(); + } else { + result = 0; + } + return result; + } + + @Override + public boolean isCreateConversionEnabled() { + return converterData.isValid() + && converterData.getConverterMode() == ConverterMode.RAW_FILE; + } + + @Override + public boolean isValid() { + return converterData.isValidFile(); + } + + @Override + public boolean isRefreshEnabled() { + return converterData.isValidFile(); + } + + @Override + public void clear() { + super.clear(); + sourceFilesBytes.clear(); + } + + public void setSourceFileBytes(int sourceFileId, byte[] bytes) { + if (sourceFileId < 0) { + throw new IllegalArgumentException( + "Parameter 'sourceFileId' must not be negative. Specified value is " + + sourceFileId + "."); + } + while (sourceFilesBytes.size() <= sourceFileId) { + sourceFilesBytes.add(null); + } + sourceFilesBytes.set(sourceFileId, bytes); + } + + public byte[] getSourceFileBytes(int sourceFileId) { + if (sourceFileId < 0) { + throw new IllegalArgumentException( + "Parameter 'sourceFileId' must not be negative. Specified value is " + + sourceFileId + "."); + } + byte[] bytes; + if (sourceFileId < sourceFilesBytes.size()) { + bytes = sourceFilesBytes.get(sourceFileId); + } else { + bytes = null; + } + return bytes; + } + + public void setImageDataValid(boolean imageDataValid) { + this.imageDataValid = imageDataValid; + } + + public boolean isImageDataValid() { + return imageDataValid; + } + + public boolean isSaveImageEnabled() { + return converterData.isValidFile()&& isImageDataValid(); + } + + /** + * Gets a byte from the source file, taking it offset from the parameter + * into account plus the relative offset of the conversion routine. + * + * @param sourceFileId + * The id of the source file, a non-negative integer. + * @param offset + * The relative object of the conversion routine, a non-negative + * integer. + * @return The byte as integer or -1 to indicate that the + * offset is outside of the file. + */ + public int getSourceFileByte(int sourceFileId, int offset) { + if (sourceFileId >= sourceFilesBytes.size()) { + return -1; + } + + byte[] sourceFileBytes = sourceFilesBytes.get(sourceFileId); + if (sourceFileBytes == null) { + return -1; + } + + offset = offset + parameters.getSourceFile(sourceFileId).getOffset(); + if (offset < 0 || offset >= sourceFileBytes.length) { + return -1; + } + int value = sourceFileBytes[offset] & 0xff; + return value; + } + + public void setPalettePixel(int x, int y, int color) { + try { + imageData.setPixel(x, y, color); + } catch (RuntimeException ex) { + GraphicsPlugin + .getInstance() + .logError( + "Error setting palette pixel at ({0}, {1}) to color {2}. Image size is {3},{4}", + new String[] { + NumberUtility.getLongValueDecimalString(x), + NumberUtility.getLongValueDecimalString(y), + HexUtility.getLongValueHexString(color), + NumberUtility + .getLongValueDecimalString(imageData.width), + NumberUtility + .getLongValueDecimalString(imageData.height) }, + ex); + } + } + + public void setDirectPixel(int x, int y, int color) { + try { + imageData.setPixel(x, y, color); + } catch (RuntimeException ex) { + GraphicsPlugin + .getInstance() + .logError( + "Error setting direct pixel at ({0}, {1}) to color {2}. Image size is {3},{4}", + new String[] { + NumberUtility.getLongValueDecimalString(x), + NumberUtility.getLongValueDecimalString(y), + HexUtility.getLongValueHexString(color), + NumberUtility + .getLongValueDecimalString(imageData.width), + NumberUtility + .getLongValueDecimalString(imageData.height) }, + ex); + } + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/FilesConverterDataLogic.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/FilesConverterDataLogic.java new file mode 100644 index 00000000..d9833fb1 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/FilesConverterDataLogic.java @@ -0,0 +1,293 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ +package com.wudsn.ide.gfx.converter; + +import java.util.Iterator; +import java.util.List; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.GraphicsPlugin; +import com.wudsn.ide.gfx.converter.atari8bit.LinearBitMapGraphics8Converter; +import com.wudsn.ide.gfx.model.ConverterDirection; + +/** + * This class is based on the excellent open source + * "First Atari Image Library (FAIL)". Thanks to the creators to FAIL: Piotr + * Fusik, Adrian Matoga and Pawel Szewczyk for their support. You can find FAIL + * on sourceforge "http://fail.sourceforge.net". + * + * @author Peter Dell + * + */ + +public final class FilesConverterDataLogic { + + /** + * Helper class to detect the support binary file formats by their + * extension. The extension have to be defined with lower case characters. + * + * @author Peter Dell + */ + public static final class FileExtensions { + + // C64 font with 2 bytes load address + public static final String _64c = "64c"; + + // 80x192, 256 colors, interlaced + // @since FAIL 1.0.0 + public static final String AP3 = "ap3"; + + // Any Point, Any Color; 80x96, 256 colors, interlaced + // @since FAIL 1.0.0 + public static final String APC = "apc"; + + // 8x8 charset, mono or multicolor + // @since FAIL 1.0.0 + public static final String CHR = "chr"; + + // Champions' Interlace; 160x192, compressed + // @since FAIL 1.0.0 + public static final String CCI = "cci"; + + // Champions' Interlace; 160x192 + // @since FAIL 1.0.0 + public static final String CIN = "cin"; + + // Trzmiel; 320x192, mono, compressed + // @since FAIL 1.0.0 + public static final String CPR = "cpr"; + + // Standard 8x8 font, mono + // @since FAIL 1.0.0 + public static final String FNT = "fnt"; + + // Gephard Hires Graphics; up to 320x200, mono + // @since FAIL 1.0.1 + public static final String GHG = "ghg"; + + // Standard 320x192, mono + // @since FAIL 1.0.0 + public static final String GR8 = "gr8"; + + // Standard 80x192, grayscale + // @since FAIL 1.0.0 + public static final String GR9 = "gr9"; + + // Hard Interlace Picture; 160x200, grayscale + // @since FAIL 1.0.0 + public static final String HIP = "hip"; + + // Hires 256x239, 3 colors, interlaced + // @since FAIL 1.0.0 + public static final String HR = "hr"; + + // Hires 320x200, 5 colors, interlaced + // @since FAIL 1.0.1 + public static final String HR2 = "hr2"; + + // APAC 80x192, 256 colors interlaced + // @since FAIL 1.0.0 + public static final String ILC = "ilc"; + + // Interlace Picture 160x200, 7 colors, interlaced + // @since FAIL 1.0.0 + public static final String INP = "inp"; + + // INT95a, up to 160x239, 16 colors, interlaced + // @since FAIL 1.0.0 + public static final String INT = "int"; + + // McPainter; 160x200, 16 colors, interlaced + // @since FAIL 1.0.1 + public static final String MCP = "mcp"; + + // Micropainter 160x192, 4 colors + // @since FAIL 1.0.0 + public static final String MIC = "mic"; + + // Koala MicroIllustrator; 160x192, 4 colors, compressed + // @since FAIL 1.0.0 + public static final String PIC = "pic"; + + // Plama 256; 80x96, 256 colors + // @since FAIL 1.0.0 + public static final String PLM = "plm"; + + // Rocky Interlace Picture; up to 160x239 + // @since FAIL 1.0.0 + public static final String RIP = "rip"; + + // C64 sprites + // Can be mono or multi color. + public static final String SPR = "spr"; + + // 16x16 font, mono + // @since FAIL 1.0.0 + public static final String SXS = "sxs"; + + // Taquart Interlace Picture; up to 160x119 + // @since FAIL 1.0.0 + public static final String TIP = "tip"; + + + + // TODO Fail 1.1.0 +// Fixed decoding of ILC, AP3, RIP, PIC, CPR, HIP and CIN. +// Added support for MCH, IGE, 256, AP2, JGP, DGP, ESC, PZM, IST and RAW. +// MCH IGE 256 AP2 JGP DGP ESC PZM IST RAW +// 256:: 80x96, 256 colors. +// AP2:: 80x96, 256 colors. +// +// DGP:: "DigiPaint", 80x192, 256 colors, interlaced. +// ESC:: "EscalPaint", 80x192, 256 colors, interlaced. +// IGE:: "Interlace Graphics Editor", 128x96, 16 colors, interlaced. +// +// IST:: "Interlace Studio", 160x200, interlaced. +// JGP:: "Jet Graphics Planner", 8x16 tiles, 4 colors. +// MCH:: Up to 192x240, 128 colors. +// PZM:: "EscalPaint", 80x192, 256 colors, interlaced. +// RAW:: "XL-Paint MAX", 160x192, 16 colors, interlaced. + +// fail.h: #define FAIL_WIDTH_MAX 320 => 384, used in RIP +// +// /* Limits. */ +// #define FAIL_IMAGE_MAX 30000 +// #define FAIL_WIDTH_MAX 384 +// #define FAIL_HEIGHT_MAX 240 +// #define FAIL_PALETTE_MAX 768 +// #define FAIL_PIXELS_MAX (FAIL_WIDTH_MAX * FAIL_HEIGHT_MAX * 3) + } + + FilesConverterDataLogic() { + + } + + public void applyDefaults(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + FilesConverterParameters parameters; + Converter converter; + + parameters = data.getParameters(); + converter = data.getConverter(); + + // Take defaults from the definition. + if (converter != null) { + int targetImagePaletteSize = converter.getDefinition() + .getTargetImagePaletteSize(); + RGB[] rgbs; + if (targetImagePaletteSize > 0) { + rgbs = new RGB[targetImagePaletteSize]; + for (int i = 0; i < targetImagePaletteSize; i++) { + int brightness = (255 * i) / (targetImagePaletteSize - 1); + RGB rgb = new RGB(brightness, brightness, brightness); + rgbs[i] = rgb; + } + } else { + rgbs = new RGB[0]; + } + parameters.setPaletteRGBs(rgbs); + parameters.setDisplayAspect(converter.getDefinition() + .getTargetImageDisplayAspect()); + } + } + + /** + * Find the most suitable converter, apply its defaults and preset image + * dimensions and colors based on the input file. In case of compressed + * images, the source file in the data container is replaced by the unpacked + * content. This leads to unwanted effect during reload which can only be + * removed by the introduction of separate converters for these cases. + * + * @param data + * The file converter data, not null. + * @param bytes + * The file content of the input file, not null. + * @param fileExtension + * The file extension of the input file, may be empty, not + * null. + */ + public void findDefaultFileConverter(FilesConverterData data, byte[] bytes, + String fileExtension) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + if (fileExtension == null) { + throw new IllegalArgumentException( + "Parameter 'fileExtension' must not be null."); + } + int columns; + int rows; + FilesConverterParameters parameters = data.getParameters(); + + ConverterRegistry converterRegistry = GraphicsPlugin.getInstance() + .getConverterRegistry(); + List converterDefinitions = converterRegistry + .getDefinitions(ConverterDirection.FILES_TO_IMAGE); + + // Try to match file extensions and content. + boolean converted = false; + Iterator i = converterDefinitions.iterator(); + while (i.hasNext() && !converted) { + ConverterDefinition converterDefinition = i.next(); + if (converterDefinition + .isSourceFileExtensionSupported(fileExtension)) { + Converter converter = converterRegistry + .getConverter(converterDefinition.getId()); + if (converter.canConvertToImage(bytes)) { + converter.convertToImageSizeAndPalette(data, bytes); + converted = true; + } + } + } + + // Ignore file extension and try to match content only. + if (!converted) { + i = converterDefinitions.iterator(); + while (i.hasNext() && !converted) { + ConverterDefinition converterDefinition = i.next(); + Converter converter = converterRegistry + .getConverter(converterDefinition.getId()); + if (converter.canConvertToImage(bytes)) { + converter.convertToImageSizeAndPalette(data, bytes); + converted = true; + } + } + } + + // If nothing matched, display as hires bitmap. + if (!converted) { + data.getParameters().setConverterId( + LinearBitMapGraphics8Converter.class.getName()); + applyDefaults(data); + columns = 40; + rows = (bytes.length + columns - 1) / columns; + parameters.setColumns(columns); + parameters.setRows(rows); + } + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/FilesConverterParameters.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/FilesConverterParameters.java new file mode 100644 index 00000000..aa31fe1e --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/FilesConverterParameters.java @@ -0,0 +1,550 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.GraphicsPlugin; +import com.wudsn.ide.gfx.model.ConverterDirection; +import com.wudsn.ide.gfx.model.GraphicsPropertiesSerializer; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; + +public final class FilesConverterParameters extends ConverterCommonParameters { + + /** + * Names of the attributes. + * + * @author Peter Dell + * + */ + public static final class Attributes { + + /** + * Creation is private. + */ + private Attributes() { + } + + public static final String SOURCE_FILES = "sourceFiles"; + public static final String SOURCE_FILE_PATH = "path"; + public static final String SOURCE_FILE_OFFSET = "offset"; + public static final String IMAGE_FILE_PATH = "imageFilePath"; + + public static final String COLUMNS = "columns"; + public static final String ROWS = "rows"; + + public static final String SPACING_COLOR = "spacingColor"; + public static final String SPACING_WIDTH = "spacingWidth"; + + public static final String PIXEL_TYPE = "pixelType"; + public static final String PALETTE = "palette"; + public static final String PALETTE_TYPE = "paletteType"; + public static final String PALETTE_COLORS = "paletteRGBs"; + } + + /** + * Defaults of the attributes. + * + * @author Peter Dell + * + */ + private static final class Defaults { + + /** + * Creation is private. + */ + private Defaults() { + } + + public static final String SOURCE_FILE_PATH = ""; + public static final int SOURCE_FILE_OFFSET = 0; + public static final String IMAGE_FILE_PATH = ""; + + public static final int COLUMNS = 40; + public static final int ROWS = 24; + + public static final RGB SPACING_COLOR = new RGB(0, 0, 128); + public static final int SPACING_WIDTH = 0; + + public static final PaletteType PALETTE_TYPE = PaletteType.ATARI_DEFAULT; + public static final Palette PALETTE = Palette.HIRES_1; + public static final RGB[] PALETTE_COLORS = new RGB[0]; + } + + /** + * Message ids of the attributes. + * + * @author Peter Dell + * + */ + public static final class MessageIds { + + /** + * Creation is private. + */ + private MessageIds() { + } + + public static final int SOURCE_FILE_PATH = 1010; + public static final int SOURCE_FILE_OFFSET = 1020; + public static final int IMAGE_FILE_PATH = 1030; + + public static final int SPACING_COLOR = 1100; + public static final int SPACING_WIDTH = 1101; + public static final int COLUMNS = 1102; + public static final int ROWS = 1103; + + } + + /** + * A source file. + * + * @author Peter Dell + * + */ + public static final class SourceFile { + private int id; + private String path; + private int offset; + + public SourceFile(int id) { + this.id = id; + path = Defaults.SOURCE_FILE_PATH; + offset = Defaults.SOURCE_FILE_OFFSET; + } + + public int getId() { + return id; + } + + public int getPathMessageId() { + return MessageIds.SOURCE_FILE_PATH + id; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + if (path == null) { + throw new IllegalArgumentException( + "Parameter 'path' must not be null."); + } + this.path = path; + } + + public int getOffsetMessageId() { + return MessageIds.SOURCE_FILE_OFFSET + id; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + throw new IllegalArgumentException( + "Parameter 'obj' must not be null."); + } + SourceFile other = (SourceFile) obj; + return other.id == this.id && other.path.equals(this.path) + && other.offset == this.offset; + } + + @Override + public int hashCode() { + return id + 7 * path.hashCode() + 17 * offset; + } + + } + + private int sourceFilesSize; + private List sourceFiles; + private String imageFilePath; + + private int columns; + private int rows; + + private RGB spacingColor; + private int spacingWidth; + + private PaletteType paletteType; + private Palette palette; + private RGB[] paletteRGBs; + + FilesConverterParameters() { + + int size = ConverterRegistry.MAX_SOURCE_FILES; + this.sourceFiles = new ArrayList(size); + for (int i = 0; i < size; i++) { + this.sourceFiles.add(new SourceFile(i)); + } + setDefaults(); + } + + @Override + public void setDefaults() { + super.setDefaults(); + + for (SourceFile sourceFile : sourceFiles) { + sourceFile.setPath(Defaults.SOURCE_FILE_PATH); + sourceFile.setOffset(Defaults.SOURCE_FILE_OFFSET); + } + imageFilePath = Defaults.IMAGE_FILE_PATH; + + columns = Defaults.COLUMNS; + rows = Defaults.ROWS; + spacingColor = Defaults.SPACING_COLOR; + spacingWidth = Defaults.SPACING_WIDTH; + + paletteType = Defaults.PALETTE_TYPE; + palette = Defaults.PALETTE; + paletteRGBs = Defaults.PALETTE_COLORS; + } + + @Override + public void setConverterId(String value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.converterId = value; + + ConverterDefinition converterDefinition; + converterDefinition = GraphicsPlugin.getInstance() + .getConverterRegistry() + .getDefinition(converterId, ConverterDirection.FILES_TO_IMAGE); + if (converterDefinition != null) { + sourceFilesSize = converterDefinition.getSourceFileDefinitions().size(); + } else { + sourceFilesSize = 0; + } + } + + public void setDefaultSourceFilePath(String sourceFilePath) { + if (sourceFilePath == null) { + throw new IllegalArgumentException( + "Parameter 'sourceFilePath' must not be null."); + } + for (int i = 0; i < sourceFiles.size(); i++) { + SourceFile sourceFile = sourceFiles.get(i); + sourceFile.setPath(sourceFilePath); + sourceFile.setOffset(0); + } + } + + public int getSourceFilesSize() { + return sourceFilesSize; + } + + public SourceFile getSourceFile(int sourceFileId) { + return sourceFiles.get(sourceFileId); + } + + public void setImageFilePath(String value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.imageFilePath = value; + } + + public String getImageFilePath() { + return imageFilePath; + } + + public void setColumns(int value) { + this.columns = value; + } + + public int getColumns() { + return columns; + } + + public void setRows(int value) { + this.rows = value; + } + + public int getRows() { + return rows; + } + + /** + * Sets the spacing color. + * + * @param value + * The spacing color or null to set the default + * value. + */ + public void setSpacingColor(RGB value) { + if (value == null) { + value = Defaults.SPACING_COLOR; + } + this.spacingColor = value; + } + + /** + * Gets the spacing color. + * + * @return The spacing color, not null. + */ + public RGB getSpacingColor() { + if (spacingColor == null) { + throw new IllegalStateException("Spacing color must not be null"); + } + return spacingColor; + } + + public void setSpacingWidth(int value) { + this.spacingWidth = value; + } + + public int getSpacingWidth() { + return spacingWidth; + } + + public void setPaletteType(PaletteType value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.paletteType = value; + } + + public PaletteType getPaletteType() { + return paletteType; + } + + public void setPalette(Palette value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.palette = value; + } + + public void setPaletteManual() { + switch (palette) { + case TRUE_COLOR: + palette = Palette.TRUE_COLOR; + break; + case HIRES_1: + case HIRES_2: + case HIRES_MANUAL: + palette = Palette.HIRES_MANUAL; + break; + case MULTI_1: + case MULTI_2: + case MULTI_3: + case MULTI_4: + case MULTI_5: + case MULTI_6: + case MULTI_MANUAL: + palette = Palette.MULTI_MANUAL; + break; + case GTIA_GREY_1: + case GTIA_GREY_2: + case GTIA_GREY_MANUAL: + palette = Palette.GTIA_GREY_MANUAL; + break; + } + } + + public Palette getPalette() { + return palette; + } + + /** + * Sets the array of palette RGBs. Note that the values is kept as a reference. + * + * @param value The array of palette RGBs, may be empty, not null. + */ + public void setPaletteRGBs(RGB[] value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.paletteRGBs = value; + + } + + /** + * Gets the array of palette RGBs. Note that the returned values is a reference. + * + * @return The array of palette RGBs, may be empty, not null. + */ + public RGB[] getPaletteRGBs() { + return paletteRGBs; + } + + protected final void copyTo(FilesConverterParameters target) { + if (target == null) { + throw new IllegalArgumentException( + "Parameter 'target' must not be null."); + } + super.copyTo(target); + + target.sourceFiles.clear(); + for (SourceFile sourceFile : sourceFiles) { + SourceFile targetSourceFile; + targetSourceFile = new SourceFile(sourceFile.getId()); + targetSourceFile.setPath(sourceFile.getPath()); + targetSourceFile.setOffset(sourceFile.getOffset()); + target.sourceFiles.add(targetSourceFile); + } + target.setImageFilePath(imageFilePath); + + target.setRows(rows); + target.setColumns(columns); + target.setSpacingColor(spacingColor); + target.setSpacingWidth(spacingWidth); + + target.setPaletteType(paletteType); + target.setPalette(palette); + target.setPaletteRGBs(paletteRGBs); + } + + protected final boolean equals(FilesConverterParameters target) { + if (target == null) { + throw new IllegalArgumentException( + "Parameter 'target' must not be null."); + } + boolean result; + result = super.equals(target); + result = result && target.sourceFiles.equals(sourceFiles); + result = result && target.getImageFilePath().equals(imageFilePath); + result = result && target.getRows() == rows; + result = result && target.getColumns() == columns; + result = result && target.getSpacingColor().equals(spacingColor); + result = result && target.getSpacingWidth() == spacingWidth; + + result = result && target.getPaletteType().equals(paletteType); + result = result && target.getPalette().equals(palette); + result = result && Arrays.equals(target.getPaletteRGBs(), paletteRGBs); + return result; + } + + @Override + protected final void serialize(GraphicsPropertiesSerializer serializer, + String key) { + if (serializer == null) { + throw new IllegalArgumentException( + "Parameter 'serializer' must not be null."); + } + if (key == null) { + throw new IllegalArgumentException( + "Parameter 'key' must not be null."); + } + + super.serialize(serializer, key); + + GraphicsPropertiesSerializer ownSerializer; + ownSerializer = new GraphicsPropertiesSerializer(); + + ownSerializer.writeInteger(Attributes.SOURCE_FILES, sourceFilesSize); + for (int i = 0; i < sourceFilesSize; i++) { + SourceFile sourceFile = sourceFiles.get(i); + GraphicsPropertiesSerializer innerSeralizer; + innerSeralizer = new GraphicsPropertiesSerializer(); + innerSeralizer.writeString(Attributes.SOURCE_FILE_PATH, + sourceFile.getPath()); + innerSeralizer.writeInteger(Attributes.SOURCE_FILE_OFFSET, + sourceFile.getOffset()); + ownSerializer.writeProperties(Attributes.SOURCE_FILES + "." + i, + innerSeralizer); + } + + ownSerializer.writeString(Attributes.IMAGE_FILE_PATH, imageFilePath); + + ownSerializer.writeInteger(Attributes.COLUMNS, columns); + ownSerializer.writeInteger(Attributes.ROWS, rows); + + ownSerializer.writeRGB(Attributes.SPACING_COLOR, spacingColor); + ownSerializer.writeInteger(Attributes.SPACING_WIDTH, spacingWidth); + + ownSerializer.writeEnum(Attributes.PALETTE, palette); + ownSerializer.writeEnum(Attributes.PALETTE_TYPE, paletteType); + ownSerializer.writeRGBArray(Attributes.PALETTE_COLORS, paletteRGBs); + + serializer.writeProperties(key, ownSerializer); + } + + @Override + protected final void deserialize(GraphicsPropertiesSerializer serializer, + String key) { + if (serializer == null) { + throw new IllegalArgumentException( + "Parameter 'serializer' must not be null."); + } + if (key == null) { + throw new IllegalArgumentException(); + } + super.deserialize(serializer, key); + + GraphicsPropertiesSerializer ownSerializer; + ownSerializer = new GraphicsPropertiesSerializer(); + serializer.readProperties(key, ownSerializer); + + sourceFiles.clear(); + for (int i = 0; i < ConverterRegistry.MAX_SOURCE_FILES; i++) { + SourceFile sourceFile = new SourceFile(i); + GraphicsPropertiesSerializer innerSerializer; + innerSerializer = new GraphicsPropertiesSerializer(); + ownSerializer.readProperties(Attributes.SOURCE_FILES + "." + i, + innerSerializer); + sourceFile.setPath(innerSerializer.readString( + Attributes.SOURCE_FILE_PATH, Defaults.SOURCE_FILE_PATH)); + sourceFile + .setOffset(innerSerializer.readInteger( + Attributes.SOURCE_FILE_OFFSET, + Defaults.SOURCE_FILE_OFFSET)); + sourceFiles.add(sourceFile); + } + + imageFilePath = ownSerializer.readString(Attributes.IMAGE_FILE_PATH, + Defaults.IMAGE_FILE_PATH); + + columns = ownSerializer.readInteger(Attributes.COLUMNS, + Defaults.COLUMNS); + rows = ownSerializer.readInteger(Attributes.ROWS, Defaults.ROWS); + + spacingColor = ownSerializer.readRGB(Attributes.SPACING_COLOR, + Defaults.SPACING_COLOR); + spacingWidth = ownSerializer.readInteger(Attributes.SPACING_WIDTH, + Defaults.SPACING_WIDTH); + + palette = ownSerializer.readEnum(Attributes.PALETTE, Defaults.PALETTE, + Palette.class); + paletteType = ownSerializer.readEnum(Attributes.PALETTE_TYPE, + Defaults.PALETTE_TYPE, PaletteType.class); + paletteRGBs = ownSerializer.readRGBArray(Attributes.PALETTE_COLORS, + Defaults.PALETTE_COLORS); + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ImageColorHistogram.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ImageColorHistogram.java new file mode 100644 index 00000000..afeda9b5 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ImageColorHistogram.java @@ -0,0 +1,240 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ +package com.wudsn.ide.gfx.converter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.TreeMap; + +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.base.common.NumberFactory; + +/** + * Image color histogram container. Counts the number of occurrences of a pixel + * color value in an image data. Pixel color values may be greater than 256 in + * case of direct palettes. + * + * @author Peter Dell + */ +public final class ImageColorHistogram { + + private PaletteData paletteData; + private int pixelCount; + private List pixelColors; + private List usedPixelColors; + private TreeMap pixelColorCounts; + + /** + * Created by {@link ImageConverterData}. + */ + ImageColorHistogram() { + pixelColors = Collections.emptyList(); + usedPixelColors = Collections.emptyList(); + pixelColorCounts = new TreeMap(); + } + + /** + * Clears the histogram. + */ + final void clear() { + paletteData = null; + pixelCount = 0; + pixelColors = Collections.emptyList(); + usedPixelColors = Collections.emptyList(); + pixelColorCounts.clear(); + } + + /** + * Counts the number of occurrences of a pixel value in the image data. + * + * @param imageData + * The image data or null. + */ + final void analyze(ImageData imageData) { + + clear(); + if (imageData != null) { + pixelCount = imageData.height * imageData.width; + paletteData = imageData.palette; + + if (paletteData.isDirect) { + pixelColors = Collections.emptyList(); + } else { + RGB[] rgbs = paletteData.getRGBs(); + int size = rgbs.length; + pixelColors = new ArrayList(size); + for (int i = 0; i < size; i++) { + pixelColors.add(NumberFactory.getInteger(i)); + } + pixelColors = Collections.unmodifiableList(pixelColors); + } + for (int y = 0; y < imageData.height; y++) { + for (int x = 0; x < imageData.width; x++) { + Integer pixelColor = NumberFactory.getInteger(imageData + .getPixel(x, y)); + Integer pixelColorCount = pixelColorCounts.get(pixelColor); + if (pixelColorCount == null) { + pixelColorCount = NumberFactory.getInteger(1); + } else { + pixelColorCount = NumberFactory + .getInteger(pixelColorCount.intValue() + 1); + } + pixelColorCounts.put(pixelColor, pixelColorCount); + } + } + } else { + pixelColors = Collections.emptyList(); + } + usedPixelColors = Collections.unmodifiableList(new ArrayList( + pixelColorCounts.keySet())); + } + + public boolean isDirectPalette() { + if (paletteData == null) { + return true; + } + return paletteData.isDirect; + } + + /** + * Gets the number of bits used for representing pixels. + * + * @return The number of bits used for representing pixels or 0 + * if there is no image. + */ + public int getPaletteBits() { + if (paletteData == null) { + return 0; + } + if (paletteData.isDirect) { + return Integer.bitCount(paletteData.redMask) + + Integer.bitCount(paletteData.greenMask) + + Integer.bitCount(paletteData.blueMask); + } + int length = paletteData.getRGBs().length; + int result = 0; + while (length != 0) { + result++; + length = length >>> 1; + } + return result; + } + + /** + * Gets the total number of pixels in the image data. It corresponds to the + * sum of count returned by {@link #getPixelColorCount(Integer)}. + * + * @return The total pixel color count. + */ + public int getPixelCount() { + return pixelCount; + } + + /** + * Gets the list of all pixel colors in the palette if the palette is an + * indexed palette. If the palette is not indexed, the result is an empty + * list. + * + * @return The unmodifiable list of pixel colors, sorted by their pixel + * value, may be empty, not null. + */ + public List getPalettePixelColors() { + return pixelColors; + } + + /** + * Gets the list of used pixel colors in the image data, sorted by their + * pixel value. This method work the same way for direct and indexed + * palettes. + * + * @return The unmodifiable list of pixel colors, sorted by their pixel + * value, may be empty, not null. + */ + public List getUsedPixelColors() { + return usedPixelColors; + } + + /** + * Gets the number of occurrences of a pixel color value in the image data. + * + * @param pixelColor + * The pixel color, not null. + * @return The count or 0 in case the pixel color is not + * contained in the image. + */ + public int getPixelColorCount(Integer pixelColor) { + if (pixelColor == null) { + throw new IllegalArgumentException( + "Parameter 'pixelColor' must not be null."); + } + Integer count = pixelColorCounts.get(pixelColor); + if (count == null) { + return 0; + } + return count.intValue(); + + } + + /** + * Gets the RGB value for a pixel color. This method work the same way for + * direct and indexed palettes. + * + * @param pixelColor + * The pixel color, not null. + * @return The RGB value for the pixel color, not null. + */ + public RGB getRGB(Integer pixelColor) { + if (pixelColor == null) { + throw new IllegalArgumentException( + "Parameter 'pixelColor' must not be null."); + } + + RGB rgb; + if (paletteData != null) { + // Indexed palette images may contain pixel values without + // corresponding + int intValue = pixelColor.intValue(); + if (paletteData.isDirect) { + rgb = paletteData.getRGB(intValue); + } else { + // In indexed palette images, the palette may be shorter than + // the actually used color. + RGB[] rgbs = paletteData.getRGBs(); + if (intValue < rgbs.length) { + rgb = rgbs[intValue]; + if (rgb == null) { + throw new IllegalStateException( + "Palette data has no RGB value at index " + + intValue + "."); + } + } else { + rgb = new RGB(0, 0, 0); + } + } + } else { + rgb = new RGB(0, 0, 0); + } + return rgb; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ImageConverterData.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ImageConverterData.java new file mode 100644 index 00000000..83bab275 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ImageConverterData.java @@ -0,0 +1,247 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.RGB; +import org.mozilla.javascript.NativeArray; + +import com.wudsn.ide.gfx.GraphicsPlugin; +import com.wudsn.ide.gfx.model.ConverterMode; + +public final class ImageConverterData extends ConverterCommonData { + + private ImageConverterParameters parameters; + + // Purely transient cache attributes. + private transient ConverterScriptData converterScriptData; + private transient ImageData targetImageData; + private transient List targetFilesBytes; + + ImageConverterData(ConverterData converterData) { + super(converterData); + this.parameters = converterData.getParameters().getImageConverterParameters(); + converterScriptData = new ConverterScriptData(); + targetFilesBytes = new ArrayList(0); + + } + + public ImageConverterParameters getParameters() { + return parameters; + } + + public Converter getConverter() { + ConverterRegistry converterRegistry; + Converter converter; + converterRegistry = GraphicsPlugin.getInstance().getConverterRegistry(); + converter = converterRegistry.getConverter(parameters.getConverterId()); + return converter; + } + + @Override + public boolean isCreateConversionEnabled() { + return converterData.isValid() && converterData.getConverterMode() == ConverterMode.RAW_IMAGE; + } + + @Override + public boolean isValid() { + return converterData.isValidImage(); + } + + public boolean isValidConversion() { + return converterData.isValidConversion(); + } + + @Override + public boolean isRefreshEnabled() { + return converterData.isValidImage(); + } + + public boolean isSaveFilesEnabled() { + if (converterData.isValidConversion()) { + for (byte[] bytes : targetFilesBytes) { + if (bytes != null) { + return true; + } + } + } + return false; + } + + /** + * Clears the image data. + */ + @Override + public void clear() { + super.clear(); + clearTargetFileBytes(); + } + + /** + * Gets the pixel color value for a given position. There must be an + * instance of image data set. + * + * @param x + * The x position, a non-negative integer. + * @param y + * The y position, a non-negative integer. + * + * @return The pixel color value. + * + * @throws NullPointerException + * if there is no image data at all. + */ + public int getPixel(int x, int y) { + try { + return imageData.getPixel(x, y); + } catch (IllegalArgumentException ex) { + throw new RuntimeException("Pixel (" + x + "," + y + ") is outside of the image."); + } + } + + /** + * Gets the pixel RGB value for a given position. There must be an instance + * of image data set. + * + * @param x + * The x position, a non-negative integer. + * @param y + * The y position, a non-negative integer. + * + * @return The pixel color value. + * + * @throws NullPointerException + * if there is no image data at all. + */ + public int getPixelRGB(int x, int y) { + int result = getPixel(x, y); + if (!imageData.palette.isDirect) { + RGB rgb = imageData.palette.getRGB(result); + result = rgb.red << 16 | rgb.green << 8 | rgb.blue; + } + return result; + } + + /** + * Sets the target image data, i.e. the image data after converting it to + * files and back. + * + * @param targetImageData + * The target image data or null. + */ + public void setTargetImageData(ImageData targetImageData) { + this.targetImageData = targetImageData; + } + + /** + * Gets the target image data, i.e. the image data after converting is to + * files and back. + * + * @return The target image data or null. + */ + public ImageData getTargetImageData() { + return targetImageData; + } + + /** + * Gets the container for the converter script. + * + * @return The container for the converter script, not null. + */ + public ConverterScriptData getConverterScriptData() { + return converterScriptData; + } + + /** + * Clears all target files bytes. + */ + public void clearTargetFileBytes() { + targetFilesBytes.clear(); + } + + /** + * Sets the bytes for a target file from java script. + * + * @param targetFileId + * The target field id, a non-negative integer. + * @param scriptBytes + * The bytes, may be empty or null. + */ + public void setTargetFileObject(int targetFileId, NativeArray scriptBytes) { + byte[] bytes = null; + if (scriptBytes != null) { + int length = (int) scriptBytes.getLength(); + bytes = new byte[length]; + for (int i = 0; i < length; i++) { + Object o = scriptBytes.get(i, null); + if (o instanceof Double) { + bytes[i] = ((Double) o).byteValue(); + } else if (o instanceof Integer) { + bytes[i] = ((Integer) o).byteValue(); + } + } + } + setTargetFileBytes(targetFileId, bytes); + } + + /** + * Sets the bytes for a target file. + * + * @param targetFileId + * The target field id, a non-negative integer. + * @param bytes + * The bytes, may be empty or null. + */ + public void setTargetFileBytes(int targetFileId, byte[] bytes) { + if (targetFileId < 0) { + throw new IllegalArgumentException("Parameter 'targetFileId' must not be negative. Specified value is " + + targetFileId + "."); + } + while (targetFilesBytes.size() <= targetFileId) { + targetFilesBytes.add(null); + } + targetFilesBytes.set(targetFileId, bytes); + } + + /** + * Gets the bytes for a target file. + * + * @param targetFileId + * The target field id, a non-negative integer. + * @return The bytes, may be empty or null. + */ + public byte[] getTargetFileBytes(int targetFileId) { + if (targetFileId < 0) { + throw new IllegalArgumentException("Parameter 'targetFileId' must not be negative. Specified value is " + + targetFileId + "."); + } + byte[] bytes; + if (targetFileId < targetFilesBytes.size()) { + bytes = targetFilesBytes.get(targetFileId); + } else { + bytes = null; + } + return bytes; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ImageConverterParameters.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ImageConverterParameters.java new file mode 100644 index 00000000..31ccb6a9 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/ImageConverterParameters.java @@ -0,0 +1,372 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.util.ArrayList; +import java.util.List; + +import com.wudsn.ide.gfx.GraphicsPlugin; +import com.wudsn.ide.gfx.model.ConverterDirection; +import com.wudsn.ide.gfx.model.GraphicsPropertiesSerializer; + +public final class ImageConverterParameters extends ConverterCommonParameters { + + public static final class Attributes { + + /** + * Creation is private. + */ + private Attributes() { + } + + public static final String IMAGE_FILE_PATH = "imageFilePath"; + + public static final String TARGET_FILES = "targetFiles"; + public static final String TARGET_FILE_PATH = "path"; + + public static final String USE_DEFAULT_SCRIPT = "useDefaultScript"; + public static final String SCRIPT = "script"; + + } + + private static final class Defaults { + + /** + * Creation is private. + */ + private Defaults() { + } + + public static final String IMAGE_FILE_PATH = ""; + public static final String TARGET_FILE_PATH = ""; + + public static final boolean USE_DEFAULT_SCRIPT = true; + public static final String SCRIPT = ""; + } + + public static final class MessageIds { + + /** + * Creation is private. + */ + private MessageIds() { + } + + public static final int IMAGE_FILE_PATH = 2010; + public static final int TARGET_FILE_PATH = 2020; + public static final int TARGET_FILE_OFFSET = 2030; + public static final int USE_DEFAULT_SCRIPT = 2040; + public static final int SCRIPT = 2041; + } + + public static final class TargetFile { + private int id; + private String path; + private int offset; + + public TargetFile(int id) { + this.id = id; + path = Defaults.TARGET_FILE_PATH; + } + + public int getId() { + return id; + } + + public int getPathMessageId() { + return MessageIds.TARGET_FILE_PATH + id; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + if (path == null) { + throw new IllegalArgumentException( + "Parameter 'path' must not be null."); + } + this.path = path; + } + + public int getOffsetMessageId() { + return MessageIds.TARGET_FILE_OFFSET + id; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + throw new IllegalArgumentException( + "Parameter 'obj' must not be null."); + } + TargetFile other = (TargetFile) obj; + return other.id == this.id && other.path.equals(this.path) + && other.offset == this.offset; + } + + @Override + public int hashCode() { + return id + 7 * path.hashCode() + 17 * offset; + } + + } + + private String imageFilePath; + private int targetFilesSize; + private List targetFiles; + private boolean useDefaultScript; + private String script; + + ImageConverterParameters() { + + int size = ConverterRegistry.MAX_SOURCE_FILES; + this.targetFiles = new ArrayList(size); + for (int i = 0; i < size; i++) { + this.targetFiles.add(new TargetFile(i)); + } + setDefaults(); + } + + @Override + public void setDefaults() { + super.setDefaults(); + imageFilePath = Defaults.IMAGE_FILE_PATH; + for (TargetFile targetFile : targetFiles) { + targetFile.setPath(Defaults.TARGET_FILE_PATH); + } + useDefaultScript = Defaults.USE_DEFAULT_SCRIPT; + script = Defaults.SCRIPT; + } + + @Override + public void setConverterId(String value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + + if (!value.equals(this.converterId)) + this.converterId = value; + + ConverterDefinition converterDefinition; + converterDefinition = GraphicsPlugin.getInstance() + .getConverterRegistry() + .getDefinition(converterId, ConverterDirection.IMAGE_TO_FILES); + if (converterDefinition != null) { + targetFilesSize = targetFiles.size(); + } else { + targetFilesSize = 0; + } + } + + public void setDefaultTargetFilePath(String targetFilePath) { + if (targetFilePath == null) { + throw new IllegalArgumentException( + "Parameter 'targetFilePath' must not be null."); + } + for (int i = 0; i < targetFiles.size(); i++) { + TargetFile targetFile = targetFiles.get(i); + targetFile.setPath(targetFilePath); + targetFile.setOffset(0); + } + } + + public void setImageFilePath(String value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.imageFilePath = value; + } + + public String getImageFilePath() { + return imageFilePath; + } + + public int getTargetFilesSize() { + return targetFilesSize; + } + + public TargetFile getTargetFile(int targetFileId) { + return targetFiles.get(targetFileId); + } + + /** + * Sets the indicator to use the default script + * + * @param value + * true to use the default script, + * false to use the saved script. + */ + public void setUseDefaultScript(boolean value) { + this.useDefaultScript = value; + } + + /** + * Gets the indicator to use the default script + * + * @return true to use the default script, false + * to use the saved script. + */ + public boolean isUseDefaultScript() { + return useDefaultScript; + } + + /** + * Gets the script for the conversion logic. + * + * @param value + * The script, may be empty, not null. + */ + public void setScript(String value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + this.script = value; + } + + /** + * Gets the script for the conversion logic. + * + * @return The script, may be empty, not null. + */ + public String getScript() { + if (script == null) { + throw new IllegalStateException("Field 'script' must not be null."); + } + return script; + } + + protected final void copyTo(ImageConverterParameters target) { + if (target == null) { + throw new IllegalArgumentException( + "Parameter 'target' must not be null."); + } + super.copyTo(target); + + target.setImageFilePath(imageFilePath); + target.targetFiles.clear(); + for (TargetFile targetFile : targetFiles) { + TargetFile targetTargetFile; + targetTargetFile = new TargetFile(targetFile.getId()); + targetTargetFile.setPath(targetFile.getPath()); + targetTargetFile.setOffset(targetFile.getOffset()); + target.targetFiles.add(targetTargetFile); + } + + target.setUseDefaultScript(useDefaultScript); + target.setScript(script); + } + + protected final boolean equals(ImageConverterParameters target) { + if (target == null) { + throw new IllegalArgumentException( + "Parameter 'target' must not be null."); + } + boolean result; + result = super.equals(target); + result = result && target.getImageFilePath().equals(imageFilePath); + result = result && target.targetFiles.equals(targetFiles); + result = result && target.isUseDefaultScript() == useDefaultScript; + result = result && target.getScript().equals(script); + return result; + } + + @Override + protected final void serialize(GraphicsPropertiesSerializer serializer, + String key) { + if (serializer == null) { + throw new IllegalArgumentException( + "Parameter 'serializer' must not be null."); + } + if (key == null) { + throw new IllegalArgumentException( + "Parameter 'key' must not be null."); + } + + super.serialize(serializer, key); + GraphicsPropertiesSerializer ownSerializer; + + ownSerializer = new GraphicsPropertiesSerializer(); + ownSerializer.writeString(Attributes.IMAGE_FILE_PATH, imageFilePath); + ownSerializer.writeInteger(Attributes.TARGET_FILES, targetFilesSize); + for (int i = 0; i < targetFilesSize; i++) { + TargetFile targetFile = targetFiles.get(i); + GraphicsPropertiesSerializer innerSeralizer; + innerSeralizer = new GraphicsPropertiesSerializer(); + innerSeralizer.writeString(Attributes.TARGET_FILE_PATH, + targetFile.getPath()); + ownSerializer.writeProperties(Attributes.TARGET_FILES + "." + i, + innerSeralizer); + } + + ownSerializer.writeBoolean(Attributes.USE_DEFAULT_SCRIPT, useDefaultScript); + ownSerializer.writeString(Attributes.SCRIPT, script); + + serializer.writeProperties(key, ownSerializer); + } + + @Override + protected final void deserialize(GraphicsPropertiesSerializer serializer, + String key) { + if (serializer == null) { + throw new IllegalArgumentException( + "Parameter 'serializer' must not be null."); + } + if (key == null) { + throw new IllegalArgumentException(); + } + + super.deserialize(serializer, key); + GraphicsPropertiesSerializer ownSerializer; + ownSerializer = new GraphicsPropertiesSerializer(); + serializer.readProperties(key, ownSerializer); + + imageFilePath = ownSerializer.readString(Attributes.IMAGE_FILE_PATH, + Defaults.IMAGE_FILE_PATH); + imageFilePath = ownSerializer.readString(Attributes.IMAGE_FILE_PATH, + Defaults.IMAGE_FILE_PATH); + targetFiles.clear(); + for (int i = 0; i < ConverterRegistry.MAX_TARGET_FILES; i++) { + TargetFile targetFile = new TargetFile(i); + GraphicsPropertiesSerializer innerSerializer; + innerSerializer = new GraphicsPropertiesSerializer(); + ownSerializer.readProperties(Attributes.TARGET_FILES + "." + i, + innerSerializer); + targetFile.setPath(innerSerializer.readString( + Attributes.TARGET_FILE_PATH, Defaults.TARGET_FILE_PATH)); + targetFiles.add(targetFile); + } + + useDefaultScript = ownSerializer.readBoolean( + Attributes.USE_DEFAULT_SCRIPT, Defaults.USE_DEFAULT_SCRIPT); + script = ownSerializer.readString(Attributes.SCRIPT, Defaults.SCRIPT); + + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/InverseBlock.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/InverseBlock.java new file mode 100644 index 00000000..19aba840 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/InverseBlock.java @@ -0,0 +1,70 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +/** + * Square block of character which shall be inverse + * + * @author Peter Dell + */ +public final class InverseBlock { + + private int column1; + private int column2; + private int row1; + private int row2; + private Integer inverseColor; + private boolean inverseIfConflict; + + InverseBlock(int column1, int column2, int row1, int row2, + Integer inverseColor, boolean inverseIfConflict) { + this.column1 = column1; + this.column2 = column2; + this.row1 = row1; + this.row2 = row2; + this.inverseColor = inverseColor; + this.inverseIfConflict = inverseIfConflict; + + } + + public int getColumn1() { + return column1; + } + + public int getColumn2() { + return column2; + } + + public int getRow1() { + return row1; + } + + public int getRow2() { + return row2; + } + + public Integer getInverseColor() { + return inverseColor; + } + + public boolean isInverseIfConflict() { + return inverseIfConflict; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/InverseBlockList.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/InverseBlockList.java new file mode 100644 index 00000000..c7e25a02 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/InverseBlockList.java @@ -0,0 +1,88 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.util.ArrayList; +import java.util.List; + +/** + * List of square blocks of character which shall be inverse + * + * @author Peter Dell + */ +public final class InverseBlockList { + + private List inverseBlocks; + + /** + * Creates an empty inverse block list. + */ + public InverseBlockList() { + inverseBlocks = new ArrayList(); + } + + /** + * Adds a new inverse block to the list. + * + * @param column1 + * Start column, a non-negative integer + * @param column2 + * End column, a non-negative integer + * @param row1 + * Start row, a non-negative integer + * @param row2 + * End row, a non-negative integer + * @param inverseColor + * The pixel color value which shall be used as inverse color + * @param inverseIfConflict + * true if the inverse color shall also be used in + * case of conflict + */ + public void add(int column1, int column2, int row1, int row2, + Integer inverseColor, boolean inverseIfConflict) { + inverseBlocks.add(new InverseBlock(column1, column2, row1, row2, + inverseColor, inverseIfConflict)); + } + + /** + * Get the inverse block at The sequence in which the blocks were added + * determines, the sequence in which the method checks for matches. + * + * @param column + * The column, a non-negative integer. + * @param row + * The column, a non-negative integer. + * @return The first matching inverse block, or null if no + * inverse block matches. + */ + public InverseBlock getInverseBlock(int column, int row) { + + for (InverseBlock inverseBlock : inverseBlocks) { + if (inverseBlock.getColumn1() <= column + && column <= inverseBlock.getColumn2() + && inverseBlock.getRow1() <= row + && row <= inverseBlock.getRow2()) { + return inverseBlock; + } + } + return null; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/PaletteMapper.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/PaletteMapper.java new file mode 100644 index 00000000..be34952a --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/PaletteMapper.java @@ -0,0 +1,177 @@ +package com.wudsn.ide.gfx.converter; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.base.common.NumberFactory; + +/** + * Copyright (C) 2009 - 2014 Peter + * Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * WUDSN IDE is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * WUDSN IDE. If not, see . + */ + +/** + * Palette mapper for mapping palette indices to RGB and back. The palette data + * is stored in files in the folder for the sub-package "/palettes", relative to + * the location if the palette mapper implementation class. The file content is + * loaded from the class path using the class loader. + * + * + * @since 1.6.4 + */ +public abstract class PaletteMapper { + private int palette_size; + private int[] palette_r; + private int[] palette_g; + private int[] palette_b; + private Map map; + + protected PaletteMapper(int palette_size) { + if (palette_size < 1) { + throw new IllegalArgumentException("Parameter 'palette_size' must be positive. Specified value is " + + palette_size + "."); + } + this.palette_size = palette_size; + map = new HashMap(); + palette_r = new int[palette_size]; + palette_g = new int[palette_size]; + palette_b = new int[palette_size]; + } + + public final void loadPalette(String fileName) { + if (fileName == null) { + throw new IllegalArgumentException("Parameter 'fileName' must not be null."); + } + InputStream inputStream; + Class clazz = getClass(); + inputStream = clazz.getClassLoader().getResourceAsStream( + clazz.getPackage().getName().replace('.', '/') + "/palettes/" + fileName); + if (inputStream == null) { + try { + + inputStream = new FileInputStream(fileName); + } catch (FileNotFoundException ex) { + throw new RuntimeException("File '" + fileName + "' not found or not readable", ex); + } + } + + byte[] buffer = new byte[palette_size * 3]; + int count; + do { + try { + count = inputStream.read(buffer); + } catch (IOException ex) { + throw new RuntimeException("Cannot read palette '" + fileName + "'", ex); + } + if (count > 0) { + int j = 0; + for (int i = 0; i < count; i = i + 3, j++) { + palette_r[j] = buffer[i] & 0xff; + palette_g[j] = buffer[i + 1] & 0xff; + palette_b[j] = buffer[i + 2] & 0xff; + } + } + } while (count > -1); + + map.clear(); + } + + /** + * Gets the index of an RGB value in the palette. + * + * @param rgb + * The 24-bit RGB value + * @return The palette index, or -1 is there is not + * corresponding palette index. + */ + public final int getPaletteIndex(int rgb) { + return getPaletteIndex(rgb >>> 16 & 0xff, rgb >>> 8 & 0xff, rgb & 0xff); + } + + /** + * Gets the index of an RGB value in the palette. + * + * @param r + * The 8-bit red value + * @param g + * The 8-bit green value + * @param b + * The 8-bit blue value + + * @return The palette index, or -1 is there is not + * corresponding palette index. + */ + public final int getPaletteIndex(int r, int g, int b) { + int color = r << 16 | g << 8 | b; + Integer colorKey = NumberFactory.getInteger(color); + + Integer colorValue = map.get(colorKey); + + if (colorValue == null) { + + int diff = 0x7fffffff; + int n = 0; + for (int m = 0; m < 256; m++) { + int e = (palette_r[m] - r); + int d = e * e; + e = (palette_g[m] - g); + d += e * e; + e = (palette_b[m] - b); + d += e * e; + if (d < diff) { + diff = d; + n = m; + } + } + colorValue = new Integer(n); + map.put(colorKey, colorValue); + } + return colorValue.intValue(); + + } + + /** + * Gets an Atari color with a given color code as RGB value. + * + * @param paletteIndex + * The palette index, a non-negative integer. + * @return The RGB value, not null. + */ + public final RGB getRGB(int paletteIndex) { + RGB result; + result = new RGB(palette_r[paletteIndex], palette_g[paletteIndex], palette_b[paletteIndex]); + return result; + } + + /** + * Gets an Atari color with a given color code as RGB int value. + * + * @param paletteIndex + * The palette index, a non-negative integer. + * @return The RGB color, not null. + */ + public final int getRGBColor(int paletteIndex) { + int result = palette_r[paletteIndex] << 16 | palette_g[paletteIndex] << 8 | palette_b[paletteIndex]; + return result; + } +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/Tile.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/Tile.java new file mode 100644 index 00000000..2ed22c29 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/Tile.java @@ -0,0 +1,261 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import com.wudsn.ide.base.common.NumberFactory; + +public final class Tile { + private TileSet tileSet; + private int column; + private int row; + + private int xOffset; + private int yOffset; + + private Map pixelColorCounts; + private List> linePixelColorCounts; + + private boolean inverseConflict; + + public Tile(TileSet tileSet, int column, int row) { + if (tileSet == null) { + throw new IllegalArgumentException( + "Parameter 'tileSet' must not be null."); + } + if (column < 0) { + throw new IllegalArgumentException( + "Parameter 'column' must not be negative. Specified value is " + + column + "."); + } + if (row < 0) { + throw new IllegalArgumentException( + "Parameter 'row' must not be negative. Specified value is " + + row + "."); + } + this.tileSet = tileSet; + this.column = column; + this.row = row; + + xOffset = column * tileSet.getPixelsPerColumn(); + yOffset = row * tileSet.getPixelsPerRow(); + + pixelColorCounts = new TreeMap(); + linePixelColorCounts = new ArrayList>(tileSet + .getPixelsPerRow()); + + for (int y = 0; y < tileSet.getPixelsPerRow(); y++) { + linePixelColorCounts.add(new TreeMap()); + for (int x = 0; x < tileSet.getPixelsPerColumn(); x++) { + Integer pixelColor = getPixelColor(x, y); + increment(pixelColorCounts, pixelColor); + increment(linePixelColorCounts.get(y), pixelColor); + } + } + } + + private void increment(Map pixelColorCounts, + Integer pixelColorKey) { + if (pixelColorCounts == null) { + throw new IllegalArgumentException( + "Parameter 'pixelColorCounts' must not be null."); + } + if (pixelColorKey == null) { + throw new IllegalArgumentException( + "Parameter 'pixelColorKey' must not be null."); + } + Integer pixelColorCount = pixelColorCounts.get(pixelColorKey); + if (pixelColorCount == null) { + pixelColorCount = NumberFactory.getInteger(1); + } else { + pixelColorCount = NumberFactory.getInteger(pixelColorCount + .intValue() + 1); + } + pixelColorCounts.put(pixelColorKey, pixelColorCount); + } + + public int getColumn() { + return column; + } + + public int getRow() { + return row; + } + + /** + * Gets the pixel color of a pixel in the tile. + * + * @param x + * The relative x position in the tile, a non-negative integer. + * @param y + * The relative x position in the tile, a non-negative integer. + * @return The pixel color, not null. + */ + public Integer getPixelColor(int x, int y) { + try { + return NumberFactory.getInteger(tileSet.getImageData().getPixel( + xOffset + x, yOffset + y)); + } catch (IllegalArgumentException ex) { + // throw new IllegalArgumentException("Cannot access pixel at " + // + xOffset + "+" + x + ", " + yOffset + "+" + y + ".", ex); + return NumberFactory.getInteger(0); + } + } + + public boolean hasPixelColor(Integer pixelColor) { + if (pixelColor == null) { + throw new IllegalArgumentException( + "Parameter 'pixelColor' must not be null."); + } + return getPixelColorCount(pixelColor) > 0; + } + + public int getPixelColorCount(Integer pixelColor) { + if (pixelColor == null) { + throw new IllegalArgumentException( + "Parameter 'pixelColor' must not be null."); + } + Integer pixelColorCount = pixelColorCounts.get(pixelColor); + if (pixelColorCount == null) { + return 0; + } + return pixelColorCount.intValue(); + + } + + /** + * Counts the map of distinct colors used and their count in the tile. + * + * @param ignoredPixelColors + * The array of colors to be ignored during counting or + * null. + * @return The map of distinct colors used and their count, not + * null. + */ + public Map getDistinctPixelColorCounts( + List ignoredPixelColors) { + + if (ignoredPixelColors == null) { + throw new IllegalArgumentException( + "Parameter 'ignoredPixelColors' must not be null."); + } + Map pixelColorCounts; + pixelColorCounts = new TreeMap(); + for (int y = 0; y < tileSet.getPixelsPerRow(); y++) { + for (int x = 0; x < tileSet.getPixelsPerColumn(); x++) { + Integer pixelColor = getPixelColor(x, y); + boolean ignore = false; + if (ignoredPixelColors != null + && ignoredPixelColors.contains(pixelColor)) { + ignore = true; + } + if (!ignore) { + increment(pixelColorCounts, pixelColor); + } + } + } + return pixelColorCounts; + } + + public static Integer getMajorColor(Map pixelColorCounts, + List ignoredPixelColors) { + if (pixelColorCounts == null) { + throw new IllegalArgumentException( + "Parameter 'pixelColorCounts' must not be null."); + } + if (pixelColorCounts.isEmpty()) { + throw new IllegalArgumentException( + "Parameter 'pixelColorCounts' must not be empty."); + } + Integer majorColor; + int majorColorCount; + majorColor = null; + majorColorCount = -1; + for (Map.Entry entry : pixelColorCounts.entrySet()) { + if (ignoredPixelColors == null + || !ignoredPixelColors.contains(entry.getKey())) { + if (entry.getValue().intValue() > majorColorCount) { + majorColor = entry.getKey(); + } + } + } + return majorColor; + } + + public int getLinePixelColorCount(int y, int pixelColor) { + Map pixelColorCounts = linePixelColorCounts.get(y); + Integer pixelColorCount = pixelColorCounts.get(NumberFactory + .getInteger(pixelColor)); + if (pixelColorCount == null) { + return 0; + } + return pixelColorCount.intValue(); + + } + + /** + * Counts the map of distinct colors used and their count in a specific line + * of the tile. + * + * @param y + * The line of the tile, a non-negative integer. + * @param ignoredPixelColors + * The list of colors to be ignored during counting or + * null. + * @return The map of distinct colors used and their count, not + * null. + */ + public Map getDistinctLinePixelColorCounts(int y, + List ignoredPixelColors) { + if (y < 0) { + throw new IllegalArgumentException( + "Parameter 'y' must not be negative, specified value is " + + y + "."); + } + Map pixelColorCounts; + pixelColorCounts = new TreeMap(); + for (int x = 0; x < tileSet.getPixelsPerColumn(); x++) { + Integer pixelColor = getPixelColor(x, y); + boolean ignore = false; + if (ignoredPixelColors != null + && ignoredPixelColors.contains(pixelColor)) { + ignore = true; + + } + if (!ignore) { + increment(pixelColorCounts, pixelColor); + } + } + return pixelColorCounts; + } + + public boolean isInverseConflict() { + return inverseConflict; + } + + public void setInverseConflict(boolean inverseConflict) { + this.inverseConflict = inverseConflict; + + } +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/TileSet.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/TileSet.java new file mode 100644 index 00000000..b57fb7f0 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/TileSet.java @@ -0,0 +1,240 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter; + +import org.eclipse.swt.graphics.ImageData; + +/** + * An image data divided into a rectangle of tiles. + * + * @author Peter Dell + * + */ +public final class TileSet { + + private ImageData imageData; + private int pixelsPerColumn; + private int pixelsPerRow; + + private int columns; + private int rows; + private int paletteSize; + + private Tile[][] tiles; + + /** + * Creates a new tile set. + * + * @param imageData + * The source image data, not null. + * @param pixelsPerColumn + * The number of pixels per column, a positive integer. + * @param pixelsPerRow + * The number of pixels per row, a positive integer. + */ + public TileSet(ImageData imageData, int pixelsPerColumn, int pixelsPerRow) { + if (imageData == null) { + throw new IllegalArgumentException( + "Parameter 'imageData' must not be null."); + } + if (pixelsPerColumn < 1) { + throw new IllegalArgumentException( + "Parameter 'pixelsPerColumn' must be poitive. Specified value is " + + pixelsPerColumn + "."); + } + if (pixelsPerRow < 1) { + throw new IllegalArgumentException( + "Parameter 'pixelsPerRow' must be poitive. Specified value is " + + pixelsPerRow + "."); + } + + this.imageData = imageData; + this.pixelsPerColumn = pixelsPerColumn; + this.pixelsPerRow = pixelsPerRow; + + // Round-up columns and rows + columns = (imageData.width + pixelsPerColumn - 1) / pixelsPerColumn; + rows = (imageData.height + pixelsPerRow - 1) / pixelsPerRow; + + // Create the tiles + tiles = new Tile[rows][]; + for (int r = 0; r < rows; r++) { + tiles[r] = new Tile[columns]; + for (int c = 0; c < columns; c++) { + Tile tile = new Tile(this, c, r); + tiles[r][c] = tile; + } + } + } + + /** + * Gets the source image data. + * + * @return The source image data, not null. + */ + public ImageData getImageData() { + return imageData; + } + + /** + * Gets the number of columns. + * + * @return The number of columns, a positive integer. + */ + public int getColumns() { + return columns; + } + + /** + * Gets the number of rows. + * + * @return The number of rows, a positive integer. + */ + public int getRows() { + return rows; + } + + /** + * Gets the number of pixels per column. + * + * @return The number of pixels per column, a positive integer. + */ + public int getPixelsPerColumn() { + return pixelsPerColumn; + } + + /** + * Gets the number of pixels per row. + * + * @return The number of of pixels per row, a positive integer. + */ + public int getPixelsPerRow() { + return pixelsPerRow; + } + + /** + * Gets the size of the palette. + * + * @return The size of the palette, a positive integer. + */ + public int getPaletteSize() { + return paletteSize; + } + + /** + * Gets the tile a a given location. + * + * @param column + * The column, a non-negative integer + * @param row + * The row, a non-negative integer + * @return The tile, not null. + */ + public Tile getTile(int column, int row) { + if (column < 0) { + throw new IllegalArgumentException( + "Parameter 'column' must not be negative. Specified value is " + + column + "."); + } + if (row < 0) { + throw new IllegalArgumentException( + "Parameter 'row' must not be negative. Specified value is " + + row + "."); + } + return tiles[row][column]; + } + + /** + * Create an image data instance large enough to hold the tiled source + * image. + * + * @return The tile image data, not null. + */ + public ImageData createTiledImageData() { + int width = columns * (pixelsPerColumn + 1) + 1; + int height = rows * (pixelsPerRow + 1) + 1; + ImageData tiledImageData = new ImageData(width, height, + imageData.depth, imageData.palette); + return tiledImageData; + } + + /** + * Draws bounding rectangles around the tiles of the target image data. + * + * @param targetImageData + * The target image data, not null. + * @param gridColor + * The pixel color for coloring the tile grid. + * @param inverseConflictColor + * The pixel color for coloring conflict tiles in the tile grid. + */ + public void drawTileBoundaries(ImageData targetImageData, + Integer gridColor, Integer inverseConflictColor) { + if (targetImageData == null) { + throw new IllegalArgumentException( + "Parameter 'targetImageData' must not be null."); + } + if (gridColor == null) { + throw new IllegalArgumentException( + "Parameter 'gridColor' must not be null."); + } + if (inverseConflictColor == null) { + throw new IllegalArgumentException( + "Parameter 'inverseConflictColor' must not be null."); + } + for (int r = 0; r < rows + 1; r++) { + int ty = r * (pixelsPerRow + 1); + for (int x = 0; x < targetImageData.width; x++) { + targetImageData.setPixel(x, ty, gridColor.intValue()); + } + } + for (int c = 0; c < columns + 1; c++) { + int tx = c * (pixelsPerColumn + 1); + for (int y = 0; y < targetImageData.height; y++) { + targetImageData.setPixel(tx, y, gridColor.intValue()); + } + } + + for (int r = 0; r < rows; r++) { + int ty = r * (pixelsPerRow + 1); + for (int c = 0; c < columns; c++) { + int tx = c * (pixelsPerColumn + 1); + + Tile tile = getTile(c, r); + if (tile.isInverseConflict()) { + for (int x = 0; x < pixelsPerColumn + 1; x++) { + targetImageData.setPixel(tx + x, ty, + inverseConflictColor.intValue()); + targetImageData.setPixel(tx + x, ty + pixelsPerRow + 1, + inverseConflictColor.intValue()); + } + for (int y = 0; y < pixelsPerRow + 1; y++) { + targetImageData.setPixel(tx, ty + y, + inverseConflictColor.intValue()); + targetImageData.setPixel(tx + pixelsPerColumn + 1, ty + + y, inverseConflictColor.intValue()); + + } + } + } + } + + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/apple2/HiresGraphicsConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/apple2/HiresGraphicsConverter.java new file mode 100644 index 00000000..28cf2433 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/apple2/HiresGraphicsConverter.java @@ -0,0 +1,119 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.apple2; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.FilesConverterParameters.SourceFile; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +public class HiresGraphicsConverter extends LinearBitMapConverter { + + static final int CELL_HEIGHT = 8; + static final int CELL_WIDTH = 7; + + public HiresGraphicsConverter() { + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 8184; // $1ff8 + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + int columns = 40; + int rows = 24; + RGB[] paletteColors; + paletteColors = PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.HIRES_1, null); + setImageSizeAndPalette(data, columns, rows, Palette.HIRES_1, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + data.setImageDataWidth(data.getParameters().getColumns() * CELL_WIDTH); + data.setImageDataHeight(data.getParameters().getRows() * CELL_HEIGHT); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + byte[] bytes = data.getSourceFileBytes(BIT_MAP_FILE); + if (bytes == null) { + return false; + } + + SourceFile sourceFile = data.getParameters() + .getSourceFile(BIT_MAP_FILE); + int offset = sourceFile.getOffset(); + + for (int y1 = 0; y1 < data.getParameters().getRows() * CELL_HEIGHT; y1++) { + int y = y1; + int page = y & 0x7; + int block = ((y >> 3) & 0x7); + int leaf = y >> 6; + int yindex = offset + (page * 1024) + (block * 128) + (leaf * 40); + + int x = 0; + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int xindex = yindex + x1; + if (xindex < bytes.length) { + int b = bytes[xindex]; + for (int i = 0; i < CELL_WIDTH; i++) { + if ((b & (1 << i)) != 0) { + data.setPalettePixel(x, y1, 1); + } + x++; + } + } + + } + } + return true; + + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/apple2/HiresGraphicsConverter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/apple2/HiresGraphicsConverter.js new file mode 100644 index 00000000..58fb83d1 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/apple2/HiresGraphicsConverter.js @@ -0,0 +1,32 @@ +function convertToFileData(data) { + var bytes = []; + var offset = 0; + var page = 0; + var block = 0; + var leaf = 0; + + if ( data.getImageDataWidth() !=280 + || data.getImageDataHeight()!=192 ){ + return; + } + + for (var y = 0; y < data.getImageDataHeight(); y++) { + page = y & 0x7; + block = ((y >> 3) & 0x7); + leaf = y >> 6; + offset = (page*1024) + (block*128) + (leaf*40); + + for (var x = 0; x < data.getImageDataWidth(); x = x + 7) { + var b = 0; + for (var i = 0; i < 7; i++) { + var color; + color = data.getPixel(x + i, y); + if (color != 0) { + b = b | 1 << i; + } + } + bytes[offset++] = b; + } + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari2600/AsymetricalPlayfieldConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari2600/AsymetricalPlayfieldConverter.java new file mode 100644 index 00000000..544c9ffa --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari2600/AsymetricalPlayfieldConverter.java @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari2600; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.generic.BitMapConverter; +import com.wudsn.ide.gfx.model.Palette; + +public class AsymetricalPlayfieldConverter extends BitMapConverter { + + public AsymetricalPlayfieldConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return false; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + int columns = 5; + int rows = (bytes.length + columns - 1) / columns; + setImageSizeAndPalette(data, columns, rows, Palette.HIRES_1, null); + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns()); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + return false; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari2600/AsymetricalPlayfieldConverter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari2600/AsymetricalPlayfieldConverter.js new file mode 100644 index 00000000..a3c2bd61 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari2600/AsymetricalPlayfieldConverter.js @@ -0,0 +1,40 @@ +function convertToFileData(data) { + var lineHeight = 5; // Height of a single text line + var lineSpacing = 1; // Space between two text lines + var lineFullHeight = lineHeight + lineSpacing; // Full height of a text line + var lines = java.lang.Math.floor((data.getImageDataHeight() + lineHeight) / lineFullHeight); // Number of text lines + var scanLines = lines * lineHeight; + var columnOffsets= [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5]; + var columnBits = [0x10,0x20,0x40,0x80,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x10,0x20,0x40,0x80,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80]; + var bytes = []; + var offset = 0; + + for (var l = 0; l < lines; l = l + 1) { + var y = l * lineFullHeight; + for (var m = 0; m < lineHeight; m++) { + var b = [0,0,0,0,0,0]; + for (var x = 0; x < data.getImageDataWidth() && x < 40; x = x + 1) { + var color; + + if (y+m < data.getImageDataHeight()){ + color = data.getPixel(x, y + m); + } else { + color = 0; + } + + if (color != 0) { + var o = columnOffsets[x]; + b[o] = b[o] | columnBits[x]; + } + } + bytes[offset+scanLines*0] = b[0]; + bytes[offset+scanLines*1] = b[1]; + bytes[offset+scanLines*2] = b[2]; + bytes[offset+scanLines*3] = b[3]; + bytes[offset+scanLines*4] = b[4]; + bytes[offset+scanLines*5] = b[5]; + offset =offset + 1; + } + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitPaletteMapper.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitPaletteMapper.java new file mode 100644 index 00000000..63174490 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitPaletteMapper.java @@ -0,0 +1,41 @@ +package com.wudsn.ide.gfx.converter.atari8bit; + +import com.wudsn.ide.gfx.converter.PaletteMapper; + + +/** + * Copyright (C) 2009 - 2014 Peter + * Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * WUDSN IDE is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * WUDSN IDE. If not, see . + */ + +/** + * Palette mapper for mapping Atari color values to RGB and back. + * + * @since 1.6.4 + */ +public final class Atari8BitPaletteMapper extends PaletteMapper { + + public Atari8BitPaletteMapper() { + super(256); +// loadPalette("default.act"); + loadPalette("laoo.act"); +// loadPalette("real.act"); + + + } + +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitPaletteUtility.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitPaletteUtility.java new file mode 100644 index 00000000..e0a8d145 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitPaletteUtility.java @@ -0,0 +1,233 @@ +package com.wudsn.ide.gfx.converter.atari8bit; + +/** +* Copyright (C) 2009 - 2014 Peter + * Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * WUDSN IDE is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * WUDSN IDE. If not, see . + */ + +/** + * Based on the Atari RGB converter by Mark Keates / Wrathchild. See http + * ://www.atariage.com/forums/topic/137075-rgb-to-atari-colors.
+ * See http://de.wikipedia.org/ + * wiki/Lab-Farbraum.
+ * + * @author Mark Keates + * @author Peter Dell + * + * @since 1.6.0 + */ +public class Atari8BitPaletteUtility { + + /** + * TODO Make Atari8BitPaletteUtility real tool/view + */ + static int real_pal[] = { 0x323132, 0x3f3e3f, 0x4d4c4d, 0x5b5b5b, 0x6a696a, + 0x797879, 0x888788, 0x979797, 0xa1a0a1, 0xafafaf, 0xbebebe, + 0xcecdce, 0xdbdbdb, 0xebeaeb, 0xfafafa, 0xffffff, 0x612e00, + 0x6c3b00, 0x7a4a00, 0x885800, 0x94670c, 0xa5761b, 0xb2842a, + 0xc1943a, 0xca9d43, 0xdaad53, 0xe8bb62, 0xf8cb72, 0xffd87f, + 0xffe88f, 0xfff79f, 0xffffae, 0x6c2400, 0x773000, 0x844003, + 0x924e11, 0x9e5d22, 0xaf6c31, 0xbc7b41, 0xcc8a50, 0xd5935b, + 0xe4a369, 0xf2b179, 0xffc289, 0xffcf97, 0xffdfa6, 0xffedb5, + 0xfffdc4, 0x751618, 0x812324, 0x8f3134, 0x9d4043, 0xaa4e50, + 0xb85e60, 0xc66d6f, 0xd57d7f, 0xde8787, 0xed9596, 0xfca4a5, + 0xffb4b5, 0xffc2c4, 0xffd1d3, 0xffe0e1, 0xffeff0, 0x620e71, + 0x6e1b7c, 0x7b2a8a, 0x8a3998, 0x9647a5, 0xa557b5, 0xb365c3, + 0xc375d1, 0xcd7eda, 0xdc8de9, 0xea97f7, 0xf9acff, 0xffbaff, + 0xffc9ff, 0xffd9ff, 0xffe8ff, 0x560f87, 0x611d90, 0x712c9e, + 0x7f3aac, 0x8d48ba, 0x9b58c7, 0xa967d5, 0xb877e5, 0xc280ed, + 0xd090fc, 0xdf9fff, 0xeeafff, 0xfcbdff, 0xffccff, 0xffdbff, + 0xffeaff, 0x461695, 0x5122a0, 0x6032ac, 0x6e41bb, 0x7c4fc8, + 0x8a5ed6, 0x996de3, 0xa87cf2, 0xb185fb, 0xc095ff, 0xcfa3ff, + 0xdfb3ff, 0xeec1ff, 0xfcd0ff, 0xffdfff, 0xffefff, 0x212994, + 0x2d359f, 0x3d44ad, 0x4b53ba, 0x5961c7, 0x686fd5, 0x777ee2, + 0x878ef2, 0x9097fa, 0x96a6ff, 0xaeb5ff, 0xbfc4ff, 0xcdd2ff, + 0xdae3ff, 0xeaf1ff, 0xfafeff, 0x0f3584, 0x1c418d, 0x2c509b, + 0x3a5eaa, 0x486cb7, 0x587bc5, 0x678ad2, 0x7699e2, 0x80a2eb, + 0x8fb2f9, 0x9ec0ff, 0xadd0ff, 0xbdddff, 0xcbecff, 0xdbfcff, + 0xeaffff, 0x043f70, 0x114b79, 0x215988, 0x2f6896, 0x3e75a4, + 0x4d83b2, 0x5c92c1, 0x6ca1d2, 0x74abd9, 0x83bae7, 0x93c9f6, + 0xa2d8ff, 0xb1e6ff, 0xc0f5ff, 0xd0ffff, 0xdeffff, 0x005918, + 0x006526, 0x0f7235, 0x1d8144, 0x2c8e50, 0x3b9d60, 0x4aac6f, + 0x59bb7e, 0x63c487, 0x72d396, 0x82e2a5, 0x92f1b5, 0x9ffec3, + 0xaeffd2, 0xbeffe2, 0xcefff1, 0x075c00, 0x146800, 0x227500, + 0x328300, 0x3f910b, 0x4fa01b, 0x5eae2a, 0x6ebd3b, 0x77c644, + 0x87d553, 0x96e363, 0xa7f373, 0xb3fe80, 0xc3ff8f, 0xd3ffa0, + 0xe3ffb0, 0x1a5600, 0x286200, 0x367000, 0x457e00, 0x538c00, + 0x629b07, 0x70a916, 0x80b926, 0x89c22f, 0x99d13e, 0xa8df4d, + 0xb7ef5c, 0xc5fc6b, 0xd5ff7b, 0xe3ff8b, 0xf3ff99, 0x334b00, + 0x405700, 0x4d6500, 0x5d7300, 0x6a8200, 0x7a9100, 0x889e0f, + 0x98ae1f, 0xa1b728, 0xbac638, 0xbfd548, 0xcee458, 0xdcf266, + 0xebff75, 0xfaff85, 0xffff95, 0x4b3c00, 0x584900, 0x655700, + 0x746500, 0x817400, 0x908307, 0x9f9116, 0xaea126, 0xb7aa2e, + 0xc7ba3e, 0xd5c74d, 0xe5d75d, 0xf2e56b, 0xfef47a, 0xffff8b, + 0xffff9a, 0x602e00, 0x6d3a00, 0x7a4900, 0x895800, 0x95670a, + 0xa4761b, 0xb2832a, 0xc2943a, 0xcb9d44, 0xdaac53, 0xe8ba62, + 0xf8cb73, 0xffd77f, 0xffe791, 0xfff69f, 0xffffaf, }; + + private static class RGB { + public RGB() { + + } + + int r; + int g; + int b; + } + + private static class Lab { + public Lab() { + } + + double L; + double a; + double b; + } + + static double[] calc = new double[256]; + + static RGB[] rgb; + static Lab[] cielab; + static RGB find_rgb; + static Lab find_lab; + + static void RGB2LAB(RGB c, Lab lab) { + double var_R = c.r / 255.0; // R from 0 to 255 + double var_G = c.g / 255.0; // G from 0 to 255 + double var_B = c.b / 255.0; // B from 0 to 255 + double X, Y, Z, var_X, var_Y, var_Z; + + if (var_R > 0.04045) + var_R = Math.pow(((var_R + 0.055) / 1.055), 2.4); + else + var_R = var_R / 12.92; + if (var_G > 0.04045) + var_G = Math.pow(((var_G + 0.055) / 1.055), 2.4); + else + var_G = var_G / 12.92; + if (var_B > 0.04045) + var_B = Math.pow(((var_B + 0.055) / 1.055), 2.4); + else + var_B = var_B / 12.92; + + var_R = var_R * 100.0; + var_G = var_G * 100.0; + var_B = var_B * 100.0; + + // Observer. = 2°, Illuminant = D65 + X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805; + Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722; + Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505; + + var_X = X / 95.047; // ref_X = 95.047 Observer= 2°, Illuminant= D65 + var_Y = Y / 100.000; // ref_Y = 100.000 + var_Z = Z / 108.883; // ref_Z = 108.883 + + if (var_X > 0.008856) { + var_X = Math.pow(var_X, (1.0 / 3.0)); + } else { + var_X = (7.787 * var_X) + (16.0 / 116.0); + } + if (var_Y > 0.008856) { + var_Y = Math.pow(var_Y, (1.0 / 3.0)); + } else { + var_Y = (7.787 * var_Y) + (16.0 / 116.0); + } + if (var_Z > 0.008856) { + var_Z = Math.pow(var_Z, (1.0 / 3.0)); + } else { + var_Z = (7.787 * var_Z) + (16.0 / 116.0); + } + lab.L = (116.0 * var_Y) - 16.0; + lab.a = 500.0 * (var_X - var_Y); + lab.b = 200.0 * (var_Y - var_Z); + } + + public static final void main(String[] args) { + double Dl, Dc, Dh, C1, C2, a2, b2, m = 0xFFFFFF; + double Sl, Sc, Sh, K1 = 0.045, K2 = 0.015; + int i, j = -1; + + if (args.length == 3) { + find_rgb = new RGB(); + find_lab = new Lab(); + find_rgb.r = Integer.parseInt(args[0]); + find_rgb.g = Integer.parseInt(args[1]); + find_rgb.b = Integer.parseInt(args[2]); + + /* Make an RGB table from pre-computed values */ + rgb = new RGB[256]; + for (i = 0; i < 0x10; i++) { + for (j = 0; j < 0x10; j++) { + int c = real_pal[i * 0x10 + j]; + int ir = (c >> 16) & 255; + int ig = (c >> 8) & 255; + int ib = c & 255; + rgb[i * 16 + j] = new RGB(); + rgb[i * 16 + j].r = ir; + rgb[i * 16 + j].g = ig; + rgb[i * 16 + j].b = ib; + } + } + /* Make an Lab table from the RGB table */ + cielab = new Lab[256]; + for (i = 0; i < 256; i++) { + cielab[i] = new Lab(); + RGB2LAB(rgb[i], cielab[i]); + } + /* What are we looking for */ + RGB2LAB(find_rgb, find_lab); + /* Calc distances */ + for (i = 0; i < 256; i++) { + C1 = Math.sqrt((find_lab.a * find_lab.a) + + (find_lab.b * find_lab.b)); + C2 = Math.sqrt((cielab[i].a * cielab[i].a) + + (cielab[i].b * cielab[i].b)); + Sl = 1.0; + Sc = 1.0 + K1 * C1; + Sh = 1.0 + K2 * C1; + Dl = find_lab.L - cielab[i].L; + Dc = C1 - C2; + a2 = find_lab.a - cielab[i].a; + a2 = a2 * a2; + b2 = find_lab.b - cielab[i].b; + b2 = b2 * b2; + Dh = Math.sqrt(a2 + b2 - (Dc * Dc)); + calc[i] = (Dl / Sl) * (Dl / Sl); + calc[i] += (Dc / Sc) * (Dc / Sc); + calc[i] += (Dh / Sh) * (Dh / Sh); + } + + for (i = 0; i < 256; i++) { + if (calc[i] < m) { + m = calc[i]; + j = i; + } + } + +// System.out.printf("R=%3d G=%3d B=%3d : $%02X Hue = %d Lum = %d\n", +// find_rgb.r, find_rgb.g, find_rgb.b, j, j / 16, j % 16); + } else { + System.out + .printf("Format:rgb2a8 Red Green Blue\n(values between 0 and 255)\n"); + } + + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitPaletteUtility2.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitPaletteUtility2.java new file mode 100644 index 00000000..4b067210 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitPaletteUtility2.java @@ -0,0 +1,361 @@ +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Rectangle; + +// TODO Class Atari8BitPaletteUtility2 is currently not used +public class Atari8BitPaletteUtility2 { + + private final int PAL_ENTRIES_NO = 256; + private final int BAR_LINES_NO = 16; + private final int BAR_ENTRIES_NO = (PAL_ENTRIES_NO / BAR_LINES_NO); + + static class RGB { + int R, G, B; + + public static RGB FromArgb(int r1, int g1, int b1) { + RGB color = new RGB(); + color.R = r1; + color.G = g1; + color.B = b1; + return color; + } + } + + private RGB[] actual_pal = new RGB[PAL_ENTRIES_NO]; + + class LAB { + public double L; + public double a; + public double b; + } + + private LAB[] cielab = new LAB[PAL_ENTRIES_NO]; + + private int min_y = 0, max_y = 0xf0; + private int colintens = 100; + private int colshift = 30; + + // public int BlackLevel + // { + // get { return min_y; } + // set { min_y = value; CalcPaletteFromSettings(); Highlight = + // highlightColor; } + // } + // + // public int WhiteLevel + // { + // get { return max_y; } + // set { max_y = value; CalcPaletteFromSettings(); Highlight = + // highlightColor; } + // } + // + // public int Saturation + // { + // get { return colintens; } + // set { colintens = value; CalcPaletteFromSettings(); Highlight = + // highlightColor; } + // } + // + // public int ColorShift + // { + // get { return colshift; } + // set { colshift = value; CalcPaletteFromSettings(); Highlight = + // highlightColor; } + // } + + private static int[] real_pal = { 0x323132, 0x3f3e3f, 0x4d4c4d, 0x5b5b5b, + 0x6a696a, 0x797879, 0x888788, 0x979797, 0xa1a0a1, 0xafafaf, + 0xbebebe, 0xcecdce, 0xdbdbdb, 0xebeaeb, 0xfafafa, 0xffffff, + 0x612e00, 0x6c3b00, 0x7a4a00, 0x885800, 0x94670c, 0xa5761b, + 0xb2842a, 0xc1943a, 0xca9d43, 0xdaad53, 0xe8bb62, 0xf8cb72, + 0xffd87f, 0xffe88f, 0xfff79f, 0xffffae, 0x6c2400, 0x773000, + 0x844003, 0x924e11, 0x9e5d22, 0xaf6c31, 0xbc7b41, 0xcc8a50, + 0xd5935b, 0xe4a369, 0xf2b179, 0xffc289, 0xffcf97, 0xffdfa6, + 0xffedb5, 0xfffdc4, 0x751618, 0x812324, 0x8f3134, 0x9d4043, + 0xaa4e50, 0xb85e60, 0xc66d6f, 0xd57d7f, 0xde8787, 0xed9596, + 0xfca4a5, 0xffb4b5, 0xffc2c4, 0xffd1d3, 0xffe0e1, 0xffeff0, + 0x620e71, 0x6e1b7c, 0x7b2a8a, 0x8a3998, 0x9647a5, 0xa557b5, + 0xb365c3, 0xc375d1, 0xcd7eda, 0xdc8de9, 0xea97f7, 0xf9acff, + 0xffbaff, 0xffc9ff, 0xffd9ff, 0xffe8ff, 0x560f87, 0x611d90, + 0x712c9e, 0x7f3aac, 0x8d48ba, 0x9b58c7, 0xa967d5, 0xb877e5, + 0xc280ed, 0xd090fc, 0xdf9fff, 0xeeafff, 0xfcbdff, 0xffccff, + 0xffdbff, 0xffeaff, 0x461695, 0x5122a0, 0x6032ac, 0x6e41bb, + 0x7c4fc8, 0x8a5ed6, 0x996de3, 0xa87cf2, 0xb185fb, 0xc095ff, + 0xcfa3ff, 0xdfb3ff, 0xeec1ff, 0xfcd0ff, 0xffdfff, 0xffefff, + 0x212994, 0x2d359f, 0x3d44ad, 0x4b53ba, 0x5961c7, 0x686fd5, + 0x777ee2, 0x878ef2, 0x9097fa, 0x96a6ff, 0xaeb5ff, 0xbfc4ff, + 0xcdd2ff, 0xdae3ff, 0xeaf1ff, 0xfafeff, 0x0f3584, 0x1c418d, + 0x2c509b, 0x3a5eaa, 0x486cb7, 0x587bc5, 0x678ad2, 0x7699e2, + 0x80a2eb, 0x8fb2f9, 0x9ec0ff, 0xadd0ff, 0xbdddff, 0xcbecff, + 0xdbfcff, 0xeaffff, 0x043f70, 0x114b79, 0x215988, 0x2f6896, + 0x3e75a4, 0x4d83b2, 0x5c92c1, 0x6ca1d2, 0x74abd9, 0x83bae7, + 0x93c9f6, 0xa2d8ff, 0xb1e6ff, 0xc0f5ff, 0xd0ffff, 0xdeffff, + 0x005918, 0x006526, 0x0f7235, 0x1d8144, 0x2c8e50, 0x3b9d60, + 0x4aac6f, 0x59bb7e, 0x63c487, 0x72d396, 0x82e2a5, 0x92f1b5, + 0x9ffec3, 0xaeffd2, 0xbeffe2, 0xcefff1, 0x075c00, 0x146800, + 0x227500, 0x328300, 0x3f910b, 0x4fa01b, 0x5eae2a, 0x6ebd3b, + 0x77c644, 0x87d553, 0x96e363, 0xa7f373, 0xb3fe80, 0xc3ff8f, + 0xd3ffa0, 0xe3ffb0, 0x1a5600, 0x286200, 0x367000, 0x457e00, + 0x538c00, 0x629b07, 0x70a916, 0x80b926, 0x89c22f, 0x99d13e, + 0xa8df4d, 0xb7ef5c, 0xc5fc6b, 0xd5ff7b, 0xe3ff8b, 0xf3ff99, + 0x334b00, 0x405700, 0x4d6500, 0x5d7300, 0x6a8200, 0x7a9100, + 0x889e0f, 0x98ae1f, 0xa1b728, 0xbac638, 0xbfd548, 0xcee458, + 0xdcf266, 0xebff75, 0xfaff85, 0xffff95, 0x4b3c00, 0x584900, + 0x655700, 0x746500, 0x817400, 0x908307, 0x9f9116, 0xaea126, + 0xb7aa2e, 0xc7ba3e, 0xd5c74d, 0xe5d75d, 0xf2e56b, 0xfef47a, + 0xffff8b, 0xffff9a, 0x602e00, 0x6d3a00, 0x7a4900, 0x895800, + 0x95670a, 0xa4761b, 0xb2832a, 0xc2943a, 0xcb9d44, 0xdaac53, + 0xe8ba62, 0xf8cb73, 0xffd77f, 0xffe791, 0xfff69f, 0xffffaf, }; + + private int highlightIndex = -1; + + + // public short A8Hue + // { + // get { return (short)(highlightIndex >> 4); } + // } + // + // public short A8Saturation + // { + // get { return (short)(highlightIndex & 15); } + // } + + + public int CalcHighlightLAB(RGB c) { + double[] calc = new double[PAL_ENTRIES_NO]; + double l2, a2, b2, m = 0xFFFFFF; + int i, j = -1; + LAB lab = new LAB(); + + log("Looking for: R=" + c.R + ", G=" + c.G + ", B=" + c.B); + RGB2LAB(c, lab); + log("Looking for: L=" + lab.L + ", a=" + lab.a + ", b=" + lab.b); + + for (i = 0; i < PAL_ENTRIES_NO; i++) { + l2 = lab.L - cielab[i].L; + l2 = l2 * l2; + a2 = lab.a - cielab[i].a; + a2 = a2 * a2; + b2 = lab.b - cielab[i].b; + b2 = b2 * b2; + calc[i] = l2 + a2 + b2; + } + + for (i = 0; i < PAL_ENTRIES_NO; i++) { + log("Distance to: L=" + cielab[i].L + ", a=" + cielab[i].a + ", b=" + + cielab[i].b + " is " + calc[i]); + if (calc[i] < m) { + m = calc[i]; + j = i; + log(" : New minimum!"); + } else if (calc[i] == m) { + log(" : Equal min!"); + } else { + log(""); + } + } + + log("Closest Color: m=" + m + " (R=" + actual_pal[j].R + ", G=" + + actual_pal[j].G + ", B=" + actual_pal[j].B + ")"); + + return j; + } + + public int CalcHighlightRGB(RGB c) { + long[] calc = new long[PAL_ENTRIES_NO]; + long r2, g2, b2, m = 0xFFFFFF, mg = 0xFFFFFF; + int i, j = -1, k = -1; + + log("Looking for: R=" + c.R + ", G=" + c.G + ", B=" + c.B); + for (i = 0; i < PAL_ENTRIES_NO; i++) { + // (R-r)*(R-r) + (G-g)*(G-g) + (B-b)*(B-b) + r2 = c.R - actual_pal[i].R; + r2 = r2 * r2; + g2 = c.G - actual_pal[i].G; + g2 = g2 * g2; + b2 = c.B - actual_pal[i].B; + b2 = b2 * b2; + // calc[i] = (((512+rm)*r2)>>8) + 4*g2 + (((767-rm)*b2)>>8); + calc[i] = (2 * r2) + (4 * g2) + (3 * b2); + } + + for (i = 0; i < 16; i++) { + log("Distance to: R=" + actual_pal[i].R + ", G=" + actual_pal[i].G + + ", B=" + actual_pal[i].B + " is " + calc[i]); + if (calc[i] < mg) { + mg = calc[i]; + k = i; + log(" : New minimum!"); + } else if (calc[i] == mg) { + log(" : Equal min!"); + } else { + log(""); + } + } + + for (i = 16; i < 256; i++) { + log("Distance to: R=" + actual_pal[i].R + ", G=" + actual_pal[i].G + + ", B=" + actual_pal[i].B + " is " + calc[i]); + if (calc[i] < m) { + m = calc[i]; + j = i; + log(" : New minimum!"); + } else if (calc[i] == m) { + log(" : Equal min!"); + } else { + log(""); + } + } + + log("Closest Grey: mg=" + mg + " (R=" + actual_pal[k].R + ", G=" + + actual_pal[k].G + ", B=" + actual_pal[k].B + ")"); + log("Closest Color: m=" + m + " (R=" + actual_pal[j].R + ", G=" + + actual_pal[j].G + ", B=" + actual_pal[j].B + ")"); + + return j; // (mg < m) ? k : j; + } + + private void log(String string) { + System.out.println(string); + + } + + void CalcPaletteFromSettings() { + int i, j; + /* Make an RGB table from computed values */ + for (i = 0; i < 0x10; i++) { + int r, b; + double angle; + + if (i == 0) { + r = b = 0; + } else { + angle = Math.PI * (i * (1.0 / 7) - colshift * 0.01); + r = (int) (Math.cos(angle) * colintens); + b = (int) (Math.cos(angle - Math.PI * (2.0 / 3)) * colintens); + } + for (j = 0; j < 0x10; j++) { + int y, r1, g1, b1; + + y = (max_y * j + min_y * (0xf - j)) / 0xf; + r1 = y + r; + g1 = y - r - b; + b1 = y + b; + if (r1 > 0xff) + r1 = 0xff; + if (r1 < 0) + r1 = 0; + if (g1 > 0xff) + g1 = 0xff; + if (g1 < 0) + g1 = 0; + if (b1 > 0xff) + b1 = 0xff; + if (b1 < 0) + b1 = 0; + actual_pal[i * 16 + j] = RGB.FromArgb(r1, g1, b1); + } + } + } + + public void AssignPalette(int[] new_pal) { + for (int i = 0; i < actual_pal.length; i++) { + int c = new_pal[i]; + int r = (c >> 16) & 255; + int g = (c >> 8) & 255; + int b = c & 255; + actual_pal[i] = RGB.FromArgb(r, g, b); + } + CalcLAB(); + } + + private void RGB2LAB(RGB c, LAB lab) { + double var_R = c.R / 255.0; // R from 0 to 255 + double var_G = c.G / 255.0; // G from 0 to 255 + double var_B = c.B / 255.0; // B from 0 to 255 + + if (var_R > 0.04045) + var_R = Math.pow(((var_R + 0.055) / 1.055), 2.4); + else + var_R = var_R / 12.92; + if (var_G > 0.04045) + var_G = Math.pow(((var_G + 0.055) / 1.055), 2.4); + else + var_G = var_G / 12.92; + if (var_B > 0.04045) + var_B = Math.pow(((var_B + 0.055) / 1.055), 2.4); + else + var_B = var_B / 12.92; + + var_R = var_R * 100.0; + var_G = var_G * 100.0; + var_B = var_B * 100.0; + + // Observer. = 2°, Illuminant = D65 + double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805; + double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722; + double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505; + + double var_X = X / 95.047; // ref_X = 95.047 Observer= 2°, Illuminant= + // D65 + double var_Y = Y / 100.000; // ref_Y = 100.000 + double var_Z = Z / 108.883; // ref_Z = 108.883 + + if (var_X > 0.008856) + var_X = Math.pow(var_X, (1.0 / 3.0)); + else + var_X = (7.787 * var_X) + (16.0 / 116.0); + if (var_Y > 0.008856) + var_Y = Math.pow(var_Y, (1.0 / 3.0)); + else + var_Y = (7.787 * var_Y) + (16.0 / 116.0); + if (var_Z > 0.008856) + var_Z = Math.pow(var_Z, (1.0 / 3.0)); + else + var_Z = (7.787 * var_Z) + (16.0 / 116.0); + + lab.L = (116.0 * var_Y) - 16.0; + lab.a = 500.0 * (var_X - var_Y); + lab.b = 200.0 * (var_Y - var_Z); + } + + private void CalcLAB() { + for (int i = 0; i < PAL_ENTRIES_NO; i++) { + RGB2LAB(actual_pal[i], cielab[i]); + } + } + + public Atari8BitPaletteUtility2() { + AssignPalette(real_pal); + } + + public void MyColorView_Paint(GC gc) { + int width=100; + int height = 100; + + int nWidth = (width - BAR_ENTRIES_NO) / BAR_ENTRIES_NO; + int nHeight = (height - BAR_LINES_NO) / BAR_LINES_NO; + + int nOffsetX = (width - (nWidth + 1) * BAR_ENTRIES_NO) / 3 + 1; + int nOffsetY = (height - (nHeight + 1) * BAR_LINES_NO) / 3 + 1; + + for (int i = 0; i < BAR_LINES_NO; i++) { + for (int j = 0; j < BAR_ENTRIES_NO; j++) { + int offset = i * BAR_ENTRIES_NO + j; + Rectangle rect = new Rectangle(nOffsetX + j * nWidth + j, + nOffsetY + i * nHeight + i, nWidth, nHeight); +// gc.setForeground(actual_pal[offset]); + gc.fillRectangle(rect); + + if (offset == highlightIndex) { + rect = new Rectangle(rect.x - 1, + rect.y - 1, rect.width + 1, + rect.height + 1); +// gc.setForeground(Color.BLACK); + gc.fillRectangle(rect); + } + } + } + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitUtility.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitUtility.java new file mode 100644 index 00000000..47a4300b --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/Atari8BitUtility.java @@ -0,0 +1,299 @@ +package com.wudsn.ide.gfx.converter.atari8bit; + +/** +* Copyright (C) 2009 - 2014 Peter + * Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * WUDSN IDE is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * WUDSN IDE. If not, see . + */ + +/** + * Utility class for Atari 8-bit specifics. + * + * @since 1.6.0 + */ +public final class Atari8BitUtility { + + /** + * Mapping of the 4 bit pixel values to the corresponding color register. + * Make sure not to modify contents of this array. + */ + public final static int[] GRAPHICS_10_REGISTERS = { 0, 1, 2, 3, 4, 5, 6, 7, + 8, 8, 8, 8, 4, 5, 6, 7 }; + + /** + * Creation is private. + * + * @since 1.6.0 + */ + private Atari8BitUtility() { + + } + + /** + * Gets a word stored lo/hi order. + * + * @param bytes + * The byte array, not empty and not null. + * @param offset + * The offset within the byte array, a non-negative integer. + * @return The length of the block header, a non-negative integer. + * + * @since 1.6.0 + */ + public static int getWord(byte[] bytes, int offset) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return (bytes[offset] & 0xff) | ((bytes[offset + 1] & 0xff) << 8); + } + + /** + * Gets the length of a binary COM block header within a byte array. + * + * @param bytes + * The byte array, may be empty, not null. + * @param offset + * The offset within the byte array, a non-negative integer. + * @return The length of the block header or -1 if there is no + * valid block at the given offset. + * + * @since 1.6.0 + */ + public static int getLengthFromBinaryHeader(byte[] bytes, int offset) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + if (offset < 0) { + throw new IllegalArgumentException( + "Parameter 'offset' must not be negative, specified value is " + + offset + "."); + } + if (bytes.length >= offset + 6 && (bytes[offset + 0] & 0xff) == 0xff + && (bytes[offset + 1] & 0xff) == 0xff) { + int startAddress = getWord(bytes, offset + 2); + int endAddress = getWord(bytes, offset + 4); + int length = endAddress - startAddress + 1; + return length; + } + return -1; + } + + /** + * Unpack a Koala Painter compressed picture. + * + * @param data + * The byte array with the packed data, may be empty, not + * null. + * @param dataOffset + * The offset within data to start unpacking, a non-negative + * integer. + * @param dataLength + * The length of the data to be unpacked, a positive integer. + * @param cprtype + * The CPR packing type, either 0,1 or 2. + * @param unpackedData + * The byte array for the unpack data, must be 7680 bytes long. + * @return true if the data was unpacked successfully, + * false otherwise. + * + * @since 1.6.0 + */ + public static boolean unpackKoala(byte[] data, int dataOffset, + int dataLength, int cprtype, byte[] unpackedData) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (dataOffset < 0) { + throw new IllegalArgumentException( + "Parameter 'dataOffset' must not be negative. Specified value is " + + dataOffset + "."); + } + if (dataLength < 1) { + throw new IllegalArgumentException( + "Parameter 'dataLength' must be positive. Specified value is " + + dataLength + "."); + } + int i; + int d; + switch (cprtype) { + case 0: + if (dataLength != 7680) { + return false; + } + System.arraycopy(data, dataOffset, unpackedData, 0, 7680); + return true; + case 1: + case 2: + break; + default: + return false; + } + + i = 0; + d = dataOffset; + int dataEnd = d + dataLength; + for (;;) { + int c; + int len; + int b; + c = data[d++] & 0xff; + if (d > dataEnd) { + return false; + } + len = c & 0x7f; + if (len == 0) { + int h; + h = data[d++] & 0xff; + if (d > dataEnd) { + return false; + } + len = data[d++] & 0xff; + + if (d > dataEnd) { + return false; + } + len += h << 8; + if (len == 0) { + return false; + } + } + + b = -1; + do { + /* + * get byte of uncompressed block or if starting RLE block + */ + if (c >= 0x80 || b < 0) { + b = data[d++] & 0xff; + if (d > dataEnd) { + return false; + } + } + unpackedData[i] = (byte) b; + /* return if last byte written */ + if (i >= 7679) { + return true; + } + if (cprtype == 2) { + i++; + } else { + i += 80; + if (i >= 7680) { + /* + * if in line 192, back to odd lines in the same column; + * if in line 193, go to even lines in the next column + */ + i -= (i < 7720) ? 191 * 40 : 193 * 40 - 1; + } + } + } while (--len > 0); + } + } + + /** + * Unpack a compressed CIN picture. + * + * @param data + * The byte array with the packed data, may be empty, not + * null. + * @param dataOffset + * The offset within data to start unpacking, a non-negative + * integer. + * @param dataLength + * The length of the data to be unpacked, a positive integer. + * @param step + * The number of "columns", a non-negative integer. + * @param count + * The number of "lines", a non-negative integer. + * @param unpackedData + * The byte array for the unpack data, must be 7680 bytes long. + * @param unpackedDataOffset + * The offset within unpackedData to start unpacking, a + * non-negative integer. + * @return true if the data was unpacked successfully, + * false otherwise. + * + * @since 1.6.0 + */ + public static boolean unpackCCI(byte data[], int dataOffset, + int dataLength, int step, int count, byte unpackedData[], + int unpackedDataOffset) { + int i = 0; + int d = 2; + int size = step * count; + int block_count = getWord(data, dataOffset); + while (block_count > 0) { + int c; + int len; + int b; + if (d > dataLength) { + return false; + } + c = data[dataOffset + d++] & 0xff; + len = (c & 0x7f) + 1; + b = -1; + do { + /* + * get byte if uncompressed block or if starting RLE block + */ + if (c < 0x80 || b < 0) { + if (d > dataLength) { + return false; + } + b = data[dataOffset + d++] & 0xff; + } + unpackedData[unpackedDataOffset + i] = (byte) b; + /* return if last byte written */ + if (i >= size - 1) { + return true; + } + i += step; + if (i >= size) { + i -= size - 1; + } + } while (--len > 0); + block_count--; + } + if (d == dataLength) { + return true; + } + return false; + } + + /** + * Determines if a byte array represents a valid Atari charset. + * + * @param bytes + * The byte array, may be empty, not null. + * @return true if the byte array represents a valid Atari + * charset, false otherwise. + * + * @since 1.6.0 + */ + public static boolean isAtariCharset(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 1024 + || (bytes.length == 1024 + 6 && Atari8BitUtility + .getLengthFromBinaryHeader(bytes, 0) == 1024); + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/CharMapGraphics12Converter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/CharMapGraphics12Converter.java new file mode 100644 index 00000000..c264e672 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/CharMapGraphics12Converter.java @@ -0,0 +1,308 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.eclipse.swt.graphics.ImageData; + +import com.wudsn.ide.base.common.NumberFactory; +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.ImageConverterData; +import com.wudsn.ide.gfx.converter.InverseBlock; +import com.wudsn.ide.gfx.converter.InverseBlockList; +import com.wudsn.ide.gfx.converter.Tile; +import com.wudsn.ide.gfx.converter.TileSet; +import com.wudsn.ide.gfx.converter.c64.C64Utility; +import com.wudsn.ide.gfx.converter.generic.CharMapConverter; +import com.wudsn.ide.gfx.converter.generic.CharMapMultiColorConverter; + +public class CharMapGraphics12Converter extends + CharMapMultiColorConverter { + + private static final Integer PF1 = NumberFactory.getInteger(1); + private static final Integer PF2 = NumberFactory.getInteger(2); + private static final Integer PF3 = NumberFactory.getInteger(3); + + public CharMapGraphics12Converter() { + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() + * (8 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight(data.getParameters().getRows() + * (8 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + return false; + + } + + + public static void convertToFileData(ImageConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + int pixelPerColumn = 4; + int pixelPerRow = 8; + + TileSet tileSet; + tileSet = new TileSet(data.getImageData(), pixelPerColumn, pixelPerRow); + + int screenWidth = 48; + int rowsPerCharset = 3; + + // If the actual image is larger that the screen with, it cannot be + // processed.. + if (tileSet.getColumns() > screenWidth) { + data.setTargetImageData(null); + } + + // If the actual image is smaller that the screen with, it shall be + // centered. + int screenOffset = (screenWidth - tileSet.getColumns()) / 2; + + boolean effect = data.getParameters().getConverterId() + .equals(CharMapGraphics12Converter.class.getName()); + + int charSets = (tileSet.getRows() + rowsPerCharset - 1) + / rowsPerCharset; + byte[] screenBuffer = new byte[tileSet.getRows() * screenWidth]; + byte[] charSetBuffer = new byte[1024 * charSets]; + + Integer gridColor = C64Utility.PINK; + Integer inverseConflictColor = C64Utility.YELLOW; + + ImageData targetImageData = tileSet.createTiledImageData(); + + int screenCharacter = 0; + int charSetCount = -1; + for (int r = 0; r < tileSet.getRows(); r++) { + if (r % rowsPerCharset == 0) { + charSetCount++; + int charSetBufferOffset = charSetCount * 1024; + for (int i = 0; i < pixelPerRow; i++) { + charSetBuffer[charSetBufferOffset + i] = (byte) 0x55; + } + screenCharacter = 1; + + } + + for (int c = 0; c < tileSet.getColumns(); c++) { + + // Create and analyze tile + Tile tile = tileSet.getTile(c, r); + + Map pixelMapping; + List ignoredPixelColors; + InverseBlockList inverseBlockList; + pixelMapping = new TreeMap(); + ignoredPixelColors = new ArrayList(); + inverseBlockList = new InverseBlockList(); + + // TODO Make hard coded mapping real parameters + if (System.getProperty("user.name").equals("d025328")) { + if (r < 10 || r > 19) { + getTileMapping1(pixelMapping, ignoredPixelColors, + inverseBlockList); + } else { + + getTileMapping2(pixelMapping, ignoredPixelColors, + inverseBlockList); + } + } + + InverseBlock inverseBlock; + inverseBlock = inverseBlockList.getInverseBlock(c, r); + + int inverseCharacter = 0x00; + Integer inverseColor; + if (inverseBlock != null) { + inverseColor = inverseBlock.getInverseColor(); + + if (tile.hasPixelColor(inverseColor)) { + // Collect all mappings which map to PF3. + List pf3colors; + pf3colors = new ArrayList(); + for (Map.Entry entry : pixelMapping + .entrySet()) { + if (entry.getValue().equals(PF3)) { + pf3colors.add(entry.getKey()); + } + } + + // Set inverse color to PF3 which becomes PF4 using the + // inverse + pixelMapping.put(inverseColor, PF3); + + for (Integer pf3Color : pf3colors) { + if (tile.hasPixelColor(pf3Color)) { + tile.setInverseConflict(true); + break; + } + } + if (!tile.isInverseConflict()) { + // No conflict + ignoredPixelColors.add(inverseColor); + inverseCharacter = 0x80; + } else { + if (inverseBlock.isInverseIfConflict()) { + inverseCharacter = 0x80; + } else { + inverseCharacter = 0x00; + } + } + } + } else { + inverseColor = null; + } + + screenBuffer[r * screenWidth + c + screenOffset] = (byte) (screenCharacter + inverseCharacter); + int charSetBufferOffset = charSetCount * 1024 + 8 + * (screenCharacter & 0x7f); + screenCharacter++; + + // Draw/copy tile. + Map pixelColorCounts = tile + .getDistinctPixelColorCounts(ignoredPixelColors); + + Integer lastRowMajorColor = null; + + for (int r1 = 0; r1 < pixelPerRow; r1++) { + int my = r * (pixelPerRow + 1) + r1 + 1; + + Map rowPixelColorCounts = tile + .getDistinctLinePixelColorCounts(r1, + ignoredPixelColors); + + int charSetByte = 0; + for (int c1 = 0; c1 < pixelPerColumn; c1++) { + int mx = c * (pixelPerColumn + 1) + c1 + 1; + + Integer color = tile.getPixelColor(c1, r1); + + Integer pixelBits = pixelMapping.get(color); + + if (effect) { + if (pixelColorCounts.size() == 0) { + color = C64Utility.BLACK; + } else if (pixelColorCounts.size() == 1) { + color = Tile.getMajorColor(pixelColorCounts, + ignoredPixelColors); + } else if (rowPixelColorCounts.size() == 0) { + color = lastRowMajorColor; + } else if (rowPixelColorCounts.size() == 1) { + color = Tile.getMajorColor(rowPixelColorCounts, + ignoredPixelColors); + lastRowMajorColor = color; + } + + if (color == null) { + color = C64Utility.BLACK; + } + if (color == inverseColor) { + color = inverseConflictColor; + } + } + + targetImageData.setPixel(mx, my, color.intValue()); + charSetByte = (charSetByte << 2); + if (pixelBits != null) { + charSetByte |= pixelBits.intValue(); + } + } + charSetBuffer[charSetBufferOffset + r1] = (byte) charSetByte; + } + } + + tileSet.drawTileBoundaries(targetImageData, gridColor, + inverseConflictColor); + } + + data.setTargetFileBytes(CharMapConverter.CHAR_SET_FILE, charSetBuffer); + data.setTargetFileBytes(CharMapConverter.CHAR_MAP_FILE, screenBuffer); + + data.setTargetImageData(targetImageData); + } + + private static void getTileMapping2(Map pixelMapping, + List ignoredPixelColors, InverseBlockList inverseBlockList) { + pixelMapping.put(C64Utility.BLACK, PF1); + pixelMapping.put(C64Utility.WHITE, PF2); + pixelMapping.put(C64Utility.RED, PF3); + pixelMapping.put(C64Utility.LIGHT_GREEN, PF3); + + ignoredPixelColors.add(C64Utility.BLACK); + ignoredPixelColors.add(C64Utility.WHITE); + // ignoredPixelColors.add(C64Utility.DARK_GRAY); + ignoredPixelColors.add(C64Utility.LIGHT_GREEN); + + // Blue floor + inverseBlockList.add(0, 39, 8, 19, C64Utility.LIGHT_BLUE, true); + + // Brown Ship + inverseBlockList.add(16, 18, 5, 7, C64Utility.BROWN, true); + // Blue Planet + inverseBlockList.add(0, 39, 0, 6, C64Utility.LIGHT_BLUE, true); + + // Cybernoid + // inverseBlockList.add(0, + // 39, 8, + // 19, + // C64Utility.LIGHT_RED); + // // Red + + // Yellow Explosion + inverseBlockList.add(4, 11, 20, 24, C64Utility.BROWN, false); + } + + private static void getTileMapping1(Map pixelMapping, + List ignoredPixelColors, InverseBlockList inverseBlockList) { + pixelMapping.put(C64Utility.BLACK, PF1); + pixelMapping.put(C64Utility.WHITE, PF2); + pixelMapping.put(C64Utility.DARK_GRAY, PF3); + + ignoredPixelColors.add(C64Utility.BLACK); + ignoredPixelColors.add(C64Utility.WHITE); + ignoredPixelColors.add(C64Utility.DARK_GRAY); + + // Brown Ship + inverseBlockList.add(16, 18, 5, 7, C64Utility.BROWN, true); + // Blue Planet + inverseBlockList.add(0, 39, 0, 6, C64Utility.LIGHT_BLUE, true); + + // Cybernoid + inverseBlockList.add(0, 39, 8, 19, C64Utility.LIGHT_RED, false); + + // Yellow Explosion + inverseBlockList.add(4, 11, 20, 24, C64Utility.BROWN, true); + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/CharMapGraphics12Converter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/CharMapGraphics12Converter.js new file mode 100644 index 00000000..75e6ba6a --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/CharMapGraphics12Converter.js @@ -0,0 +1,4 @@ +function convertToFileData(data) { + // This is not yet implemented + // com.wudsn.ide.gfx.converter.atari8bit.CharMapGraphics12Converter.convertToFileData(data); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAP3Converter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAP3Converter.java new file mode 100644 index 00000000..c65b00d7 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAP3Converter.java @@ -0,0 +1,101 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; + +public class LinearBitMapAP3Converter extends LinearBitMapConverter { + + public LinearBitMapAP3Converter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 15872; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + setImageSizeAndPalette(data, 40, 192, Palette.TRUE_COLOR, null); + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 2); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int columns = data.getParameters().getColumns(); + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + + int offset1 = 8192; + int offset2 = 0; + int xpixels = 2; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1 = y1 + 1) { + for (int x1 = 0; x1 < columns; x1++) { + int c = data.getSourceFileByte(BIT_MAP_FILE, offset1++); + if (c < 0) { + return true; + } + int b = data.getSourceFileByte(BIT_MAP_FILE, offset2++); + if (b < 0) { + return true; + } + for (int x2 = 0; x2 < 2; x2++) { + int x = x1 * xpixels + x2; + + int color = (c & mask_4bit[x2]) >>> shift_4bit[x2]; + int brightness = (b & mask_4bit[x2]) >>> shift_4bit[x2]; + int atariColor = color << 4 | brightness; + int directColor = paletteMapper.getRGBColor(atariColor); + data.setDirectPixel(x, y1, directColor); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAPACConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAPACConverter.java new file mode 100644 index 00000000..87f6f65f --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAPACConverter.java @@ -0,0 +1,98 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; + +public class LinearBitMapAPACConverter extends LinearBitMapConverter { + + public LinearBitMapAPACConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException("Parameter 'bytes' must not be null."); + } + return bytes.length > 40 && bytes.length % 40 == 0; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException("Parameter 'bytes' must not be null."); + } + setImageSizeAndPalette(data, 40, (bytes.length + 40 - 1) / 40, Palette.TRUE_COLOR, null); + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 2); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + + int columns = data.getParameters().getColumns(); + int rows = data.getParameters().getRows(); + int offset1 = 0; + int offset2 = columns; + int xpixels = 2; + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + + for (int y1 = 0; y1 < rows; y1 = y1 + 1) { + for (int x1 = 0; x1 < columns; x1++) { + int c = data.getSourceFileByte(BIT_MAP_FILE, offset1++); + if (c < 0) { + return true; + } + int b = data.getSourceFileByte(BIT_MAP_FILE, offset2++); + if (b < 0) { + return true; + } + for (int x2 = 0; x2 < 2; x2++) { + int x = x1 * xpixels + x2; + + int color = (c & mask_4bit[x2]) >>> shift_4bit[x2]; + int brightness = (b & mask_4bit[x2]) >>> shift_4bit[x2]; + int atariColor = color << 4 | brightness; + int directColor = paletteMapper.getRGBColor(atariColor); + data.setDirectPixel(x, y1, directColor); + } + + } + offset1 = offset1 + columns; + offset2 = offset2 + columns; + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAPACConverter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAPACConverter.js new file mode 100644 index 00000000..73fd38f1 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAPACConverter.js @@ -0,0 +1,14 @@ +function convertToFileData(data) { + var bpsl = (data.getImageDataWidth() + 1) / 2; + var bytes = [] + var offset = 0; + for (var y = 0; y < data.getImageDataHeight(); y++) { + for (var x = 0; x < data.getImageDataWidth(); x = x + 2) { + var c1 = data.getPixelRGB(x, y); + var c2 = data.getPixelRGB(x + 1, y); + var b = c1 << 4 | c2; + bytes[offset++] = b; + } + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAPCConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAPCConverter.java new file mode 100644 index 00000000..e4a6c4c7 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapAPCConverter.java @@ -0,0 +1,105 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; + +public class LinearBitMapAPCConverter extends LinearBitMapConverter { + + public LinearBitMapAPCConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + // 7680 bytes of bitmap, optionally 40 bytes of text in ATASCII screen + // code + return bytes.length == 7680 || bytes.length == 7680 + 40; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + setImageSizeAndPalette(data, 40, 96, Palette.TRUE_COLOR, null); + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 2); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int columns = data.getParameters().getColumns(); + + int offset1 = 0; + int offset2 = columns; + int xpixels = 2; + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1 = y1 + 1) { + for (int x1 = 0; x1 < columns; x1++) { + int c = data.getSourceFileByte(BIT_MAP_FILE, offset1++); + if (c < 0) { + return true; + } + int b = data.getSourceFileByte(BIT_MAP_FILE, offset2++); + if (b < 0) { + return true; + } + for (int x2 = 0; x2 < 2; x2++) { + int x = x1 * xpixels + x2; + + int color = (c & mask_4bit[x2]) >>> shift_4bit[x2]; + int brightness = (b & mask_4bit[x2]) >>> shift_4bit[x2]; + int atariColor = color << 4 | brightness; + int directColor = paletteMapper.getRGBColor(atariColor); + data.setDirectPixel(x, y1, directColor); + } + + } + offset1 = offset1 + columns; + offset2 = offset2 + columns; + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapCINConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapCINConverter.java new file mode 100644 index 00000000..26e422b3 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapCINConverter.java @@ -0,0 +1,195 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.FilesConverterParameters.SourceFile; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; + +/** + * Converter for CCI and CIN files. + * + * @author Peter Dell + * + * @since 1.6.0 + */ +public class LinearBitMapCINConverter extends LinearBitMapConverter { + + public LinearBitMapCINConverter() { + + } + + private boolean isCIN(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 16384; + } + + private boolean isCCI(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length > 7 && bytes[0] == 'C' && bytes[1] == 'I' + && bytes[2] == 'N' && bytes[3] == ' ' && bytes[4] == '1' + && bytes[5] == '.' && bytes[6] == '2' && bytes[7] == ' '; + } + + private boolean unpackCCI(byte[] bytes, int offset, byte[] unpackedImage) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + if (offset < 0) { + throw new IllegalArgumentException( + "Parameter 'offset' must not be negative. Specified value is " + + offset + "."); + } + if (unpackedImage == null) { + throw new IllegalArgumentException( + "Parameter 'unpackedImage' must not be null."); + } + // Compressed even lines of graphics 15 frame + int dataOffset = offset + 8; + int dataLength = Atari8BitUtility.getWord(bytes, dataOffset); + if (!Atari8BitUtility.unpackCCI(bytes, dataOffset + 2, dataLength, 80, 96, + unpackedImage, 0)) { + return false; + } + + // Compressed odd lines of graphics 15 frame + dataOffset += 2 + dataLength; + dataLength = Atari8BitUtility.getWord(bytes, dataOffset); + if (!Atari8BitUtility.unpackCCI(bytes, dataOffset + 2, dataLength, 80, 96, + unpackedImage, 40)) { + return false; + } + + // Compressed graphics 11 + dataOffset += 2 + dataLength; + dataLength = Atari8BitUtility.getWord(bytes, dataOffset); + if (!Atari8BitUtility.unpackCCI(bytes, dataOffset + 2, dataLength, 40, + 192, unpackedImage, 7680)) { + return false; + } + + /* compressed color values for gr15 */ + dataOffset += 2 + dataLength; + dataLength = Atari8BitUtility.getWord(bytes, dataOffset); + if (!Atari8BitUtility.unpackCCI(bytes, dataOffset + 2, dataLength, 1, + 0x400, unpackedImage, 0x3C00)) { + return false; + } + + dataOffset += 2 + dataLength; + return dataOffset == bytes.length; + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return isCIN(bytes) || isCCI(bytes); + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + setImageSizeAndPalette(data, 40, 192, Palette.TRUE_COLOR, null); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 4); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + byte[] bytes = data.getSourceFileBytes(BIT_MAP_FILE); + if (bytes == null) { + return false; + } + + byte[] unpackedImage; + SourceFile sourceFile = data.getParameters() + .getSourceFile(BIT_MAP_FILE); + int offset = sourceFile.getOffset(); + + if (isCCI(bytes)) { + unpackedImage = new byte[16384]; + if (!unpackCCI(bytes, offset, unpackedImage)) { + return false; + } + } else { + unpackedImage = bytes; + } + int xpixels = 4; + PaletteMapper paletteMapper=new Atari8BitPaletteMapper(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + if (offset + 7680 >= unpackedImage.length) { + return true; + } + int b1 = unpackedImage[offset + 7680] & 0xff; + int b2 = unpackedImage[offset++] & 0xff; + + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + x2; + int x3 = x2 >>> 1; + int hue = (b1 & mask_4bit[x3]) >>> shift_4bit[x3]; + int lumaRegister = (b2 & mask_2bit[x2]) >>> shift_2bit[x2]; + int lumaOffset = 0x3c00 + lumaRegister * 0x100 + y1; + int luma = 0; + if (lumaOffset < unpackedImage.length) { + luma = unpackedImage[lumaOffset] & 0xe; + } + + int color = paletteMapper.getRGBColor(hue << 4 + | luma); + data.setDirectPixel(x, y1, color); + } + } + } + return true; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapCPRConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapCPRConverter.java new file mode 100644 index 00000000..c32be954 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapCPRConverter.java @@ -0,0 +1,122 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +public class LinearBitMapCPRConverter extends LinearBitMapConverter { + + public LinearBitMapCPRConverter() { + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + if (bytes.length < 3) { + return false; + } + + byte[] unpackedImage = new byte[7684]; + boolean result = Atari8BitUtility.unpackKoala(bytes, 1, bytes.length - 1, + bytes[0] & 0xff, unpackedImage); + return result; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + byte[] unpackedImage = new byte[7684]; + boolean result = Atari8BitUtility.unpackKoala(bytes, 1, bytes.length - 1, + bytes[0] & 0xff, unpackedImage); + if (!result) { + return; + } + + RGB[] paletteColors; + paletteColors = PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.HIRES_1, null); + setImageSizeAndPalette(data, 40, 192, Palette.HIRES_1, paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 8); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + byte[] bytes = data.getSourceFileBytes(BIT_MAP_FILE); + if (bytes == null || bytes.length < 3) { + return false; + } + + byte[] unpackedImage = new byte[7680]; + boolean result = Atari8BitUtility.unpackKoala(bytes, 1, bytes.length - 1, + bytes[0] & 0xff, unpackedImage); + + if (!result) { + return false; + } + + int offset = 0; + int xpixels = 8; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + if (offset >= unpackedImage.length) { + return true; + } + int b = unpackedImage[offset++] & 0xff; + for (int x2 = 0; x2 < 8; x2++) { + int x = x1 * xpixels + x2; + int color = (b & mask_1bit[x2]) >>> shift_1bit[x2]; + data.setPalettePixel(x, y1, color); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGHGConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGHGConverter.java new file mode 100644 index 00000000..12de4594 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGHGConverter.java @@ -0,0 +1,100 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; + +public class LinearBitMapGHGConverter extends LinearBitMapConverter { + + public LinearBitMapGHGConverter() { + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 0x1f43 && Atari8BitUtility.getWord(bytes, 0) > 0 + && Atari8BitUtility.getWord(bytes, 0) <= 320 + && (bytes[2] & 0xff) > 0 && (bytes[2] & 0xff) <= 200; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + int columns = (Atari8BitUtility.getWord(bytes, 0) + 7) / 8; + int rows = (bytes[2] & 0xff); + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + + RGB[] paletteColors = new RGB[2]; + paletteColors[0] = paletteMapper.getRGB(12); + paletteColors[1] = paletteMapper.getRGB(2); + + setImageSizeAndPalette(data, columns, rows, Palette.HIRES_MANUAL, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 8); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 3; + int xpixels = 8; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b = data.getSourceFileByte(BIT_MAP_FILE, offset++); + if (b < 0) { + return true; + } + for (int x2 = 0; x2 < 8; x2++) { + int x = x1 * xpixels + x2; + int color = (b & mask_1bit[x2]) >>> shift_1bit[x2]; + data.setPalettePixel(x, y1, color); + } + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics10Converter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics10Converter.java new file mode 100644 index 00000000..39c72d35 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics10Converter.java @@ -0,0 +1,64 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; + +public class LinearBitMapGraphics10Converter extends LinearBitMapConverter { + + public LinearBitMapGraphics10Converter() { + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 8); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 2; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b = data.getSourceFileByte(BIT_MAP_FILE, offset++); + if (b < 0) { + return true; + } + for (int x2 = 0; x2 < 2; x2++) { + int x = x1 * xpixels + x2; + + int color = (b & mask_4bit[x2]) >>> shift_4bit[x2]; + data.setDirectPixel(x, y1, color * 0x101010); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics10Converter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics10Converter.js new file mode 100644 index 00000000..5703f985 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics10Converter.js @@ -0,0 +1,14 @@ +function convertToFileData(data) { + var bpsl = (data.getImageDataWidth() + 1) / 2; + var bytes = []; + var offset = 0; + for (var y = 0; y < data.getImageDataHeight(); y++) { + for (var x = 0; x < data.getImageDataWidth(); x = x + 2) { + var c1 = data.getPixel(x, y); + var c2 = data.getPixel(x + 1, y); + var b = c1 << 4 | c2; + bytes[offset++] = b; + } + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics15Converter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics15Converter.java new file mode 100644 index 00000000..6116fc98 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics15Converter.java @@ -0,0 +1,99 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +public class LinearBitMapGraphics15Converter extends LinearBitMapConverter { + + public LinearBitMapGraphics15Converter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 7680; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + int columns = 40; + int rows = (bytes.length + columns - 1) / columns; + RGB[] paletteColors; + paletteColors = PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.MULTI_1, null); + setImageSizeAndPalette(data, columns, rows, Palette.MULTI_1, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 4); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 4; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b = data.getSourceFileByte(BIT_MAP_FILE, offset++); + if (b < 0) { + return true; + } + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + x2; + + int color = (b & mask_2bit[x2]) >>> shift_2bit[x2]; + data.setPalettePixel(x, y1, color); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics15Converter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics15Converter.js new file mode 100644 index 00000000..b270fbe8 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics15Converter.js @@ -0,0 +1,16 @@ +function convertToFileData(data) { + var bpsl = (data.getImageDataWidth() + 3) / 4; + var bytes = []; + var offset = 0; + for (var y = 0; y < data.getImageDataHeight(); y++) { + for (var x = 0; x < data.getImageDataWidth(); x = x + 4) { + var c1,c2,c3,c4; + c1 = data.getPixel(x, y) & 0x3; + c2 = data.getPixel(x+1, y) & 0x3; + c3 = data.getPixel(x+2, y) & 0x3; + c4 = data.getPixel(x+3, y) & 0x3; + bytes[offset++] = c1 << 6 | c2 << 4 | c3 << 2 | c4; + } + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics8Converter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics8Converter.java new file mode 100644 index 00000000..93dce9cc --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics8Converter.java @@ -0,0 +1,93 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +public class LinearBitMapGraphics8Converter extends LinearBitMapConverter { + + public LinearBitMapGraphics8Converter() { + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 7680; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + RGB[] paletteColors; + paletteColors = PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.HIRES_1, null); + setImageSizeAndPalette(data, 40, 192, Palette.HIRES_1, paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 8); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 8; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b = data.getSourceFileByte(BIT_MAP_FILE, offset++); + if (b < 0) { + return true; + } + for (int x2 = 0; x2 < 8; x2++) { + int x = x1 * xpixels + x2; + int color = (b & mask_1bit[x2]) >>> shift_1bit[x2]; + data.setPalettePixel(x, y1, color); + } + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics8Converter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics8Converter.js new file mode 100644 index 00000000..6af9a6a9 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics8Converter.js @@ -0,0 +1,19 @@ +function convertToFileData(data) { + var bpsl = (data.getImageDataWidth() + 7) / 8; + var bytes = []; + var offset = 0; + for (var y = 0; y < data.getImageDataHeight(); y++) { + for (var x = 0; x < data.getImageDataWidth(); x = x + 8) { + var b = 0; + for (var p = 0; p < 8; p++) { + var color; + color = data.getPixel(x + p, y); + if (color != 0) { + b = b | 1 << 7 - p; + } + } + bytes[offset++] = b; + } + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics9Converter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics9Converter.java new file mode 100644 index 00000000..8d4db187 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics9Converter.java @@ -0,0 +1,96 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +public class LinearBitMapGraphics9Converter extends LinearBitMapConverter { + + public LinearBitMapGraphics9Converter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 7680; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + RGB[] paletteColors; + paletteColors = PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.GTIA_GREY_1, null); + setImageSizeAndPalette(data, 40, 192, Palette.GTIA_GREY_1, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 2); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 2; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b = data.getSourceFileByte(BIT_MAP_FILE, offset++); + if (b < 0) { + return true; + } + for (int x2 = 0; x2 < 2; x2++) { + int x = x1 * xpixels + x2; + + int color = (b & mask_4bit[x2]) >>> shift_4bit[x2]; + data.setPalettePixel(x, y1, color); + } + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics9Converter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics9Converter.js new file mode 100644 index 00000000..5703f985 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapGraphics9Converter.js @@ -0,0 +1,14 @@ +function convertToFileData(data) { + var bpsl = (data.getImageDataWidth() + 1) / 2; + var bytes = []; + var offset = 0; + for (var y = 0; y < data.getImageDataHeight(); y++) { + for (var x = 0; x < data.getImageDataWidth(); x = x + 2) { + var c1 = data.getPixel(x, y); + var c2 = data.getPixel(x + 1, y); + var b = c1 << 4 | c2; + bytes[offset++] = b; + } + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHIPConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHIPConverter.java new file mode 100644 index 00000000..060fbeac --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHIPConverter.java @@ -0,0 +1,193 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.RBGUtility; + +public class LinearBitMapHIPConverter extends LinearBitMapConverter { + + public LinearBitMapHIPConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + // HIP image with binary file headers. Two concatenated COM files. + int frame1Length = Atari8BitUtility.getLengthFromBinaryHeader(bytes, 0); + if (frame1Length > 0 && frame1Length * 2 + 12 == bytes.length + && frame1Length % 40 == 0) { + + int frame2Length = Atari8BitUtility.getLengthFromBinaryHeader(bytes, + frame1Length + 6); + if (frame2Length == frame1Length) { + return true; + } + } + // HIP image with graphics 10 palette. + else if ((bytes.length - 9) % 80 == 0) { + return true; + } + return false; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + // HIP image with binary file headers. Two concatenated COM files. + int rows; + int frame1Length = Atari8BitUtility.getLengthFromBinaryHeader(bytes, 0); + if (frame1Length > 0 && frame1Length * 2 + 12 == bytes.length + && frame1Length % 40 == 0) { + + int frame2Length = Atari8BitUtility.getLengthFromBinaryHeader(bytes, + frame1Length + 6); + if (frame2Length != frame1Length) { + throw new IllegalStateException("Inconsistent file"); + } + + rows = frame1Length / 40; + } + // hip image with gr10 palette. + else if ((bytes.length - 9) % 80 == 0) { + rows = (bytes.length - 9) / 80; + } else { + throw new IllegalStateException("Inconsistent file"); + } + + setImageSizeAndPalette(data, 40, rows, Palette.TRUE_COLOR, null); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 4 + 1); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int rows = data.getParameters().getRows(); + int columns = data.getParameters().getColumns(); + PaletteMapper paletteMapper=new Atari8BitPaletteMapper(); + + // Assume the binary is already merged in case of a 160012 bytes HIP. + int offset9, offset10, offsetPalette; + + byte[] sourceFileBytes = data.getSourceFileBytes(BIT_MAP_FILE); + if (sourceFileBytes == null) { + return false; + } + + // Assume grey scale colors by default. + int[] graphics10Colors = { 0, 0, 2, 4, 6, 8, 10, 12, 14 }; + + // Compute the offsets in the file. + int frameSize = rows * columns; + int rest = sourceFileBytes.length - 2 * frameSize; + if (rest == 0 || rest == 9) { + // In this case the graphics 9 picture comes first + offset9 = 0; + offset10 = offset9 + 0 + frameSize; + offsetPalette = offset10 + frameSize; + if (rest == 9) { + for (int i = 0; i < 9; i++) { + graphics10Colors[i] = sourceFileBytes[offsetPalette + i]; + } + } + } else if (rest == 12) { + // In this case the graphics 10 picture comes first + offset10 = 6; + offset9 = offset10 + 6 + frameSize; + } else { + return false; + } + + int[] buffer1 = new int[columns * 4 + 1]; + int[] buffer2 = new int[columns * 4 + 1]; + + for (int y1 = 0; y1 < rows; y1++) { + for (int x1 = 0; x1 < columns; x1++) { + int byte9 = data.getSourceFileByte(BIT_MAP_FILE, offset9++); + if (byte9 < 0) { + return true; + } + int byte10 = data.getSourceFileByte(BIT_MAP_FILE, offset10++); + if (byte10 < 0) { + return true; + } + + // Byte 1 is the GTIA 9 byte, take the values as brightness + // values + int brightness1 = (byte9 & mask_4bit[0]) >>> shift_4bit[0]; + int brightness2 = (byte9 & mask_4bit[1]) >>> shift_4bit[1]; + + // Byte 2 is the GTIA 10 byte, take the values from the GTIA 10 + // palette + int brightness3 = (byte10 & mask_4bit[0]) >>> shift_4bit[0]; + int brightness4 = (byte10 & mask_4bit[1]) >>> shift_4bit[1]; + brightness3 = graphics10Colors[Atari8BitUtility.GRAPHICS_10_REGISTERS[brightness3]]; + brightness4 = graphics10Colors[Atari8BitUtility.GRAPHICS_10_REGISTERS[brightness4]]; + + // Put the color values in the row buffer, shifted by 1 pixel + int x = x1 << 2; + buffer1[x + 0] = brightness1; + buffer1[x + 1] = brightness1; + buffer1[x + 2] = brightness2; + buffer1[x + 3] = brightness2; + + buffer2[x + 1] = brightness3; + buffer2[x + 2] = brightness3; + buffer2[x + 3] = brightness4; + buffer2[x + 4] = brightness4; + } + + // Merge the two buffers into combined color values. + for (int x = 0; x < buffer1.length; x++) { + int atariColor = RBGUtility.combineRGBColor( + paletteMapper.getRGBColor(buffer1[x]), + paletteMapper.getRGBColor(buffer2[x])); + data.setDirectPixel(x, y1, atariColor); + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHIPConverter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHIPConverter.js new file mode 100644 index 00000000..679fa642 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHIPConverter.js @@ -0,0 +1,31 @@ +function convertToFileData(data) { + var bpsl = (data.getImageDataWidth() + 1) / 2; + var bptl = bpsl / 2; + var bytes = []; + var offset = 0; + for (var y = 0; y < data.getImageDataHeight(); y++) { + for (var x = 0; x < data.getImageDataWidth(); x = x + 4) { + var c1; + var c2; + c1 = data.getPixel(x, y); + if (x+2 < data.getImageDataWidth() ){ + c2 = data.getPixel(x+2, y); + } else { + c2 = 0; + } + bytes[offset] = (color1 << 4 | color2); + + c1 = data.getPixel(x+1, y); + if (x+3 < data.getImageDataWidth() ){ + c2 = data.getPixel(x+3, y); + } else { + c2 = 0; + } + bytes[offset] = (color1 << 4 | color2); + } + bytes[offset++] = b; + } + offset += bptl; + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHR2Converter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHR2Converter.java new file mode 100644 index 00000000..4aec11c3 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHR2Converter.java @@ -0,0 +1,122 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.RBGUtility; + +public class LinearBitMapHR2Converter extends LinearBitMapConverter { + + public LinearBitMapHR2Converter() { + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 16006; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + PaletteMapper paletteMapper=new Atari8BitPaletteMapper(); + + RGB[] paletteColors = new RGB[8]; + RGB[] palette1Colors = new RGB[2]; + RGB[] palette2Colors = new RGB[4]; + palette1Colors[0] = paletteMapper.getRGB(bytes[16000] & 0xfe); + palette1Colors[1] = paletteMapper.getRGB(bytes[16001] & 0xfe); + palette2Colors[0] = paletteMapper.getRGB(bytes[16002] & 0xfe); + palette2Colors[1] = paletteMapper.getRGB(bytes[16003] & 0xfe); + palette2Colors[2] = paletteMapper.getRGB(bytes[16004] & 0xfe); + palette2Colors[3] = paletteMapper.getRGB(bytes[16005] & 0xfe); + + // Compute mixed interlace colors. + for (int x1 = 0; x1 < palette1Colors.length; x1++) { + for (int x2 = 0; x2 < palette2Colors.length; x2++) { + paletteColors[x1 * palette2Colors.length + x2] = RBGUtility + .combineRGB(palette1Colors[x1], palette2Colors[x2]); + } + } + setImageSizeAndPalette(data, 40, 200, Palette.MULTI_MANUAL, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 8); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 8; + + int frameSize = 8000; + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b1 = data.getSourceFileByte(BIT_MAP_FILE, offset); + if (b1 < 0) { + return true; + } + int b2 = data.getSourceFileByte(BIT_MAP_FILE, offset + + frameSize); + if (b2 < 0) { + return true; + } + offset++; + + for (int x2 = 0; x2 < 8; x2++) { + int x = x1 * xpixels + x2; + // Graphics 8 + int color1 = (b1 & mask_1bit[x2]) >>> shift_1bit[x2]; + // Graphics 15, half resolution + int color2 = (b2 & mask_2bit[x2 >>> 1]) >>> shift_2bit[x2 >>> 1]; + data.setPalettePixel(x, y1, (color1 << 2) + color2); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHRConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHRConverter.java new file mode 100644 index 00000000..8113bd29 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapHRConverter.java @@ -0,0 +1,108 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.RBGUtility; +import com.wudsn.ide.gfx.model.PaletteUtility; + +public class LinearBitMapHRConverter extends LinearBitMapConverter { + + public LinearBitMapHRConverter() { + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 16384; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + RGB[] paletteColors = new RGB[3]; + paletteColors[0] = PaletteUtility.BLACK; + paletteColors[2] = PaletteUtility.WHITE; + + // Compute mixed interlace colors. + paletteColors[1] = RBGUtility.combineRGB(paletteColors[0], + paletteColors[2]); + setImageSizeAndPalette(data, 32, 239, Palette.MULTI_MANUAL, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 8); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 8; + + int frameSize = 8192; + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b1 = data.getSourceFileByte(BIT_MAP_FILE, offset); + if (b1 < 0) { + return true; + } + int b2 = data.getSourceFileByte(BIT_MAP_FILE, offset + + frameSize); + if (b2 < 0) { + return true; + } + offset++; + + for (int x2 = 0; x2 < 8; x2++) { + int x = x1 * xpixels + x2; + int color1 = (b1 & mask_1bit[x2]) >>> shift_1bit[x2]; + int color2 = (b2 & mask_1bit[x2]) >>> shift_1bit[x2]; + data.setPalettePixel(x, y1, color1 + color2); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapILCConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapILCConverter.java new file mode 100644 index 00000000..64cc1704 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapILCConverter.java @@ -0,0 +1,102 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; + +public class LinearBitMapILCConverter extends LinearBitMapConverter { + + public LinearBitMapILCConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 15360; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + setImageSizeAndPalette(data, 40, 192, Palette.TRUE_COLOR, null); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 2); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int columns = data.getParameters().getColumns(); + + int offset1 = 7680; + int offset2 = 0; + int xpixels = 2; + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1 = y1 + 1) { + for (int x1 = 0; x1 < columns; x1++) { + int c = data.getSourceFileByte(BIT_MAP_FILE, offset1++); + if (c < 0) { + return true; + } + int b = data.getSourceFileByte(BIT_MAP_FILE, offset2++); + if (b < 0) { + return true; + } + for (int x2 = 0; x2 < 2; x2++) { + int x = x1 * xpixels + x2; + + int color = (c & mask_4bit[x2]) >>> shift_4bit[x2]; + int brightness = (b & mask_4bit[x2]) >>> shift_4bit[x2]; + int atariColor = color << 4 | brightness; + int directColor = paletteMapper + .getRGBColor(atariColor); + data.setDirectPixel(x, y1, directColor); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapINPConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapINPConverter.java new file mode 100644 index 00000000..2f740d21 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapINPConverter.java @@ -0,0 +1,117 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.RBGUtility; + +/** + * The valid bit pattern combinations from the two images are: (0,0)=0, (0,1)=1, + * (1,1)=2, (1,2)=3, (2,2)=4, (2,3)=5, (3,3)=6 + */ + +public class LinearBitMapINPConverter extends LinearBitMapConverter { + + public LinearBitMapINPConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 16004 || bytes.length == 16052; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + RGB[] paletteColors = new RGB[7]; + paletteColors[0] = paletteMapper.getRGB(bytes[16000] & 0xfe); + paletteColors[2] = paletteMapper.getRGB(bytes[16001] & 0xfe); + paletteColors[4] = paletteMapper.getRGB(bytes[16002] & 0xfe); + paletteColors[6] = paletteMapper.getRGB(bytes[16003] & 0xfe); + + // Compute mixed interlace colors. + paletteColors[1] = RBGUtility.combineRGB(paletteColors[0], + paletteColors[2]); + paletteColors[3] = RBGUtility.combineRGB(paletteColors[2], + paletteColors[4]); + paletteColors[5] = RBGUtility.combineRGB(paletteColors[4], + paletteColors[6]); + + setImageSizeAndPalette(data, 40, 200, Palette.MULTI_MANUAL, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 4); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 4; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b1 = data.getSourceFileByte(BIT_MAP_FILE, offset + 8000); + int b2 = data.getSourceFileByte(BIT_MAP_FILE, offset++); + if (b1 < 0 || b2 < 0) { + return true; + } + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + x2; + + int color1 = (b1 & mask_2bit[x2]) >>> shift_2bit[x2]; + int color2 = (b2 & mask_2bit[x2]) >>> shift_2bit[x2]; + data.setPalettePixel(x, y1, color1 + color2); + } + + } + } + return true; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapINTConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapINTConverter.java new file mode 100644 index 00000000..6742f4d9 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapINTConverter.java @@ -0,0 +1,147 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.RBGUtility; + +/** + * The valid bit pattern combinations from the two images are: (0,0)=0, (0,1)=1, + * (1,1)=2, (1,2)=3, (2,2)=4, (2,3)=5, (3,3)=6 + */ + +public class LinearBitMapINTConverter extends LinearBitMapConverter { + + public LinearBitMapINTConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + if (bytes.length < 10) { + return false; + } + if (bytes[0] != (byte) 'I' + || bytes[1] != (byte) 'N' + || bytes[2] != (byte) 'T' + || bytes[3] != (byte) '9' + || bytes[4] != (byte) '5' + || bytes[5] != (byte) 'a' + || bytes[6] == (byte) 0 + || (bytes[6] & 0xff) > 40 + || bytes[7] == (byte) 0 + || (bytes[7] & 0xff) > 239 + || bytes[8] != (byte) 0x0f + || bytes[9] != (byte) 0x2b + || 18 + (bytes[6] & 0xff) * (bytes[7] & 0xff) * 2 != bytes.length) { + return false; + } + return true; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + int rows; + int columns; + rows = bytes[7] & 0xff; + columns = bytes[6] & 0xff; + + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + RGB[] paletteColors = new RGB[16]; + RGB[] palette1Colors = new RGB[4]; + RGB[] palette2Colors = new RGB[4]; + palette1Colors[0] = paletteMapper.getRGB(bytes[10] & 0xfe); + palette1Colors[1] = paletteMapper.getRGB(bytes[11] & 0xfe); + palette1Colors[2] = paletteMapper.getRGB(bytes[12] & 0xfe); + palette1Colors[3] = paletteMapper.getRGB(bytes[13] & 0xfe); + palette2Colors[0] = paletteMapper.getRGB(bytes[14] & 0xfe); + palette2Colors[1] = paletteMapper.getRGB(bytes[15] & 0xfe); + palette2Colors[2] = paletteMapper.getRGB(bytes[16] & 0xfe); + palette2Colors[3] = paletteMapper.getRGB(bytes[17] & 0xfe); + + // Compute mixed interlace colors. + for (int x1 = 0; x1 < 4; x1++) { + for (int x2 = 0; x2 < 4; x2++) { + paletteColors[x1 * 4 + x2] = RBGUtility.combineRGB( + palette1Colors[x1], palette2Colors[x2]); + } + + } + setImageSizeAndPalette(data, columns, rows, Palette.MULTI_MANUAL, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 4); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset1 = 18; + int offset2 = offset1 + data.getParameters().getRows() + * data.getParameters().getColumns(); + int xpixels = 4; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b1 = data.getSourceFileByte(BIT_MAP_FILE, offset1++); + int b2 = data.getSourceFileByte(BIT_MAP_FILE, offset2++); + if (b1 < 0 || b2 < 0) { + return true; + } + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + x2; + + int color1 = (b1 & mask_2bit[x2]) >>> shift_2bit[x2]; + int color2 = (b2 & mask_2bit[x2]) >>> shift_2bit[x2]; + int color = 4 * color1 + color2; + data.setPalettePixel(x, y1, color); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapKoalaConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapKoalaConverter.java new file mode 100644 index 00000000..b8f5b61a --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapKoalaConverter.java @@ -0,0 +1,147 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; + +public class LinearBitMapKoalaConverter extends LinearBitMapConverter { + + public LinearBitMapKoalaConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + if (bytes.length < 22) { + return false; + } + + if ((bytes[0] != (byte) 0xff || bytes[1] != (byte) 0x80 + || bytes[2] != (byte) 0xc9 || bytes[3] != (byte) 0xc7 + || bytes[4] < (byte) 0x1a || (bytes[4] & 0xff) >= bytes.length + || bytes[5] != (byte) 0 || bytes[6] != (byte) 1 + || bytes[8] != (byte) 0x0e || bytes[9] != (byte) 0 + || bytes[10] != (byte) 40 || bytes[11] != (byte) 0 + || bytes[12] != (byte) 192 || bytes[20] != (byte) 0 || bytes[21] != (byte) 0)) { + return false; + } + + byte[] unpackedImage = new byte[7684]; + boolean result = Atari8BitUtility.unpackKoala(bytes, + (bytes[4] & 0xff) + 1, bytes.length - (bytes[4] & 0xff) - 1, + bytes[7] & 0xff, unpackedImage); + + return result; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + byte[] unpackedImage = new byte[7684]; + boolean result = Atari8BitUtility.unpackKoala(bytes, + (bytes[4] & 0xff) + 1, bytes.length - (bytes[4] & 0xff) - 1, + bytes[7] & 0xff, unpackedImage); + + if (!result) { + throw new IllegalStateException("canConverterToImage() not called"); + } + + unpackedImage[7680] = bytes[17]; + unpackedImage[7681] = bytes[13]; + unpackedImage[7682] = bytes[14]; + unpackedImage[7683] = bytes[15]; + + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + RGB[] paletteColors = new RGB[4]; + paletteColors[0] = paletteMapper.getRGB(unpackedImage[7680] & 0xfe); + paletteColors[1] = paletteMapper.getRGB(unpackedImage[7681] & 0xfe); + paletteColors[2] = paletteMapper.getRGB(unpackedImage[7682] & 0xfe); + paletteColors[3] = paletteMapper.getRGB(unpackedImage[7683] & 0xfe); + + setImageSizeAndPalette(data, 40, 192, Palette.MULTI_MANUAL, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 4); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + byte[] bytes = data.getSourceFileBytes(BIT_MAP_FILE); + if (bytes == null || bytes.length < 8) { + return false; + } + + byte[] unpackedImage = new byte[7684]; + boolean result; + + result = Atari8BitUtility.unpackKoala(bytes, (bytes[4] & 0xff) + 1, + bytes.length - (bytes[4] & 0xff) - 1, bytes[7] & 0xff, + unpackedImage); + if (!result) { + return false; + } + + int offset = 0; + int xpixels = 4; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + if (offset >= unpackedImage.length) { + return true; + } + int b = unpackedImage[offset++] & 0xff; + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + x2; + int color = (b & mask_2bit[x2]) >>> shift_2bit[x2]; + data.setPalettePixel(x, y1, color); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapMCPConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapMCPConverter.java new file mode 100644 index 00000000..ecf542c2 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapMCPConverter.java @@ -0,0 +1,123 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.RBGUtility; + +public class LinearBitMapMCPConverter extends LinearBitMapConverter { + + public LinearBitMapMCPConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 16008; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + RGB[] paletteColors = new RGB[16]; + RGB[] palette1Colors = new RGB[4]; + RGB[] palette2Colors = new RGB[4]; + palette1Colors[0] = paletteMapper.getRGB(bytes[16003] & 0xfe); + palette1Colors[1] = paletteMapper.getRGB(bytes[16000] & 0xfe); + palette1Colors[2] = paletteMapper.getRGB(bytes[16001] & 0xfe); + palette1Colors[3] = paletteMapper.getRGB(bytes[16002] & 0xfe); + palette2Colors[0] = paletteMapper.getRGB(bytes[16007] & 0xfe); + palette2Colors[1] = paletteMapper.getRGB(bytes[16004] & 0xfe); + palette2Colors[2] = paletteMapper.getRGB(bytes[16005] & 0xfe); + palette2Colors[3] = paletteMapper.getRGB(bytes[16006] & 0xfe); + + // Compute mixed interlace colors. + for (int x1 = 0; x1 < 4; x1++) { + for (int x2 = 0; x2 < 4; x2++) { + paletteColors[x1 * 4 + x2] = RBGUtility.combineRGB( + palette1Colors[x1], palette2Colors[x2]); + } + } + + setImageSizeAndPalette(data, 40, 200, Palette.MULTI_MANUAL, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 4); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 4; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b1 = data.getSourceFileByte(BIT_MAP_FILE, offset + 8000); + int b2 = data.getSourceFileByte(BIT_MAP_FILE, offset++); + if (b1 < 0 || b2 < 0) { + return true; + } + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + x2; + + int color1 = (b1 & mask_2bit[x2]) >>> shift_2bit[x2]; + int color2 = (b2 & mask_2bit[x2]) >>> shift_2bit[x2]; + int color; + if ((y1 & 1) == 1) { + color = 4 * color1 + color2; + } else { + color = 4 * color2 + color1; + } + data.setPalettePixel(x, y1, color); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapMicroPainterConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapMicroPainterConverter.java new file mode 100644 index 00000000..262b5068 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapMicroPainterConverter.java @@ -0,0 +1,107 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +public class LinearBitMapMicroPainterConverter extends LinearBitMapConverter { + + public LinearBitMapMicroPainterConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 7680 || bytes.length == 7684; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + RGB[] paletteColors; + if (bytes.length == 7684) { + paletteColors = new RGB[4]; + paletteColors[0] = paletteMapper.getRGB(bytes[7680] & 0xfe); + paletteColors[1] = paletteMapper.getRGB(bytes[7681] & 0xfe); + paletteColors[2] = paletteMapper.getRGB(bytes[7682] & 0xfe); + paletteColors[3] = paletteMapper.getRGB(bytes[7683] & 0xfe); + } else { + paletteColors = PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.MULTI_1, null); + } + + setImageSizeAndPalette(data, 40, 192, Palette.MULTI_MANUAL, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 4); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 4; + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int b = data.getSourceFileByte(BIT_MAP_FILE, offset++); + if (b < 0) { + return true; + } + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + x2; + + int color = (b & mask_2bit[x2]) >>> shift_2bit[x2]; + data.setPalettePixel(x, y1, color); + } + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapRIPConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapRIPConverter.java new file mode 100644 index 00000000..6899f43f --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapRIPConverter.java @@ -0,0 +1,698 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.RBGUtility; + +/** + * RIP picture format description
+ * + * Original text by Rocky of Madteam taken from Syzygy Magazine
+ * RIP picture was shown first time in Orneta of Poland in '97 in Igor demo by + * Madteam. There we copied several disks of RIP images. RIP is a new graphics + * storage format on Atari 8-bit. It is based on already famous HIP picture + * format (Gr.9 + Gr.10). Theoretically it is possible to get 144 colors (there + * are about 40 in practice) with resolution of 160x238 (RIP mode 32; 16 lum x 9 + * col). RIP is more complicated than HIP, because of the header which contains + * a lot of information about colors, resolution and a note from the author. RIP + * can have various vertical sizes (max. 238 lines) which cause less space on + * disk and faster reading.
+ *
+ * + * (E.g. we have a logo with 50 lines. Our logo will be saved with 200 lines as + * HIP and takes about 16kB but saved as RIP - only 4kB plus several bytes of + * header. That's a difference, isn't it?) In addition RIP can be colored and + * HIP can only be grey scaled. (HIP can also be colored but there is no room + * for color info in the header.) The first one can still be packed (algorithm + * in end phase) for RIP dedicated Visage viewer which is able to recognize its + * size, colors, compression method and displaying on screen. Saving HIP as RIP + * is no problem 'couse of similar data format. Adapting existing HIP viewers + * for RIP pictures shouldn't be problematic too; Only what has to be done is + * format recognition, displaying of various image height and setting colors + * (for Gr.10) from the header (see below).
+ *
+ * + * How to make a RIP picture?
+ * + * It can be quite difficult. There is a converter for Amiga and PC. This is not + * a real converter from any graphics format (GIF, IFF or Jpeg) to RIP. To make + * a RIP picture, you will have to use programs not only dedicated to RIP. The + * best for Amiga is Personal Paint and for PC - Display. It's quite a large + * job. One picture has to be divided into two others. Next: size modification, + * color palette reduction (one of these two pictures has to be 16 grey scales + * what can be done with almost all programs and the other picture has to be in + * 9 colors, what most programs for the Amiga and PC simply cannot do). The + * effect can be very satisfactory, but it might also be completely bad, which + * happens quite often (none of the pics is perfect). You can then always create + * a HIP picture, which is better in this case (grey scale is easier to do) but + * you will be limited to 200 lines. Well, life is brutal...
+ *
+ * Header description:
+ * In 'Description' filed text with quotes (") is pure ASCII string. + * + *
+ *  Offset | Len | Description
+ * --------------------------------------------
+ *       0 |  3  | "RIP" - RIP image identifier
+ *       3 |  4  | version:
+ *         |     |         "1.x " - standard RIP
+ *         |     |         "2.0 " - Multi RIP
+ *       7 |  1  | graphics mode:
+ *         |     |         $20 - RIP or HIP
+ *         |     |         $30 - Multi RIP, palette at the end of file
+ *         |     |         $0f - Graphics  8
+ *         |     |         $4f - Graphics  9
+ *         |     |         $8f - Graphics 10
+ *         |     |         $cf - Graphics 11
+ *         |     |         $0e - Graphics 15
+ *       8 |  2  | compression method:
+ *         |     |         0, 0 - no compress
+ *         |     |         0, 1 - RIPPCK
+ *      10 |  2  | header length in bytes, MSB/LSB !!!
+ *      12 |  1  | not used
+ *      13 |  1  | image width in pixels (max. 80)     *see below
+ *      14 |  1  | not used
+ *      15 |  1  | image height in lines (max. 238)
+ *      16 |  1  | display option (?), standard set to $20
+ *      17 |  1  | author note length in bytes (max. 256)
+ *      18 |  2  | "T:" - text identifier
+ *      20 |  n  | author note
+ *    20+n |  1  | number of colors (fixed = 9 from Gr.10)
+ *    21+n |  3  | "CM:" - color map identifier
+ *    24+n |  9  | color values                        **see below
+ *    33+n |  3  | "PCK" - Multi RIP packed file only, means packed
+ *         |     |         images data
+ * 
+ * + * Directly after header images data are stored. First Gr.10, next Gr.9. + * + * HIP and RIP are 80 pixels wide pictures with shifted 9-color plan (Gr.10) + * relativelly to 16-grey shaded plan (Gr.9) for half pixel right. Thus, they + * appear as 160x200, but one pic has only 80x200; + * + * Number of colors is fixed to 9 now but it may change. So, take number of + * colors from 20+n byte of header (n - length of author note) for safety. (RIP + * mode 48 has more colors !!) + * + * Displaying RIP "1.x" picture routine is similar to HIP routine. The only + * difference is to set color registers with values put behind "CM:" while Gr.10 + * line. + * + * Information above is enough for writing own procedure showing RIP 1.x + * picture. For now I don't have any info about Multi RIP especially for + * compression algorithm and color palette. The only thing I know for sure is + * the palette should be changed every 2 scanlines. Maybe someone else knows a + * little bit more about Multi RIP (or RIP mode 48 with many more colors than + * mode 32)... + * + * Note: This implementation is based on FAIL 1.0.1 and allows 239 lines tough + * the specification above states 238 as the maximum. + */ +// TODO Verify against FAIL 1.0.2, check if the spurious grey spot and bugs are +// gone +public class LinearBitMapRIPConverter extends LinearBitMapConverter { + + private final static class RIPFile { + public static final byte RIP = 0x20; + public static final byte MULTI_RIP = 0x30; + + private int graphicsMode; + private int width; + private int height; + private int[] palette; + private byte[] unpackedImage; + + private RIPFile(int graphicsMode, int width, int height, int[] palette, + byte[] unpacked_image) { + this.graphicsMode = graphicsMode; + this.width = width; + this.height = height; + this.palette = palette; + this.unpackedImage = unpacked_image; + + } + + public static RIPFile createInstance(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + if (bytes.length < 23) { + return null; + } + int graphicsMode = bytes[7]; + int headerLength = (bytes[11] & 0xff) + 256 * (bytes[12] & 0xff); + int width = bytes[13] & 0xff; + int height = bytes[15] & 0xff; + int textLength = bytes[17] & 0xff; + if (bytes.length < 20 + textLength) { + return null; + } + int paletteLength = bytes[20 + textLength] & 0xff; + int dataLength = bytes.length - headerLength; + + if (bytes[0] != 'R' || bytes[1] != 'I' || bytes[2] != 'P' + || width > 80 || height > 239 || textLength > 152 + || bytes[18] != 'T' || bytes[19] != ':' + || paletteLength != 9 || bytes[21 + textLength] != 'C' + || bytes[22 + textLength] != 'M' + || bytes[23 + textLength] != ':') { + return null; + } + + byte[] unpackedImage = new byte[24576]; + + // Check compression mode. + switch (bytes[9]) { + case 0: + // No compression. + if (dataLength > unpackedImage.length) { + return null; + } + System.arraycopy(bytes, headerLength, unpackedImage, 0, + dataLength); + break; + + // Compression + case 1: + if (!ShannonFano.unpack(bytes, headerLength, dataLength, + unpackedImage)) { + return null; + } + break; + + default: + return null; + } + + // Check graphic mode + switch (graphicsMode) { + case RIP: + break; + case MULTI_RIP: + int frame_len = (width / 2) * height; + for (int y = 0; y < height; y++) { + for (int x = 0; x < 8; x++) { + int ix = 2 * frame_len + y * 8 + x; + if (y > 0 && unpackedImage[ix] == 0) + unpackedImage[ix] = unpackedImage[ix - 8]; + } + } + break; + default: + return null; + } + + int[] palette = new int[paletteLength]; + for (int i = 0; i < paletteLength; i++) { + palette[i] = bytes[24 + textLength + i] & 0xff; + } + RIPFile result = new RIPFile(graphicsMode, width, height, palette, + unpackedImage); + return result; + } + + public int getGraphicsMode() { + return graphicsMode; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int[] getPalette() { + return palette; + } + + public byte[] getUnpackedImage() { + return unpackedImage; + } + + } + + private static final class ShannonFano { + + private static void unpack_cnibl(byte data[], int dataOffset, int size, + int output[]) { + int x = dataOffset; + int y = 0; + while (y < size) { + int a = data[x++] & 0xff; + output[y++] = a >>> 4; + output[y++] = a & 0x0f; + } + } + + private static void unpack_sort(byte data[], int dataOffset, int size, + int tre01[], int tre02[]) { + int[] pom = new int[16]; + int y; + int x; + int md_ = 0; + int md = 0; + + unpack_cnibl(data, dataOffset, size, tre02); + + for (y = 0; y < size; y++) { + pom[tre02[y]]++; + } + + x = 0; + do { + y = 0; + do { + if (x == tre02[y]) { + tre01[md_++] = y; + } + y++; + } while (y < size); + x++; + } while (x < 16); + + x = 0; + do { + y = pom[x]; + while (y != 0) { + tre02[md++] = x; + y--; + } + x++; + } while (x < 16); + } + + private static void unpack_fano(byte data[], int dataOffset, int size, + int tre01[], int tre02[], int l0[], int h0[], int l1[], + int h1[], int lhOffset) { + int p; + int err; + int l; + int nxt; + int y; + + unpack_sort(data, dataOffset, size, tre01, tre02); + + clearMemory(l0, lhOffset, size); + clearMemory(l1, lhOffset, size); + clearMemory(h0, lhOffset, size); + clearMemory(h1, lhOffset, size); + + p = 0; + err = 0; + l = 0; + nxt = 0; + y = 0; + do { + if (tre02[y] != 0) { + int x; + int tmp; + int val; + int a; + p += err; + x = tre02[y]; + if (x != l) { + l = x; + err = 0x10000 >>> x; + } + tmp = p; + val = tre01[y]; + x = tre02[y]; + a = 0; + for (;;) { + int z = lhOffset + a; + x--; + tmp <<= 1; + if (tmp < 0x10000) { + if (x == 0) { + a = val; + l0[z] = a; + break; + } + a = h0[z]; + if (a == 0) { + a = ++nxt; + h0[z] = a; + } + } else { + tmp &= 0xFFFF; + if (x == 0) { + a = val; + l1[z] = a; + break; + } + a = h1[z]; + if (a == 0) { + a = ++nxt; + h1[z] = a; + } + } + } + } + y++; + } while (y < size); + } + + private static void clearMemory(int[] array, int offset, int size) { + for (int i = 0; i < size; i++) { + array[offset + i] = 0; + } + + } + + public static boolean unpack(byte data[], int dataOffset, + int dataLength, byte unpackedData[]) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (dataOffset < 0) { + throw new IllegalArgumentException( + "Parameter 'dataOffset' must not be negative, specified value is " + + dataOffset + "."); + } + if (unpackedData == null) { + throw new IllegalArgumentException( + "Parameter 'unpackedData' must not be null."); + } + int[] adl0 = new int[576]; + int[] adh0 = new int[576]; + int[] adl1 = new int[576]; + int[] adh1 = new int[576]; + + int[] tre01 = new int[256]; + int[] tre02 = new int[256]; + + int unpacked_len; + int sx, sxend; + int cx, dx; + int lic, csh, c; + + // "PCK" header (16 bytes) + 288 bytes shannon-fano + if (dataLength < 16 + 288 || data[dataOffset + 0] != 'P' + || data[dataOffset + 1] != 'C' + || data[dataOffset + 2] != 'K') { + return false; + } + + unpacked_len = (data[dataOffset + 4] & 0xff) + 256 + * (data[dataOffset + 5] & 0xff) - 33; + if (unpacked_len > 0x5EFE) { + return false; + } + + // Buggy pictures?! + if (unpacked_len == 16811) { + unpacked_len = 16800; + } + + unpack_fano(data, dataOffset + 16, 64, tre01, tre02, adl0, adh0, + adl1, adh1, 0); + unpack_fano(data, dataOffset + 16 + 32, 256, tre01, tre02, adl0, + adh0, adl1, adh1, 64); + unpack_fano(data, dataOffset + 16 + 160, 256, tre01, tre02, adl0, + adh0, adl1, adh1, 320); + + sx = dataOffset + 16 + 288; + sxend = dataOffset + dataLength + 1; + + dx = 0; + lic = -1; + csh = 0; + + do { + // GBIT(); + if (--lic < 0) { + if (sx >= sxend) { + return false; + } + csh = data[sx++] & 0xff; + lic = 7; + } + c = (csh & (1 << lic)); + + if (c == 0) { + int a = 0; + for (;;) { + int y = a; + + // GBIT(); + if (--lic < 0) { + if (sx >= sxend) { + return false; + } + csh = data[sx++] & 0xff; + lic = 7; + } + c = (csh & (1 << lic)); + + if (c == 0) { + if ((a = adh0[320 + y]) == 0) { + unpackedData[dx] = (byte) adl0[320 + y]; + break; + } + } else { + if ((a = adh1[320 + y]) == 0) { + unpackedData[dx] = (byte) adl1[320 + y]; + break; + } + } + } + ++dx; + } else { + int a = 0; + for (;;) { + int y = a; + + // GBIT(); + if (--lic < 0) { + if (sx >= sxend) { + return false; + } + csh = data[sx++] & 0xff; + lic = 7; + } + c = (csh & (1 << lic)); + + if (c == 0) { + if ((a = adh0[64 + y]) == 0) { + a = adl0[64 + y]; + break; + } + } else { + if ((a = adh1[64 + y]) == 0) { + a = adl1[64 + y]; + break; + } + } + } + cx = dx - (a + 2); + a = 0; + for (;;) { + int y = a; + + // GBIT(); + if (--lic < 0) { + if (sx >= sxend) { + return false; + } + csh = data[sx++] & 0xff; + lic = 7; + } + c = (csh & (1 << lic)); + + if (c == 0) { + if ((a = adh0[y]) == 0) { + a = adl0[y]; + break; + } + } else { + if ((a = adh1[y]) == 0) { + a = adl1[y]; + break; + } + } + } + + if (cx > 0) { + System.arraycopy(unpackedData, cx, unpackedData, dx, + a + 2); + } + dx += a + 2; + } + } while (dx < unpacked_len); + + return true; + } + } + + public LinearBitMapRIPConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + RIPFile ripFile = RIPFile.createInstance(bytes); + if (ripFile == null) { + return false; + } + return true; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + RIPFile ripFile = RIPFile.createInstance(bytes); + if (ripFile == null) { + throw new IllegalStateException("canConvertToImage() not called"); + } + + int columns; + int rows; + columns = (ripFile.getWidth() + 1) / 2; + rows = ripFile.getHeight(); + + setImageSizeAndPalette(data, columns, rows, Palette.TRUE_COLOR, null); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 4 + 1); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int rows = data.getParameters().getRows(); + int columns = data.getParameters().getColumns(); + PaletteMapper paletteMapper = new Atari8BitPaletteMapper(); + + // Compute palette. + RIPFile ripFile = RIPFile.createInstance(data + .getSourceFileBytes(BIT_MAP_FILE)); + if (ripFile == null) { + return false; + } + + byte[] unpackedImage = ripFile.getUnpackedImage(); + int[] graphics10Colors; + switch (ripFile.getGraphicsMode()) { + case RIPFile.RIP: + graphics10Colors = ripFile.getPalette(); + break; + case RIPFile.MULTI_RIP: + graphics10Colors = new int[ripFile.getPalette().length]; + break; + default: + throw new IllegalStateException("Unsupported graphics mode " + + ripFile.getGraphicsMode() + "."); + + } + + // Compute the offsets in the file. + int offset9, offset10; + int frameSize = rows * columns; + offset10 = 0; + offset9 = offset10 + frameSize; + + int[] buffer1 = new int[columns * 4 + 1]; + int[] buffer2 = new int[columns * 4 + 1]; + for (int y1 = 0; y1 < rows; y1++) { + + // MultiRIP mode? + if (ripFile.getGraphicsMode() == RIPFile.MULTI_RIP) { + int offset = frameSize * 2 + ((y1 >>> 1) << 3); + for (int i = 0; i < graphics10Colors.length - 1; i++) { + graphics10Colors[i + 1] = unpackedImage[offset + i] & 0xff; + } + } + + for (int x1 = 0; x1 < columns; x1++) { + if (offset9 >= unpackedImage.length) { + return true; + } + int byte9 = unpackedImage[offset9++]; + if (offset10 >= unpackedImage.length) { + return true; + } + int byte10 = unpackedImage[offset10++]; + + // Byte 1 is the GTIA 9 byte, take the values as brightness + // values + int color1 = (byte9 & mask_4bit[0]) >>> shift_4bit[0]; + int color2 = (byte9 & mask_4bit[1]) >>> shift_4bit[1]; + + // Byte 2 is the GTIA 10 byte, take the values from the GTIA 10 + // palette + int color3 = (byte10 & mask_4bit[0]) >>> shift_4bit[0]; + int color4 = (byte10 & mask_4bit[1]) >>> shift_4bit[1]; + color3 = graphics10Colors[Atari8BitUtility.GRAPHICS_10_REGISTERS[color3]]; + color4 = graphics10Colors[Atari8BitUtility.GRAPHICS_10_REGISTERS[color4]]; + + // Put the color values in the row buffer, shifted by 1 pixel + int x = x1 << 2; + buffer1[x + 0] = color1; + buffer1[x + 1] = color1; + buffer1[x + 2] = color2; + buffer1[x + 3] = color2; + + buffer2[x + 1] = color3; + buffer2[x + 2] = color3; + buffer2[x + 3] = color4; + buffer2[x + 4] = color4; + } + + // Merge the two buffers into combined color values. + for (int x = 0; x < buffer1.length; x++) { + int atariColor = RBGUtility.combineRGBColor( + paletteMapper.getRGBColor(buffer1[x]), + paletteMapper.getRGBColor(buffer2[x])); + data.setDirectPixel(x, y1, atariColor); + } + } + return true; + + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapTIPConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapTIPConverter.java new file mode 100644 index 00000000..757505a3 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/LinearBitMapTIPConverter.java @@ -0,0 +1,170 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atari8bit; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.ImageConverterData; +import com.wudsn.ide.gfx.converter.PaletteMapper; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.RBGUtility; + +/** + * Layout in the TIP picture is 9 bytes header, graphics 9 picture, graphics 10 + * picture, graphics 11 picture + */ +public class LinearBitMapTIPConverter extends LinearBitMapConverter { + + public LinearBitMapTIPConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + if (bytes.length < 9) { + return false; + } + + int frameLength = (bytes[7] & 0xff) + ((bytes[8] & 0xff) << 8); + if (bytes[0] != 'T' || bytes[1] != 'I' || bytes[2] != 'P' + || bytes[3] != 1 || bytes[4] != 0 || bytes[5] == 0 + || (bytes[5] & 0xff) > 160 || bytes[6] == 0 + || (bytes[6] & 0xff) > 119 + || (9 + frameLength * 3) != bytes.length) { + return false; + } + + return true; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + int columns; + int rows; + columns = (bytes[5] & 0xff) / 4; + rows = (bytes[6] & 0xff); + setImageSizeAndPalette(data, columns, rows, Palette.TRUE_COLOR, null); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 4 + 1); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int rows = data.getParameters().getRows(); + int columns = data.getParameters().getColumns(); + PaletteMapper paletteMapper=new Atari8BitPaletteMapper(); + + // Assume the binary is already merged in case of a 160012 bytes HIP. + int offset9, offset10, offset11; + + // Assume grey scale colors by default. + int[] graphics10Colors = { 0, 0, 2, 4, 6, 8, 10, 12, 14 }; + + // Compute the offsets in the file. + int frameSize = rows * columns; + offset9 = 9; + offset10 = offset9 + frameSize; + offset11 = offset10 + frameSize; + + int[] buffer1 = new int[columns * 4 + 1]; + int[] buffer2 = new int[columns * 4 + 1]; + for (int y1 = 0; y1 < rows; y1++) { + for (int x1 = 0; x1 < columns; x1++) { + int byte1 = data.getSourceFileByte(BIT_MAP_FILE, offset9++); + if (byte1 < 0) { + return true; + } + int byte2 = data.getSourceFileByte(BIT_MAP_FILE, offset10++); + if (byte2 < 0) { + return true; + } + int byte3 = data.getSourceFileByte(BIT_MAP_FILE, offset11++); + if (byte3 < 0) { + return true; + } + // Byte 1 is the GTIA 9 byte, take the values as brightness + // values + int brightness1 = (byte1 & mask_4bit[0]) >>> shift_4bit[0]; + int brightness2 = (byte1 & mask_4bit[1]) >>> shift_4bit[1]; + + // Byte 2 is the GTIA 10 byte, take the values from the GTIA 10 + // palette + int brightness3 = (byte2 & mask_4bit[0]) >>> shift_4bit[0]; + int brightness4 = (byte2 & mask_4bit[1]) >>> shift_4bit[1]; + brightness3 = graphics10Colors[Atari8BitUtility.GRAPHICS_10_REGISTERS[brightness3]]; + brightness4 = graphics10Colors[Atari8BitUtility.GRAPHICS_10_REGISTERS[brightness4]]; + + // Byte 3 is the GTIA 11 byte, take the values as color values + int color1 = (byte3 & 0xf0); + int color2 = (byte3 & 0x0f) << 4; + + // Put the color values in the row buffer, shifted by 1 pixel + int x = x1 << 2; + buffer1[x + 0] = color1 | brightness1; + buffer1[x + 1] = color1 | brightness1; + buffer1[x + 2] = color2 | brightness2; + buffer1[x + 3] = color2 | brightness2; + + buffer2[x + 1] = color1 | brightness3; + buffer2[x + 2] = color1 | brightness3; + buffer2[x + 3] = color2 | brightness4; + buffer2[x + 4] = color2 | brightness4; + } + + // Merge the two buffers into combined color values. + for (int x = 0; x < buffer1.length; x++) { + int atariColor = RBGUtility.combineRGBColor( + paletteMapper.getRGBColor(buffer1[x]), + paletteMapper.getRGBColor(buffer2[x])); + data.setDirectPixel(x, y1, atariColor); + } + } + return true; + } + + public static void convertToFileData(ImageConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/altirra.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/altirra.act new file mode 100644 index 00000000..59e9be3a Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/altirra.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/atari800winplus.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/atari800winplus.act new file mode 100644 index 00000000..3ee8ebf8 Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/atari800winplus.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/c64.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/c64.act new file mode 100644 index 00000000..37f3a6eb Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/c64.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/default.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/default.act new file mode 100644 index 00000000..3ee8ebf8 Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/default.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/g2f.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/g2f.act new file mode 100644 index 00000000..fb76d4cb Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/g2f.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/gray.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/gray.act new file mode 100644 index 00000000..3422b067 Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/gray.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/green.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/green.act new file mode 100644 index 00000000..60858b3e Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/green.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/jakub.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/jakub.act new file mode 100644 index 00000000..396a5cf3 Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/jakub.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/laoo.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/laoo.act new file mode 100644 index 00000000..5f33ecab Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/laoo.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/olivierp.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/olivierp.act new file mode 100644 index 00000000..ea0a70d0 Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/olivierp.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/real.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/real.act new file mode 100644 index 00000000..e36ffd72 Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/real.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/xformer.act b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/xformer.act new file mode 100644 index 00000000..ab4d10ea Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atari8bit/palettes/xformer.act differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atarist/InterleavedBitMap4Planes.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atarist/InterleavedBitMap4Planes.java new file mode 100644 index 00000000..c7e7cf90 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/atarist/InterleavedBitMap4Planes.java @@ -0,0 +1,134 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.atarist; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.generic.LinearBitMapConverter; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +/** + * TODO Implement Atari ST Conversion + * + * @author Peter Dell + * + */ +public class InterleavedBitMap4Planes extends LinearBitMapConverter { + + public InterleavedBitMap4Planes() { + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException("Parameter 'bytes' must not be null."); + } + return bytes.length > 0 && bytes.length % 80 == 0; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException("Parameter 'bytes' must not be null."); + } + + RGB[] paletteColors; + paletteColors = PaletteUtility.getPaletteColors(PaletteType.ATARI_DEFAULT, Palette.GTIA_GREY_1, null); + setImageSizeAndPalette(data, 40, 192, Palette.GTIA_GREY_1, paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() * 16); + data.setImageDataHeight(data.getParameters().getRows()); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + + final int[] mask_1bit = new int[] { 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100, 0x80, 0x40, + 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + final int[] shift_1bit = new int[] { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + + int offset_line = 0; + int xpixels = 16; + + for (int y1 = data.getParameters().getRows() - 1; y1 >= 0; y1--) { + int offset = offset_line; + offset_line += 27 * 8; + + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int w1 = getWord(data, offset); + if (w1 < 0) { + return true; + } + offset += 2; + int w2 = getWord(data, offset); + if (w2 < 0) { + return true; + } + offset += 2; + int w3 = getWord(data, offset); + if (w3 < 0) { + return true; + } + offset += 2; + int w4 = getWord(data, offset); + if (w4 < 0) { + return true; + } + offset += 2; + + for (int x2 = 0; x2 < 16; x2++) { + int x = x1 * xpixels + 15 - x2; + int shift = shift_1bit[x2]; + int mask = mask_1bit[x2]; + int color = ((w1 & mask) >>> shift) + (((w2 & mask) >>> shift) << 1) + + (((w3 & mask) >>> shift) << 2) + (((w4 & mask) >>> shift) << 3); + data.setPalettePixel(x, y1, color); + } + + } + } + return true; + } + + private int getWord(FilesConverterData data, int offset) { + int b2 = data.getSourceFileByte(BIT_MAP_FILE, offset + 1); + if (b2 < 0) { + return b2; + } + int b1 = data.getSourceFileByte(BIT_MAP_FILE, offset); + if (b1 < 0) { + return b1; + } + return b1 + (b2 << 8); + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/C64PaletteMapper.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/C64PaletteMapper.java new file mode 100644 index 00000000..df290460 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/C64PaletteMapper.java @@ -0,0 +1,57 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.c64; + +import com.wudsn.ide.gfx.converter.PaletteMapper; + +// TODO C64PaletteMapper is not yet used. Will be required for Koala pictures etc. +/** + * C64 to Atari Mapping + * + *
+ *  0	Black		0,0	0,2
+ *  1	White		0,15	0,14
+ *  2	Red		3,5	3,6
+ *  3	Cyan		9,11	9,12
+ *  4	Purple		4,7	5,8
+ *  5	Green		11,8	11,10
+ *  6	Blue		7,5	7,6
+ *  7	Yellow		14,14	14,14
+ *  8	Orange		1,5	1,12 (Light Brown)
+ *  9	Brown		14,4	1,8
+ * 10	Light Red	3,10	3,12 (Pink)
+ * 11	Dark Grey	0,6	0,6
+ * 12	Med Grey	0,9	0,10
+ * 13	Light Green	11,13	11,14
+ * 14	Light Blue	6,10	7,10
+ * 15	Light Grey	0,11	0,12
+ * 
+ */ +public final class C64PaletteMapper extends PaletteMapper{ + + /** + * Creation is private. + */ + public C64PaletteMapper() { + super(16); + // From http://unusedino.de/ec64/technical/misc/vic656x/colors/index.html + loadPalette("pepto.pal"); + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/C64Utility.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/C64Utility.java new file mode 100644 index 00000000..3d1509a9 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/C64Utility.java @@ -0,0 +1,86 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.c64; + +import com.wudsn.ide.base.common.NumberFactory; + +/** + * C64Utility color codes as defined by VIC II. + * + * @author Peter Dell + * + */ +public final class C64Utility { + + public static final Integer BLACK = NumberFactory.getInteger(0); + public static final Integer WHITE = NumberFactory.getInteger(1); + public static final Integer RED = NumberFactory.getInteger(2); + public static final Integer CYAN = NumberFactory.getInteger(3); + public static final Integer PINK = NumberFactory.getInteger(4); + public static final Integer GREEN = NumberFactory.getInteger(5); + public static final Integer BLUE = NumberFactory.getInteger(6); + public static final Integer YELLOW = NumberFactory.getInteger(7); + public static final Integer ORANGE = NumberFactory.getInteger(8); + public static final Integer BROWN = NumberFactory.getInteger(9); + public static final Integer LIGHT_RED = NumberFactory.getInteger(10); + public static final Integer DARK_GRAY = NumberFactory.getInteger(11); + public static final Integer MEDIUM_GRAY = NumberFactory.getInteger(12); + public static final Integer LIGHT_GREEN = NumberFactory.getInteger(13); + public static final Integer LIGHT_BLUE = NumberFactory.getInteger(14); + public static final Integer LIGHT_GRAY = NumberFactory.getInteger(15); + + /** + * Determines if a byte array represents a valid C64 charset. + * + * @param bytes + * The byte array, may be empty, not null. + * @return true if the byte array represents a valid C64 + * charset, false otherwise. + * + * @since 1.6.0 + */ + public static boolean isC64Charset(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 2048 || bytes.length % 0x100 == 2 + || (bytes.length > 2 && bytes[0] == 0x00 && bytes[1] == 0x38); + } + + /** + * Determines if a byte array represents a valid C64 sprite (or many). + * + * @param bytes + * The byte array, may be empty, not null. + * @return true if the byte array represents a valid C64 sprite + * (or many), false otherwise. + * + * @since 1.6.0 + */ + public static boolean isC64Sprite(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + return bytes.length == 64 + || (bytes.length > 2 + 64 && bytes[0] == 0x00); + } +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/SpriteConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/SpriteConverter.java new file mode 100644 index 00000000..ffbe4d83 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/SpriteConverter.java @@ -0,0 +1,34 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.c64; + +import com.wudsn.ide.gfx.converter.Converter; + +public abstract class SpriteConverter extends Converter { + + /** + * Source file ids. + */ + public static final int SPRITE_FILE = 0; + + + protected SpriteConverter() { + } +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/SpriteHiresConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/SpriteHiresConverter.java new file mode 100644 index 00000000..67db2f56 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/SpriteHiresConverter.java @@ -0,0 +1,119 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.c64; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +public class SpriteHiresConverter extends SpriteConverter { + + public SpriteHiresConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + boolean c64Sprite = C64Utility.isC64Sprite(bytes); + return c64Sprite; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + int columns = 8; + int lineSize = columns * 64; + int rows; + if (bytes.length % 0x100 == 2) { + data.getParameters().getSourceFile(SpriteConverter.SPRITE_FILE) + .setOffset(2); + rows = (bytes.length - 2 + lineSize - 1) / lineSize; + + } else { + rows = (bytes.length + lineSize - 1) / lineSize; + } + + RGB[] paletteColors; + paletteColors = PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.HIRES_1, null); + setImageSizeAndPalette(data, columns, rows, Palette.HIRES_1, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() + * (3 * 8 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight(data.getParameters().getRows() + * (21 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 3 * 8 + data.getParameters().getSpacingWidth(); + int ypixels = 21 + data.getParameters().getSpacingWidth(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < (data.getParameters().getColumns()); x1++) { + for (int y2 = 0; y2 < 21; y2++) { + for (int x2 = 0; x2 < 3; x2++) { + int b = data.getSourceFileByte(SPRITE_FILE, offset++); + if (b < 0) { + return true; + } + + int y = y1 * ypixels + y2; + for (int x3 = 0; x3 < 8; x3++) { + int x = x1 * xpixels + x2 * 8 + x3; + + int color = (b & mask_1bit[x3]) >>> shift_1bit[x3]; + data.setPalettePixel(x, y, color); + } + } + } + offset++; // 64th byte + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/SpriteMultiColorConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/SpriteMultiColorConverter.java new file mode 100644 index 00000000..b67d0103 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/SpriteMultiColorConverter.java @@ -0,0 +1,72 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.c64; + +import com.wudsn.ide.gfx.converter.FilesConverterData; + +public class SpriteMultiColorConverter extends SpriteConverter { + + public SpriteMultiColorConverter() { + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() + * (3 * 4 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight(data.getParameters().getRows() + * (21 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 3 * 4 + data.getParameters().getSpacingWidth(); + int ypixels = 21 + data.getParameters().getSpacingWidth(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < (data.getParameters().getColumns()); x1++) { + for (int y2 = 0; y2 < 21; y2++) { + for (int x2 = 0; x2 < 3; x2++) { + int b = data.getSourceFileByte(SPRITE_FILE, offset++); + if (b < 0) { + return true; + } + + int y = y1 * ypixels + y2; + for (int x3 = 0; x3 < 4; x3++) { + int x = x1 * xpixels + x2 * 4 + x3; + + int color = (b & mask_2bit[x3]) >>> shift_2bit[x3]; + data.setPalettePixel(x, y, color); + } + } + } + offset++; // 64th byte + } + } + return true; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/palettes/pepto.pal b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/palettes/pepto.pal new file mode 100644 index 00000000..5a54b136 Binary files /dev/null and b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/c64/palettes/pepto.pal differ diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/BitMapConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/BitMapConverter.java new file mode 100644 index 00000000..6f99d075 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/BitMapConverter.java @@ -0,0 +1,35 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import com.wudsn.ide.gfx.converter.Converter; + +public abstract class BitMapConverter extends Converter { + + /** + * Source file ids. + */ + public static final int BIT_MAP_FILE = 0; + + protected BitMapConverter() { + + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharMapConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharMapConverter.java new file mode 100644 index 00000000..2c6c2a51 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharMapConverter.java @@ -0,0 +1,36 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import com.wudsn.ide.gfx.converter.Converter; + +public abstract class CharMapConverter extends Converter { + + /** + * Source file ids. + */ + public static final int CHAR_SET_FILE = 0; + public static final int CHAR_MAP_FILE = 1; + + public CharMapConverter() { + + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharMapHiresConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharMapHiresConverter.java new file mode 100644 index 00000000..2096957c --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharMapHiresConverter.java @@ -0,0 +1,76 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import com.wudsn.ide.gfx.converter.FilesConverterData; + +public class CharMapHiresConverter extends CharMapConverter { + + public CharMapHiresConverter() { + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() + * (8 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight(data.getParameters().getRows() + * (8 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + int offset = 0; + int xpixels = 8 + data.getParameters().getSpacingWidth(); + int ypixels = 8 + data.getParameters().getSpacingWidth(); + + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int c = data.getSourceFileByte(CHAR_MAP_FILE, offset++) & 127; + if (c < 0) { + return true; + } + int charset_offset = c * 8; + for (int y2 = 0; y2 < 8; y2++) { + int b = data.getSourceFileByte(CHAR_SET_FILE, + charset_offset++); + + if (b < 0) { + return true; + } + int y = y1 * ypixels + y2; + for (int x2 = 0; x2 < 8; x2++) { + int x = x1 * xpixels + x2; + + int color = (b & mask_1bit[x2]) >>> shift_1bit[x2]; + data.setPalettePixel(x, y, color); + } + } + } + } + return false; + + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharMapMultiColorConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharMapMultiColorConverter.java new file mode 100644 index 00000000..04681b13 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharMapMultiColorConverter.java @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import com.wudsn.ide.gfx.converter.FilesConverterData; + +public class CharMapMultiColorConverter extends CharMapConverter { + + public CharMapMultiColorConverter() { + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() + * (4 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight(data.getParameters().getRows() + * (8 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 4 + data.getParameters().getSpacingWidth(); + int ypixels = 8 + data.getParameters().getSpacingWidth(); + +// int[] fonts = new int[] { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, +// 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 3, 0, 1, 4,0 }; + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + int c = data.getSourceFileByte(CHAR_MAP_FILE, offset++) & 127; + if (c < 0) { + return true; + } + int charset_offset = c * 8; // + fonts[y1] * 1024; + for (int y2 = 0; y2 < 8; y2++) { + int b = data.getSourceFileByte(CHAR_SET_FILE, + charset_offset++); + + if (b < 0) { + return true; + } + int y = y1 * ypixels + y2; + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + x2; + + int color = (b & mask_2bit[x2]) >>> shift_2bit[x2]; + data.setPalettePixel(x, y, color); + } + } + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1HiresConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1HiresConverter.java new file mode 100644 index 00000000..20257c2b --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1HiresConverter.java @@ -0,0 +1,123 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.atari8bit.Atari8BitUtility; +import com.wudsn.ide.gfx.converter.c64.C64Utility; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +public class CharSet1x1HiresConverter extends CharSetConverter { + + public CharSet1x1HiresConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + boolean atariCharset = Atari8BitUtility.isAtariCharset(bytes); + boolean c64Charset = C64Utility.isC64Charset(bytes); + return atariCharset || c64Charset; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + int columns = 32; + int lineSize = columns * 8; + int rows; + if ((bytes.length == 1024 + 6 && Atari8BitUtility + .getLengthFromBinaryHeader(bytes, 0) == 1024)) { + data.getParameters().getSourceFile(CharSetConverter.CHAR_SET_FILE) + .setOffset(6); + + rows = (bytes.length - 6 + lineSize - 1) / lineSize; + } else if (bytes.length % 0x100 == 2 + || (bytes.length > 2 && bytes[0] == 0x00 && bytes[1] == 0x38)) { + data.getParameters().getSourceFile(CharSetConverter.CHAR_SET_FILE) + .setOffset(2); + rows = (bytes.length - 2 + lineSize - 1) / lineSize; + + } else { + rows = (bytes.length + lineSize - 1) / lineSize; + } + + RGB[] paletteColors; + paletteColors = PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.HIRES_1, null); + setImageSizeAndPalette(data, columns, rows, Palette.HIRES_1, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() + * (8 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight(data.getParameters().getRows() + * (8 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 8 + data.getParameters().getSpacingWidth(); + int ypixels = 8 + data.getParameters().getSpacingWidth(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + for (int y2 = 0; y2 < 8; y2++) { + int b = data.getSourceFileByte(CHAR_SET_FILE, offset++); + if (b < 0) { + return true; + } + int y = y1 * ypixels + y2; + for (int x2 = 0; x2 < 8; x2++) { + int x = x1 * xpixels + x2; + int color = (b & mask_1bit[x2]) >>> shift_1bit[x2]; + data.setPalettePixel(x, y, color); + } + } + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1HiresConverter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1HiresConverter.js new file mode 100644 index 00000000..b1f8f6b6 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1HiresConverter.js @@ -0,0 +1,28 @@ +function convertToFileData(data) { + var columns = data.getImageDataWidth() / 8; + var rows = data.getImageDataHeight() / 8; + var chars = 256; + + var char = 0; + var bytes = []; + var offset = 0; + for (var r = 0; r < rows; r++) { + for (var c = 0; c < columns; c++) { + if (char < chars) { + for (var l=0;l<8;l++) { + var b = 0; + for (var p = 0; p < 8; p++) { + var color; + color = data.getPixel(c*8+p, r*8+l); + if (color != 0) { + b = b | 1 << 7 - p; + } + } + bytes[offset++] = b; + } + char++; + } + } + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1MultiColorConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1MultiColorConverter.java new file mode 100644 index 00000000..88a7fefe --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1MultiColorConverter.java @@ -0,0 +1,69 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import com.wudsn.ide.gfx.converter.FilesConverterData; + +public class CharSet1x1MultiColorConverter extends CharSetConverter { + + public CharSet1x1MultiColorConverter() { + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() + * (4 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight(data.getParameters().getRows() + * (8 + data.getParameters().getSpacingWidth())); + } + + + @Override + public boolean convertToImageData(FilesConverterData data) { + + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 4 + data.getParameters().getSpacingWidth(); + int ypixels = 8 + data.getParameters().getSpacingWidth(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + for (int y2 = 0; y2 < 8; y2++) { + int b = data.getSourceFileByte(CHAR_SET_FILE, offset++); + if (b < 0) { + return true; + } + int y = y1 * ypixels + y2; + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + x2; + int color = (b & mask_2bit[x2]) >>> shift_2bit[x2]; + data.setPalettePixel(x, y, color); + } + } + } + } + return true; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1MultiColorConverter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1MultiColorConverter.js new file mode 100644 index 00000000..18a5307d --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet1x1MultiColorConverter.js @@ -0,0 +1,29 @@ +function convertToFileData(data) { + var columns = data.getImageDataWidth() / 8; + var rows = data.getImageDataHeight() / 8; + var chars = 256; + + var char = 0; + var bytes = []; + var offset = 0; + for (var r = 0; r < rows; r++) { + for (var c = 0; c < columns; c++) { + if (char < chars) { + for (var l=0;l<8;l++) { + var b; + var x,y,c1,c2,c3,c4; + x = c*4; + y = r*8 + l; + c1 = data.getPixel(x, y) & 0x3; + c2 = data.getPixel(x+1, y) & 0x3; + c3 = data.getPixel(x+2, y) & 0x3; + c4 = data.getPixel(x+3, y) & 0x3; + b = c1 << 6 | c2 << 4 | c3 << 2 | c4; + bytes[offset++] = b; + } + char++; + } + } + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x1HiresConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x1HiresConverter.java new file mode 100644 index 00000000..bf42fee1 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x1HiresConverter.java @@ -0,0 +1,127 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.atari8bit.Atari8BitUtility; +import com.wudsn.ide.gfx.converter.c64.C64Utility; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +public class CharSet2x1HiresConverter extends CharSetConverter { + + public CharSet2x1HiresConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + boolean atariCharset = Atari8BitUtility.isAtariCharset(bytes); + boolean c64Charset =C64Utility.isC64Charset(bytes); + return atariCharset || c64Charset; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + int columns = 16; + int lineSize = columns * 8*2; + int rows; + if ((bytes.length == 1024 + 6 && Atari8BitUtility + .getLengthFromBinaryHeader(bytes, 0) == 1024)) { + data.getParameters().getSourceFile(CharSetConverter.CHAR_SET_FILE) + .setOffset(6); + + rows = (bytes.length - 6 + lineSize - 1) / lineSize; + } else if (bytes.length % 0x100 == 2) { + data.getParameters().getSourceFile(CharSetConverter.CHAR_SET_FILE) + .setOffset(2); + rows = (bytes.length - 2 + lineSize - 1) / lineSize; + + } else { + rows = (bytes.length + lineSize - 1) / lineSize; + } + + RGB[] paletteColors; + paletteColors = PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.HIRES_1, null); + setImageSizeAndPalette(data, columns, rows, Palette.HIRES_1, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth((data.getParameters().getColumns()) + * (8 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight((data.getParameters().getRows()) + * (16 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 8 + data.getParameters().getSpacingWidth(); + int ypixels = 16 + data.getParameters().getSpacingWidth(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + for (int cy = 0; cy < 2; cy++) { + for (int cx = 0; cx < 1; cx++) { + for (int y2 = 0; y2 < 8; y2++) { + int b = data.getSourceFileByte(CHAR_SET_FILE, + offset++); + if (b < 0) { + return true; + } + int y = y1 * ypixels + cy * 8 + y2; + for (int x2 = 0; x2 < 8; x2++) { + int x = x1 * xpixels + cx * 8 + x2; + int color = (b & mask_1bit[x2]) >>> shift_1bit[x2]; + data.setPalettePixel(x, y, color); + } + } + } + } + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x1HiresConverter.js b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x1HiresConverter.js new file mode 100644 index 00000000..7874cd36 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x1HiresConverter.js @@ -0,0 +1,28 @@ +function convertToFileData(data) { + var columns = data.getImageDataWidth() / 8; + var rows = data.getImageDataHeight() / 16; + var chars = 256; + + var char = 0; + var bytes = []; + var offset = 0; + for (var r = 0; r < rows; r++) { + for (var c = 0; c < columns; c++) { + if (char < chars) { + for (var l=0;l<16;l++) { + var b = 0; + for (var p = 0; p < 8; p++) { + var color; + color = data.getPixel(c*8+p, r*16+l); + if (color != 0) { + b = b | 1 << 7 - p; + } + } + bytes[offset++] = b; + } + char++; + } + } + } + data.setTargetFileObject(0, bytes); +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x2HiresConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x2HiresConverter.java new file mode 100644 index 00000000..9ed39fa9 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x2HiresConverter.java @@ -0,0 +1,128 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.atari8bit.Atari8BitUtility; +import com.wudsn.ide.gfx.converter.c64.C64Utility; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +// TODO Have base class for n*m charset converters +public class CharSet2x2HiresConverter extends CharSetConverter { + + public CharSet2x2HiresConverter() { + + } + + @Override + public boolean canConvertToImage(byte[] bytes) { + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + boolean atariCharset = Atari8BitUtility.isAtariCharset(bytes); + boolean c64Charset =C64Utility.isC64Charset(bytes); + return atariCharset || c64Charset; + } + + @Override + public void convertToImageSizeAndPalette(FilesConverterData data, + byte[] bytes) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + if (bytes == null) { + throw new IllegalArgumentException( + "Parameter 'bytes' must not be null."); + } + + int columns = 16; + int lineSize = columns * 8*4; + int rows; + if ((bytes.length == 1024 + 6 && Atari8BitUtility + .getLengthFromBinaryHeader(bytes, 0) == 1024)) { + data.getParameters().getSourceFile(CharSetConverter.CHAR_SET_FILE) + .setOffset(6); + + rows = (bytes.length - 6 + lineSize - 1) / lineSize; + } else if (bytes.length % 0x100 == 2) { + data.getParameters().getSourceFile(CharSetConverter.CHAR_SET_FILE) + .setOffset(2); + rows = (bytes.length - 2 + lineSize - 1) / lineSize; + + } else { + rows = (bytes.length + lineSize - 1) / lineSize; + } + + RGB[] paletteColors; + paletteColors = PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.HIRES_1, null); + setImageSizeAndPalette(data, columns, rows, Palette.HIRES_1, + paletteColors); + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth((data.getParameters().getColumns()) + * (16 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight((data.getParameters().getRows()) + * (16 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 16 + data.getParameters().getSpacingWidth(); + int ypixels = 16 + data.getParameters().getSpacingWidth(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + for (int cy = 0; cy < 2; cy++) { + for (int cx = 0; cx < 2; cx++) { + for (int y2 = 0; y2 < 8; y2++) { + int b = data.getSourceFileByte(CHAR_SET_FILE, + offset++); + if (b < 0) { + return true; + } + int y = y1 * ypixels + cy * 8 + y2; + for (int x2 = 0; x2 < 8; x2++) { + int x = x1 * xpixels + cx * 8 + x2; + int color = (b & mask_1bit[x2]) >>> shift_1bit[x2]; + data.setPalettePixel(x, y, color); + } + } + } + } + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x2MultiColorConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x2MultiColorConverter.java new file mode 100644 index 00000000..7b5eb17f --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSet2x2MultiColorConverter.java @@ -0,0 +1,72 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import com.wudsn.ide.gfx.converter.FilesConverterData; + +public class CharSet2x2MultiColorConverter extends CharSetConverter { + + public CharSet2x2MultiColorConverter() { + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth((data.getParameters().getColumns()) + * (8 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight((data.getParameters().getRows()) + * (16 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 8 + data.getParameters().getSpacingWidth(); + int ypixels = 16 + data.getParameters().getSpacingWidth(); + + for (int y1 = 0; y1 < data.getParameters().getRows() ; y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns() ; x1++) { + for (int cy = 0; cy < 2; cy++) { + for (int cx = 0; cx < 2; cx++) { + for (int y2 = 0; y2 < 8; y2++) { + int b = data.getSourceFileByte(CHAR_SET_FILE, + offset++); + if (b < 0) { + return true; + } + int y = y1 * ypixels + cy * 8 + y2; + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + cx * 4 + x2; + int color = (b & mask_2bit[x2]) >>> shift_2bit[x2]; + data.setPalettePixel(x, y, color); + } + } + } + } + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSetConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSetConverter.java new file mode 100644 index 00000000..85c292f2 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/CharSetConverter.java @@ -0,0 +1,33 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import com.wudsn.ide.gfx.converter.Converter; + +public abstract class CharSetConverter extends Converter { + + /** + * Source file ids. + */ + public static final int CHAR_SET_FILE = 0; + + public CharSetConverter() { + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/LinearBitMapConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/LinearBitMapConverter.java new file mode 100644 index 00000000..274fe60c --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/LinearBitMapConverter.java @@ -0,0 +1,31 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + + +public abstract class LinearBitMapConverter extends BitMapConverter { + + + + protected LinearBitMapConverter() { + + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMap2x2MultiColorConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMap2x2MultiColorConverter.java new file mode 100644 index 00000000..bad74331 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMap2x2MultiColorConverter.java @@ -0,0 +1,121 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.c64.C64Utility; + +public class TiledBitMap2x2MultiColorConverter extends TiledBitMapConverter { + + public TiledBitMap2x2MultiColorConverter() { + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() + * (8 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight(data.getParameters().getRows() + * (16 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + int[] colors = new int[] { 0x191d19, 0xfcf9fc, 0x933a4c, 0xb6fafa, + 0xd27ded, 0x6acf6f, 0x4f44d8, 0xfbfb8b, 0xd89c5b, 0x7f5307, + 0xef839f, 0x575753, 0xa3a7a7, 0xb7ffbbf, 0xa397ff, 0xefe9e7 }; + + for (int i = 0; i < 16; i++) { + int r = (colors[i] >> 16) & 0xff; + int g = (colors[i] >> 8) & 0xff; + int b = (colors[i] >> 0) & 0xff; + data.getImageData().palette.colors[i] = new RGB(r, g, b); + } + + int tile = 0; + int bitmap_offset = 0; + int video_ram_offset = 0; + int color_ram_offset = 0; + int xpixels = 8 + data.getParameters().getSpacingWidth(); + int ypixels = 16 + data.getParameters().getSpacingWidth(); + int rows = data.getParameters().getRows(); + int columns = data.getParameters().getColumns(); + + int[] cell_colors = new int[] { 0, 1, 2, 3 }; + + for (int y1 = 0; y1 < rows; y1++) { + for (int x1 = 0; x1 < columns; x1++) { + video_ram_offset = tile * 4; + color_ram_offset = tile * 2; + for (int y2 = 0; y2 < 2; y2++) { + for (int x2 = 0; x2 < 2; x2++) { + int v = data.getSourceFileByte(VIDEO_RAM_FILE, + video_ram_offset + y2 * 2 + x2); + int c = data.getSourceFileByte(COLOR_RAM_FILE, + color_ram_offset + y2); + if (v >= 0 && c >= 0) { + cell_colors[1] = (v >> 4) & 0xf; + cell_colors[2] = (v >> 0) & 0xf; + if (x2 == 0) { + cell_colors[3] = (c >> 4) & 0xf; + } else { + cell_colors[3] = (c >> 0) & 0xf; + + } + + } else { + cell_colors[1] = C64Utility.RED.intValue(); + cell_colors[2] = C64Utility.LIGHT_RED.intValue(); + cell_colors[3] = C64Utility.WHITE.intValue(); + } + + for (int y3 = 0; y3 < 8; y3++) { + int b = data.getSourceFileByte(BIT_MAP_FILE, + bitmap_offset++); + if (b < 0) { + return true; + } + + int y = y1 * ypixels + y2 * 8 + y3; + for (int x3 = 0; x3 < 4; x3++) { + int x = x1 * xpixels + x2 * 4 + x3; + + int color = (b & mask_2bit[x3]) >>> shift_2bit[x3]; + data.setPalettePixel(x, y, cell_colors[color]); + } + } + + } + } + color_ram_offset += 4; + video_ram_offset += 4; + tile++; + + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMapConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMapConverter.java new file mode 100644 index 00000000..62e71964 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMapConverter.java @@ -0,0 +1,35 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + + +public abstract class TiledBitMapConverter extends BitMapConverter { + + /** + * Source file ids. + */ + public static final int VIDEO_RAM_FILE = 1; + public static final int COLOR_RAM_FILE = 2; + + protected TiledBitMapConverter() { + + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMapHiresConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMapHiresConverter.java new file mode 100644 index 00000000..78a8ffdc --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMapHiresConverter.java @@ -0,0 +1,67 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import com.wudsn.ide.gfx.converter.FilesConverterData; + +public class TiledBitMapHiresConverter extends TiledBitMapConverter { + + public TiledBitMapHiresConverter() { + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() + * (8 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight(data.getParameters().getRows() + * (8 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 8 + data.getParameters().getSpacingWidth(); + int ypixels = 8 + data.getParameters().getSpacingWidth(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + for (int y2 = 0; y2 < 8; y2++) { + int b = data.getSourceFileByte(BIT_MAP_FILE, offset++); + if (b < 0) { + return true; + } + int y = y1 * ypixels + y2; + for (int x2 = 0; x2 < 8; x2++) { + int x = x1 * xpixels + x2; + int color = (b & mask_1bit[x2]) >>> shift_1bit[x2]; + data.setPalettePixel(x, y, color); + } + } + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMapMultiColorConverter.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMapMultiColorConverter.java new file mode 100644 index 00000000..a2f7be8e --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/converter/generic/TiledBitMapMultiColorConverter.java @@ -0,0 +1,68 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.converter.generic; + +import com.wudsn.ide.gfx.converter.FilesConverterData; + +public class TiledBitMapMultiColorConverter extends TiledBitMapConverter { + + public TiledBitMapMultiColorConverter() { + + } + + @Override + public void convertToImageDataSize(FilesConverterData data) { + data.setImageDataWidth(data.getParameters().getColumns() + * (4 + data.getParameters().getSpacingWidth())); + data.setImageDataHeight(data.getParameters().getRows() + * (8 + data.getParameters().getSpacingWidth())); + } + + @Override + public boolean convertToImageData(FilesConverterData data) { + if (data == null) { + throw new IllegalArgumentException( + "Parameter 'data' must not be null."); + } + + int offset = 0; + int xpixels = 4 + data.getParameters().getSpacingWidth(); + int ypixels = 8 + data.getParameters().getSpacingWidth(); + + for (int y1 = 0; y1 < data.getParameters().getRows(); y1++) { + for (int x1 = 0; x1 < data.getParameters().getColumns(); x1++) { + for (int y2 = 0; y2 < 8; y2++) { + int b = data.getSourceFileByte(BIT_MAP_FILE, offset++); + if (b < 0) { + return true; + } + int y = y1 * ypixels + y2; + for (int x2 = 0; x2 < 4; x2++) { + int x = x1 * xpixels + x2; + + int color = (b & mask_2bit[x2]) >>> shift_2bit[x2]; + data.setPalettePixel(x, y, color); + } + } + } + } + return true; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/FilesConverterDataView.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/FilesConverterDataView.java new file mode 100644 index 00000000..d38aa200 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/FilesConverterDataView.java @@ -0,0 +1,327 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.editor; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.preference.ColorSelector; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.TraverseEvent; +import org.eclipse.swt.events.TraverseListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +import com.wudsn.ide.base.common.NumberUtility; +import com.wudsn.ide.base.gui.Action; +import com.wudsn.ide.base.gui.FilePathField; +import com.wudsn.ide.base.gui.IntegerField; +import com.wudsn.ide.base.gui.MessageManager; +import com.wudsn.ide.base.gui.SWTFactory; +import com.wudsn.ide.gfx.Texts; +import com.wudsn.ide.gfx.converter.Converter; +import com.wudsn.ide.gfx.converter.ConverterCommonParameters; +import com.wudsn.ide.gfx.converter.ConverterSourceFileDefinition; +import com.wudsn.ide.gfx.converter.FilesConverterData; +import com.wudsn.ide.gfx.converter.FilesConverterParameters; +import com.wudsn.ide.gfx.converter.FilesConverterParameters.SourceFile; +import com.wudsn.ide.gfx.gui.AspectField; +import com.wudsn.ide.gfx.gui.ConverterIdField; +import com.wudsn.ide.gfx.gui.SourceFileView; +import com.wudsn.ide.gfx.model.ConverterDirection; + +final class FilesConverterDataView { + + public final class Actions { + + /** + * Creation is private. + */ + private Actions() { + } + + public static final int FIND_DEFAULT_FILE_CONVERTER = 999; + public static final int CREATE_CONVERSION = 1000; + public static final int REFRESH = 1001; + public static final int SAVE_IMAGE = 1002; + public static final int CONVERTER_ID_CHANGED = 1003; + public static final int PARAMETER_CHANGED = 1100; + public static final int PALETTE_COLORS_CHANGED = 1101; + } + + private FilesConverterData filesConverterData; + private FilesConverterParameters filesConverterParameters; + + private Composite composite; + + private ConverterIdField converterIdField; + + private ToolItem findDefaultFileConverterButton; + private ToolItem createConversionButton; + private ToolItem refreshButton; + private ToolItem saveImageButton; + + private static final int SOURCE_FILES = 3; + private List sourceFileViews; + + private IntegerField columnsField; + private IntegerField rowsField; + + private Label spacingColorSelectorLabel; + private ColorSelector spacingColorSelector; + private IntegerField spacingWidthField; + + private FilePathField imageFilePathField; + private AspectField imageAspectField; + private IntegerField imageDataWidthField; + private IntegerField imageDataHeightField; + + public FilesConverterDataView(final GraphicsEditor editor, Composite parent, FilesConverterData filesConverterData) { + if (parent == null) { + throw new IllegalArgumentException("Parameter 'parent' must not be null."); + } + + if (filesConverterData == null) { + throw new IllegalArgumentException("Parameter 'filesConverterData' must not be null."); + } + this.filesConverterData = filesConverterData; + this.filesConverterParameters = this.filesConverterData.getParameters(); + + MessageManager messageManager = editor.getMessageManager(); + + GridData gd = new GridData(); + + composite = SWTFactory.createComposite(parent, 9, 1, SWT.HORIZONTAL); + + converterIdField = new ConverterIdField(composite, Texts.CONVERTER_PARAMETERS_CONVERTER_ID_LABEL, + ConverterDirection.FILES_TO_IMAGE); + converterIdField.addSelectionListener(new Action(Actions.CONVERTER_ID_CHANGED, editor)); + messageManager.registerField(converterIdField, ConverterCommonParameters.MessageIds.CONVERTER_ID); + + Composite toolBarcomposite = SWTFactory.createComposite(composite, 3, 7, GridData.FILL_HORIZONTAL); + ToolBar toolbar = new ToolBar(toolBarcomposite, SWT.HORIZONTAL); + + findDefaultFileConverterButton = new ToolItem(toolbar, SWT.PUSH); + findDefaultFileConverterButton.setImage(Icons.FIND_DEFAULT_CONVERTER); + findDefaultFileConverterButton.setToolTipText(Texts.FIND_DEFAULT_FILE_CONVERTER_BUTTON_TOOLTIP); + findDefaultFileConverterButton.addSelectionListener(new Action(Actions.FIND_DEFAULT_FILE_CONVERTER, editor)); + + createConversionButton = new ToolItem(toolbar, SWT.PUSH); + createConversionButton.setImage(Icons.CREATE_CONVERSION); + createConversionButton.setToolTipText(Texts.CREATE_CONVERSION_BUTTON_TOOLTIP); + createConversionButton.addSelectionListener(new Action(Actions.CREATE_CONVERSION, editor)); + + final Action refreshAction = new Action(Actions.REFRESH, editor); + refreshButton = new ToolItem(toolbar, SWT.PUSH); + refreshButton.setImage(Icons.REFRESH); + refreshButton.setToolTipText(Texts.REFRESH_BUTTON_TOOLTIP); + refreshButton.addSelectionListener(refreshAction); + + // Press + composite.addTraverseListener(new TraverseListener() { + + @Override + public void keyTraversed(TraverseEvent event) { + if (event.detail == SWT.TRAVERSE_RETURN) { + // The user pressed Enter + refreshAction.widgetDefaultSelected(null); + } + + } + }); + + saveImageButton = new ToolItem(toolbar, SWT.NONE); + saveImageButton.setImage(Icons.SAVE_IMAGE); + saveImageButton.setToolTipText(Texts.SAVE_IMAGE_BUTTON_TOOLTIP); + saveImageButton.addSelectionListener(new Action(Actions.SAVE_IMAGE, editor)); + + sourceFileViews = new ArrayList(SOURCE_FILES); + for (int i = 0; i < SOURCE_FILES; i++) { + SourceFileView sourceFileView; + + sourceFileView = new SourceFileView(composite, "", SWT.OPEN); + sourceFileView.addChangeListener(editor); + sourceFileView.getFileOffsetField().addSelectionAction(refreshAction); + messageManager.registerField(sourceFileView.getFilePathField(), + FilesConverterParameters.MessageIds.SOURCE_FILE_PATH + i); + messageManager.registerField(sourceFileView.getFileOffsetField(), + FilesConverterParameters.MessageIds.SOURCE_FILE_OFFSET + i); + sourceFileViews.add(sourceFileView); + SWTFactory.createLabels(composite, 1); + + } + + SWTFactory.createLabels(composite, 1); + + spacingColorSelectorLabel = new Label(composite, SWT.NONE); + spacingColorSelectorLabel.setText(Texts.CONVERTER_PARAMETERS_SPACING_COLOR_LABEL); + spacingColorSelector = new ColorSelector(composite); + Button spacingColorButton = spacingColorSelector.getButton(); + gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + spacingColorButton.setLayoutData(gd); + spacingColorButton.addSelectionListener(new Action(Actions.PARAMETER_CHANGED, editor)); + // messageManager.registerField(rowsField, + // FilesConverterParameters.MessageIds.SPACING_COLOR); + // TODO Requires a ColorSelectorField + + spacingWidthField = new IntegerField(composite, Texts.CONVERTER_PARAMETERS_SPACING_WIDTH_LABEL, new int[] { 0, + 1, 2, 4, 8 }, false, NumberUtility.AUTOMATIC_LENGTH, SWT.NONE); + spacingWidthField.addSelectionAction(new Action(Actions.PARAMETER_CHANGED, editor)); + messageManager.registerField(spacingWidthField, FilesConverterParameters.MessageIds.SPACING_WIDTH); + + columnsField = new IntegerField(composite, Texts.CONVERTER_PARAMETERS_COLUMNS_LABEL, new int[] { 1, 2, 3, 4, 8, + 16, 32, 40, 48, 64, 128, 256 }, false, NumberUtility.AUTOMATIC_LENGTH, SWT.NONE); + columnsField.addChangeListener(editor); + columnsField.addSelectionAction(new Action(Actions.PARAMETER_CHANGED, editor)); + messageManager.registerField(columnsField, FilesConverterParameters.MessageIds.COLUMNS); + + rowsField = new IntegerField(composite, Texts.CONVERTER_PARAMETERS_ROWS_LABEL, + new int[] { 1, 2, 3, 4, 24, 25 }, false, NumberUtility.AUTOMATIC_LENGTH, SWT.NONE); + rowsField.addChangeListener(editor); + rowsField.addSelectionAction(new Action(Actions.PARAMETER_CHANGED, editor)); + messageManager.registerField(rowsField, FilesConverterParameters.MessageIds.ROWS); + + imageFilePathField = new FilePathField(composite, Texts.CONVERTER_PARAMETERS_IMAGE_FILE_PATH_LABEL, SWT.SAVE); + imageFilePathField.addChangeListener(editor); + imageFilePathField.addChangeListener(editor); + messageManager.registerField(imageFilePathField, FilesConverterParameters.MessageIds.IMAGE_FILE_PATH); + + imageAspectField = new AspectField(composite, Texts.CONVERTER_PARAMETERS_IMAGE_ASPECT_LABEL); + imageAspectField.addSelectionAction(new Action(Actions.PARAMETER_CHANGED, editor)); + imageFilePathField.addChangeListener(editor); + messageManager.registerField(imageAspectField, ConverterCommonParameters.MessageIds.IMAGE_ASPECT); + + // Read only fields. + imageDataWidthField = new IntegerField(composite, Texts.CONVERTER_DATA_IMAGE_DATA_WIDTH_LABEL, null, false, + NumberUtility.AUTOMATIC_LENGTH, SWT.READ_ONLY); + imageDataHeightField = new IntegerField(composite, Texts.CONVERTER_DATA_IMAGE_DATA_HEIGHT_LABEL, null, false, + NumberUtility.AUTOMATIC_LENGTH, SWT.READ_ONLY); + } + + public Composite getComposite() { + return composite; + } + + public void dataFromUI() { + + // Copy the file paths and offsets before setting the new converter. + Converter converter = filesConverterData.getConverter(); + for (int i = 0; i < sourceFileViews.size(); i++) { + SourceFileView sourceFileView = sourceFileViews.get(i); + if (converter == null) { + + } else { + List sourceFileDefinitions = converter.getDefinition() + .getSourceFileDefinitions(); + if (i < sourceFileDefinitions.size()) { + SourceFile sourceFile = filesConverterParameters.getSourceFile(i); + sourceFile.setPath(sourceFileView.getFilePath()); + sourceFile.setOffset(sourceFileView.getFileOffset()); + } + } + } + + filesConverterParameters.setImageFilePath(imageFilePathField.getValue()); + + filesConverterParameters.setConverterId(converterIdField.getValue()); + + filesConverterParameters.setColumns(columnsField.getValue()); + filesConverterParameters.setRows(rowsField.getValue()); + + filesConverterParameters.setSpacingColor(spacingColorSelector.getColorValue()); + filesConverterParameters.setSpacingWidth(spacingWidthField.getValue()); + + filesConverterParameters.setImageAspect(imageAspectField.getValue()); + } + + public void dataToUI() { + + findDefaultFileConverterButton.setEnabled(filesConverterData.isValid()); + createConversionButton.setEnabled(filesConverterData.isCreateConversionEnabled()); + refreshButton.setEnabled(filesConverterData.isRefreshEnabled()); + saveImageButton.setEnabled(filesConverterData.isSaveImageEnabled()); + + converterIdField.setValue(filesConverterParameters.getConverterId()); + converterIdField.setEnabled(filesConverterData.isValid()); + + Converter converter = filesConverterData.getConverter(); + for (int i = 0; i < sourceFileViews.size(); i++) { + SourceFileView sourceFileView = sourceFileViews.get(i); + sourceFileView.setFilePathPrefix(filesConverterData.getFilePathPrefix()); + if (converter == null) { + sourceFileView.getFilePathField().setLabelText("Not used"); + sourceFileView.setFilePath(""); + sourceFileView.setFileBytes(null); + sourceFileView.setFileOffset(0); + sourceFileView.setVisible(true); + sourceFileView.setEnabled(false); + } else { + List sourceFileDefinitions = converter.getDefinition() + .getSourceFileDefinitions(); + if (i < sourceFileDefinitions.size()) { + sourceFileView.getFilePathField().setLabelText(sourceFileDefinitions.get(i).getLabel()); + SourceFile sourceFile = filesConverterParameters.getSourceFile(i); + sourceFileView.setFilePath(sourceFile.getPath()); + sourceFileView.setFileBytes(filesConverterData.getSourceFileBytes(sourceFile.getId())); + sourceFileView.setFileOffset(sourceFile.getOffset()); + sourceFileView.setVisible(true); + sourceFileView.setEnabled(true); + } else { + sourceFileView.getFilePathField().setLabelText("Not used"); + sourceFileView.setFilePath(""); + sourceFileView.setFileBytes(null); + sourceFileView.setFileOffset(0); + sourceFileView.setVisible(true); + sourceFileView.setEnabled(false); + } + } + + } + + imageFilePathField.setFilePathPrefix(filesConverterData.getFilePathPrefix()); + imageFilePathField.setValue(filesConverterParameters.getImageFilePath()); + imageFilePathField.setEnabled(filesConverterData.isValid()); + imageFilePathField.setEditable(true); + + columnsField.setValue(filesConverterParameters.getColumns()); + columnsField.setEnabled(filesConverterData.isValid()); + rowsField.setValue(filesConverterParameters.getRows()); + rowsField.setEnabled(filesConverterData.isValid()); + + spacingColorSelector.setColorValue(filesConverterParameters.getSpacingColor()); + spacingColorSelectorLabel.setEnabled(filesConverterData.isValid()); + spacingColorSelector.setEnabled(filesConverterData.isValid()); + spacingWidthField.setValue(filesConverterParameters.getSpacingWidth()); + spacingWidthField.setEnabled(filesConverterData.isValid()); + + imageAspectField.setValue(filesConverterParameters.getImageAspect()); + imageAspectField.setEnabled(filesConverterData.isValid()); + imageDataWidthField.setValue(filesConverterData.getImageDataWidth()); + imageDataWidthField.setEnabled(filesConverterData.isImageDataValid()); + imageDataHeightField.setValue(filesConverterData.getImageDataHeight()); + imageDataHeightField.setEnabled(filesConverterData.isImageDataValid()); + + composite.pack(); + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/GraphicsEditor.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/GraphicsEditor.java new file mode 100644 index 00000000..81243168 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/GraphicsEditor.java @@ -0,0 +1,729 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.editor; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.TabItem; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.dialogs.SaveAsDialog; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.part.EditorPart; + +import com.wudsn.ide.base.BasePlugin; +import com.wudsn.ide.base.common.NumberUtility; +import com.wudsn.ide.base.gui.Action; +import com.wudsn.ide.base.gui.Application; +import com.wudsn.ide.base.gui.MessageManager; +import com.wudsn.ide.gfx.GraphicsPlugin; +import com.wudsn.ide.gfx.Texts; +import com.wudsn.ide.gfx.converter.ConverterData; +import com.wudsn.ide.gfx.converter.ConverterDataLogic; +import com.wudsn.ide.gfx.converter.FilesConverterParameters; +import com.wudsn.ide.gfx.converter.ImageColorHistogram; +import com.wudsn.ide.gfx.converter.ImageConverterParameters; +import com.wudsn.ide.gfx.model.Aspect; +import com.wudsn.ide.gfx.model.ConverterDirection; +import com.wudsn.ide.gfx.model.ConverterMode; + + +public final class GraphicsEditor extends EditorPart implements Application, ISelectionProvider, ChangeListener { + + public final class Actions { + + /** + * Creation is private. + */ + private Actions() { + } + + public static final int TAB_CHANGED = 900; + } + + /** + * Encapsulation of the external image views. + */ + private final class MyImageProvider implements ImageProvider { + + private ImageData displayImageData; + private ImageColorHistogram displayImageColorHistogram; + + private ImageView imageView; + private ImagePaletteView imagePaletteView; + + MyImageProvider() { + + } + + @Override + public void setImageView(ImageView imageView) { + this.imageView = imageView; + } + + @Override + public void setImagePaletteView(ImagePaletteView imagePaletteView) { + this.imagePaletteView = imagePaletteView; + } + + @Override + public Aspect getAspect() { + return converterData.getParameters().getConverterCommonParameters().getDisplayAspect(); + } + + @Override + public void setAspect(Aspect value) { + dataFromUI(); + converterData.getParameters().getConverterCommonParameters().setDisplayAspect(value); + dataToUI(); + } + + @Override + public boolean isShrinkToFit() { + return converterData.getParameters().getConverterCommonParameters().isDisplayShrinkToFit(); + } + + @Override + public void setShrinkToFit(boolean value) { + dataFromUI(); + converterData.getParameters().getConverterCommonParameters().setDisplayShrinkToFit(value); + dataToUI(); + } + + @Override + public boolean isZoomToFit() { + return converterData.getParameters().getConverterCommonParameters().isDisplayZoomToFit(); + } + + @Override + public void setZoomToFit(boolean value) { + dataFromUI(); + converterData.getParameters().getConverterCommonParameters().setDisplayZoomToFit(value); + dataToUI(); + } + + @Override + public ImageData getImageData() { + return displayImageData; + } + + @Override + public ImageColorHistogram getImageColorHistogram() { + return displayImageColorHistogram; + } + + @Override + public boolean isPaletteChangeable() { + return converterData.getConverterDirection() == ConverterDirection.FILES_TO_IMAGE + && displayImageData != null && !displayImageData.palette.isDirect; + } + + @Override + public void setPaletteRGBs(RGB[] rgbs) { + if (rgbs == null) { + throw new IllegalArgumentException("Parameter 'rgbs' must not be null."); + } + dataFromUI(); + FilesConverterParameters parameters; + parameters = converterData.getParameters().getFilesConverterParameters(); + RGB[] currentRGBs = parameters.getPaletteRGBs(); + for (int i = 0; i < rgbs.length && i < currentRGBs.length; i++) { + currentRGBs[i] = rgbs[i]; + } + parameters.setPaletteManual(); + parameters.setPaletteRGBs(currentRGBs); + convert(); + dataToUi(); + } + + @Override + public void setPaletteRGB(int pixelColor, RGB rgb) { + if (rgb == null) { + throw new IllegalArgumentException("Parameter 'rgb' must not be null."); + } + dataFromUI(); + FilesConverterParameters parameters; + parameters = converterData.getParameters().getFilesConverterParameters(); + RGB[] rgbs = parameters.getPaletteRGBs(); + rgbs[pixelColor] = rgb; + parameters.setPaletteManual(); + parameters.setPaletteRGBs(rgbs); + convert(); + dataToUi(); + } + + final void dataToUi() { + IWorkbenchPage workbenchPage = getSite().getPage(); + + // If there is no perspective active yet, we are in the phase of + // starting while launching the IDE. + // In this situation, the additional views cannot be opened yet. + if (workbenchPage.getOpenPerspectives().length == 0) { + return; + } + + displayImageData = converterData.getConverterCommonData().getImageData(); + displayImageColorHistogram = converterData.getConverterCommonData().getImageColorHistogram(); + + // Ensure that there is an open image palette view. + if (imagePaletteView == null) { + try { + IViewPart viewPart = getSite().getPage().showView(ImagePaletteView.ID); + if (viewPart instanceof ImagePaletteView) { + ((ImagePaletteView) viewPart).setImageProvider(this); + } + } catch (PartInitException ex) { + imagePaletteView = null; + BasePlugin.getInstance().logError("Cannot open image palette view.", null, ex.getCause()); + } + } + if (imagePaletteView != null) { + imagePaletteView.dataToUI(); + } + + // Ensure that there is an open image view. + if (imageView == null) { + try { + IViewPart viewPart = getSite().getPage().showView(ImageView.ID); + if (viewPart instanceof ImageView) { + ((ImageView) viewPart).setImageProvider(this); + } + } catch (PartInitException ex) { + imageView = null; + BasePlugin.getInstance().logError("Cannot open image view.", null, ex); + } + } + if (imageView != null) { + imageView.dataToUI(); + } + } + + final void dispose() { + if (imageView != null) { + imageView.setImageProvider(null); + } + if (imagePaletteView != null) { + imagePaletteView.setImageProvider(null); + } + } + } + + private static final class MySaveAsDialog extends SaveAsDialog { + private String title; + private String message; + + public MySaveAsDialog(Shell parentShell, String title, String message) { + super(parentShell); + this.title = title; + this.message = message; + } + + @Override + protected Control createContents(Composite parent) { + if (parent == null) { + throw new IllegalArgumentException("Parameter 'parent' must not be null."); + } + Control result; + result = super.createContents(parent); + setTitle(title); + setMessage(message); + return result; + } + + } + + // ID of the editor in the plugin manifest. + public static final String ID = "com.wudsn.ide.gfx.editor.GraphicsEditor"; + + private MessageManager messageManager; + private boolean processing; + private boolean closeEditor; + + // All data and parameters. + private ConverterDataLogic converterDataLogic; + final ConverterData converterData; + + // UI state. + private boolean partControlCreated; + private TabFolder tabFolder; + private TabItem filesConverterDataViewTabItem; + private FilesConverterDataView filesConverterDataView; + private TabItem imageConverterDataViewTabItem; + private ImageConverterDataView imageConverterDataView; + + // UI state in external views. + private List selectionChangedListeners; + private MyImageProvider imageProvider; + + public GraphicsEditor() { + messageManager = new MessageManager(this); + + converterDataLogic = new ConverterDataLogic(messageManager); + converterData = converterDataLogic.createData(); + + selectionChangedListeners = new ArrayList(); + imageProvider = new MyImageProvider(); + } + + @Override + public MessageManager getMessageManager() { + return messageManager; + } + + @Override + public void dispose() { + imageProvider.dispose(); + messageManager.dispose(); + super.dispose(); + } + + @Override + public void doSave(IProgressMonitor monitor) { + dataFromUI(); + if (!converterData.isValid()) { + throw new IllegalStateException("Converter data is not valid."); + } + if (converterData.getConverterMode() != ConverterMode.CNV) { + throw new IllegalStateException("Converter data is not in mode CNV."); + } + messageManager.clearMessages(); + IFile saveFile = converterDataLogic.saveConversion(converterData, monitor); + if (saveFile != null) { + firePropertyChange(PROP_INPUT); + messageManager.sendMessage(0, IStatus.INFO, "Conversion {0} saved", saveFile.getFullPath().toString()); + } else if (monitor != null) { + monitor.setCanceled(true); + + } + dataToUI(); + } + + @Override + public void doSaveAs() { + dataFromUI(); + if (!converterData.isValid()) { + throw new IllegalStateException("Converter data is not valid."); + } + if (converterData.getConverterMode() != ConverterMode.CNV) { + throw new IllegalStateException("Converter data is not in mode CNV."); + } + IFile saveAsFile = saveConversionAs(converterData, Texts.SAVE_AS_DIALOG_TITLE, Texts.SAVE_AS_DIALOG_MESSAGE, + null); + if (saveAsFile != null) { + firePropertyChange(PROP_INPUT); + messageManager.sendMessage(0, IStatus.INFO, "Conversion {0} saved", saveAsFile.getFullPath().toString()); + } + dataToUI(); + } + + @Override + public void init(IEditorSite site, IEditorInput input) throws PartInitException { + if (site == null) { + throw new IllegalArgumentException("Parameter 'site' must not be null."); + } + setSite(site); + setInput(input); + + if (input != null) { + setPartName(input.getName()); + } else { + setPartName(""); + } + + messageManager.clearMessages(); + converterData.clear(); + try { + if (input instanceof IFileEditorInput) { + IFileEditorInput fileEditorInput = (IFileEditorInput) input; + IFile file = fileEditorInput.getFile(); + converterData.setFile(file); + converterDataLogic.load(converterData); + } + } catch (Exception ex) { + BasePlugin.getInstance().logError("Cannot open file.", null, ex); + } + convert(); + if (partControlCreated) { + dataToUI(); + } + + } + + /** + * Opens another file a new editor instance. + * + * @param file + * The file, not null. + * @return true if the editor was opened, false + * otherwise. + */ + private boolean openEditor(IFile file) { + if (file == null) { + throw new IllegalArgumentException("Parameter 'file' must not be null."); + } + + boolean result; + + result = false; + try { + + IDE.openEditor(getSite().getPage(), file, ID); + result = true; + + } catch (PartInitException ex) { + GraphicsPlugin.getInstance().logError("Cannot open default editor for {0}'.", new Object[] { file }, ex); + } + return result; + } + + /** + * Closes the current editor instance. + */ + private void closeEditor() { + getSite().getPage().closeEditor(this, false); + } + + @Override + public boolean isDirty() { + boolean result; + dataFromUI(); + result = converterData.isValidConversion() && converterData.isChanged(); + return result; + } + + @Override + public boolean isSaveAsAllowed() { + boolean result; + result = converterData.isValidConversion(); + return result; + } + + @Override + public void createPartControl(Composite parent) { + + getSite().setSelectionProvider(this); + + Composite composite = parent; + composite.setLayout(new FillLayout(SWT.VERTICAL)); + tabFolder = new TabFolder(composite, SWT.TOP); + + filesConverterDataViewTabItem = new TabItem(tabFolder, SWT.NONE); + filesConverterDataViewTabItem.setText(Texts.FILES_CONVERTER_DATA_VIEW_TAB); + filesConverterDataView = new FilesConverterDataView(this, tabFolder, converterData.getFilesConverterData()); + filesConverterDataViewTabItem.setControl(filesConverterDataView.getComposite()); + + imageConverterDataViewTabItem = new TabItem(tabFolder, SWT.NONE); + imageConverterDataViewTabItem.setText(Texts.IMAGE_CONVERTER_DATA_VIEW_TAB); + imageConverterDataView = new ImageConverterDataView(this, tabFolder, converterData.getImageConverterData()); + imageConverterDataViewTabItem.setControl(imageConverterDataView.getComposite()); + + // Add selection listener only after all tabs have been added. + tabFolder.addSelectionListener(new Action(Actions.TAB_CHANGED, this)); + + partControlCreated = true; + + dataToUI(); + + } + + @Override + public void performAction(Action action) { + if (action == null) { + throw new IllegalArgumentException("Parameter 'action' must not be null."); + } + if (!processing) { + processing = true; + + try { + + messageManager.clearMessages(); + dataFromUI(); + + switch (action.getId()) { + case Actions.TAB_CHANGED: + loadSources(false, true); + break; + + case FilesConverterDataView.Actions.FIND_DEFAULT_FILE_CONVERTER: + converterDataLogic.findDefaultFileConverter(converterData); + convert(); + break; + + case FilesConverterDataView.Actions.CREATE_CONVERSION: + createConversion(); + break; + + case FilesConverterDataView.Actions.REFRESH: + loadSources(false, true); + break; + + case FilesConverterDataView.Actions.SAVE_IMAGE: + saveTargets(); + break; + + case FilesConverterDataView.Actions.CONVERTER_ID_CHANGED: + loadSources(true, true); + break; + + case FilesConverterDataView.Actions.PARAMETER_CHANGED: + convert(); + break; + + case FilesConverterDataView.Actions.PALETTE_COLORS_CHANGED: + converterData.getFilesConverterData().getParameters().setPaletteManual(); + convert(); + break; + + case ImageConverterDataView.Actions.CREATE_CONVERSION: + createConversion(); + break; + + case ImageConverterDataView.Actions.REFRESH: + loadSources(false, true); + break; + + case ImageConverterDataView.Actions.SAVE_FILES: + saveTargets(); + break; + + case ImageConverterDataView.Actions.CONVERTER_ID_CHANGED: + loadSources(true, true); + break; + + case ImageConverterDataView.Actions.PARAMETER_CHANGED: + convert(); + } + + dataToUI(); + } catch (Exception ex) { + GraphicsPlugin.getInstance().showError(getSite().getShell(), "Error in update()", ex); + } + + processing = false; + if (closeEditor) { + closeEditor(); + } + } + + } + + private void loadSources(boolean applyDefaults, boolean convert) { + if (applyDefaults) { + converterDataLogic.applyDefaults(converterData); + } + long startTimeMillis = System.currentTimeMillis(); + if (converterDataLogic.loadSources(converterData, false)) { + if (convert) { + converterDataLogic.convert(converterData); + long duration = System.currentTimeMillis() - startTimeMillis; + String durationString = NumberUtility.getLongValueDecimalString(duration); + switch (converterData.getConverterDirection()) { + case FILES_TO_IMAGE: + messageManager.sendMessage(ImageConverterParameters.MessageIds.IMAGE_FILE_PATH, IStatus.OK, + Texts.MESSAGE_S100, durationString); + break; + case IMAGE_TO_FILES: + messageManager.sendMessage(ImageConverterParameters.MessageIds.IMAGE_FILE_PATH, IStatus.OK, + "Image file loaded and converted in {0} ms", durationString); + break; + } + } else { + switch (converterData.getConverterDirection()) { + case FILES_TO_IMAGE: + messageManager.sendMessage(ImageConverterParameters.MessageIds.IMAGE_FILE_PATH, IStatus.OK, + "Source files loaded"); + break; + case IMAGE_TO_FILES: + messageManager.sendMessage(ImageConverterParameters.MessageIds.IMAGE_FILE_PATH, IStatus.OK, + "Image file loaded"); + break; + } + } + } + } + + final void convert() { + converterDataLogic.convert(converterData); + } + + private void saveTargets() { + converterDataLogic.saveTargets(converterData); + + } + + private void createConversion() { + + ConverterData newConverterData; + IFile saveAsFile; + + newConverterData = converterDataLogic.createConversion(converterData); + + saveAsFile = saveConversionAs(newConverterData, Texts.CREATE_CONVERSION_DIALOG_TITLE, + Texts.CREATE_CONVERSION_DIALOG_MESSAGE, null); + if (saveAsFile != null) { + messageManager.sendMessage(0, IStatus.INFO, "Conversion {0} saved", saveAsFile.getFullPath().toString()); + closeEditor = openEditor(saveAsFile); + + } + } + + private IFile saveConversionAs(ConverterData data, String title, String message, IProgressMonitor monitor) { + if (data == null) { + throw new IllegalArgumentException("Parameter 'data' must not be null."); + } + + if (title == null) { + throw new IllegalArgumentException("Parameter 'title' must not be null."); + } + if (message == null) { + throw new IllegalArgumentException("Parameter 'message' must not be null."); + } + IFile saveAsFile; + IPath saveAsPath; + SaveAsDialog saveAsDialog = new MySaveAsDialog(getSite().getShell(), title, message); + saveAsDialog.setBlockOnOpen(true); + saveAsDialog.setOriginalFile(data.getFile()); + saveAsDialog.open(); + saveAsPath = saveAsDialog.getResult(); + if (saveAsPath != null) { + + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + saveAsFile = workspaceRoot.getFile(saveAsPath); + converterData.setFile(saveAsFile); + converterDataLogic.saveConversion(data, monitor); + + } else { + saveAsFile = null; + } + return saveAsFile; + } + + final void dataFromUI() { + + TabItem[] tabItems = tabFolder.getSelection(); + if (tabItems == null || tabItems.length == 0 || tabItems[0] == filesConverterDataViewTabItem) { + converterData.getParameters().setConverterDirection(ConverterDirection.FILES_TO_IMAGE); + } else { + converterData.getParameters().setConverterDirection(ConverterDirection.IMAGE_TO_FILES); + } + + filesConverterDataView.dataFromUI(); + imageConverterDataView.dataFromUI(); + + } + + final void dataToUI() { + + firePropertyChange(PROP_DIRTY); + + switch (converterData.getConverterDirection()) { + case FILES_TO_IMAGE: + tabFolder.setSelection(filesConverterDataViewTabItem); + break; + case IMAGE_TO_FILES: + tabFolder.setSelection(imageConverterDataViewTabItem); + break; + default: + throw new IllegalStateException("Unknown converter direction '" + converterData.getConverterDirection() + + "'."); + } + + filesConverterDataView.dataToUI(); + imageConverterDataView.dataToUI(); + + if (partControlCreated) { + imageProvider.dataToUi(); + } + + messageManager.displayMessages(); + + } + + @Override + public void setFocus() { + tabFolder.setFocus(); + // dataToUI(); Do not use here. Causes a recursion due to the image view + // trying to come to front. + } + + @Override + public void addSelectionChangedListener(ISelectionChangedListener listener) { + selectionChangedListeners.add(listener); + } + + @Override + public void removeSelectionChangedListener(ISelectionChangedListener listener) { + selectionChangedListeners.remove(listener); + } + + @Override + public ISelection getSelection() { + return new StructuredSelection(); + } + + @Override + public void setSelection(ISelection selection) { + for (ISelectionChangedListener listener : selectionChangedListeners) { + listener.selectionChanged(new SelectionChangedEvent(this, selection)); + } + } + + @Override + public void stateChanged(ChangeEvent event) { + firePropertyChange(PROP_DIRTY); + } + + /** + * Gets the image provider for this editor. + * + * @return The image provider, not null. + */ + public ImageProvider getImageProvider() { + return imageProvider; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/GraphicsEditorOpenCommandHandler.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/GraphicsEditorOpenCommandHandler.java new file mode 100644 index 00000000..b3115a86 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/GraphicsEditorOpenCommandHandler.java @@ -0,0 +1,39 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.editor; + +import com.wudsn.ide.base.editor.CommonOpenEditorCommandHandler; + +/** + * The action to open the graphics editor from the context menu. + * + * @author Peter Dell + */ +public final class GraphicsEditorOpenCommandHandler extends CommonOpenEditorCommandHandler { + + /** + * Creation is public. Called by extension "org.eclipse.ui.popupMenus". + */ + public GraphicsEditorOpenCommandHandler() { + super(GraphicsEditor.ID); + } + + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/Icons.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/Icons.java new file mode 100644 index 00000000..d209856d --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/Icons.java @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.editor; + +import org.eclipse.swt.graphics.Image; + +import com.wudsn.ide.base.common.AbstractIDEPlugin; +import com.wudsn.ide.gfx.GraphicsPlugin; + +final class Icons { + + public static final Image FIND_DEFAULT_CONVERTER; + public static final Image CREATE_CONVERSION; + public static final Image REFRESH; + public static final Image SAVE_IMAGE; + public static final Image SAVE_FILES; + + static { + AbstractIDEPlugin plugin = GraphicsPlugin.getInstance(); + FIND_DEFAULT_CONVERTER = plugin.getImage("searchm_obj.gif"); + CREATE_CONVERSION = plugin.getImage("graphics-editor-16x16.gif"); + REFRESH = plugin.getImage("refresh.gif"); + SAVE_IMAGE = plugin.getImage("save_edit.gif"); + SAVE_FILES = plugin.getImage("save_edit.gif"); + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImageConverterDataView.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImageConverterDataView.java new file mode 100644 index 00000000..7233c590 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImageConverterDataView.java @@ -0,0 +1,297 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ +package com.wudsn.ide.gfx.editor; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +import com.wudsn.ide.base.common.NumberUtility; +import com.wudsn.ide.base.gui.Action; +import com.wudsn.ide.base.gui.CheckBoxField; +import com.wudsn.ide.base.gui.FilePathField; +import com.wudsn.ide.base.gui.IntegerField; +import com.wudsn.ide.base.gui.MessageManager; +import com.wudsn.ide.base.gui.MultiLineTextField; +import com.wudsn.ide.base.gui.SWTFactory; +import com.wudsn.ide.gfx.Texts; +import com.wudsn.ide.gfx.converter.Converter; +import com.wudsn.ide.gfx.converter.ConverterCommonParameters; +import com.wudsn.ide.gfx.converter.ConverterTargetFileDefinition; +import com.wudsn.ide.gfx.converter.ImageConverterData; +import com.wudsn.ide.gfx.converter.ImageConverterParameters; +import com.wudsn.ide.gfx.converter.ImageConverterParameters.TargetFile; +import com.wudsn.ide.gfx.gui.AspectField; +import com.wudsn.ide.gfx.gui.ConverterIdField; +import com.wudsn.ide.gfx.gui.TargetFileView; +import com.wudsn.ide.gfx.model.ConverterDirection; + +final class ImageConverterDataView { + + public final class Actions { + + /** + * Creation is private. + */ + private Actions() { + } + + public static final int CREATE_CONVERSION = 2000; + public static final int REFRESH = 2001; + public static final int SAVE_FILES = 2002; + public static final int CONVERTER_ID_CHANGED = 2003; + + public static final int PARAMETER_CHANGED = 2100; + public static final int PALETTE_COLORS_CHANGED = 2101; + } + + private ImageConverterData imageConverterData; + private ImageConverterParameters imageConverterParameters; + + private Composite composite; + + private ConverterIdField converterIdField; + + private ToolItem createConversionButton; + private ToolItem refreshButton; + private ToolItem saveFilesButton; + + private FilePathField imageFilePathField; + private AspectField imageAspectField; + private IntegerField imageDataWidthField; + private IntegerField imageDataHeightField; + + private static final int TARGET_FILES = 3; + private List targetFileViews; + + private CheckBoxField useDefaultScriptField; + private MultiLineTextField scriptField; + + public ImageConverterDataView(GraphicsEditor editor, Composite parent, ImageConverterData imageConverterData) { + if (editor == null) { + throw new IllegalArgumentException("Parameter 'editor' must not be null."); + } + if (parent == null) { + throw new IllegalArgumentException("Parameter 'parent' must not be null."); + } + if (imageConverterData == null) { + throw new IllegalArgumentException("Parameter 'imageConverterData' must not be null."); + } + this.imageConverterData = imageConverterData; + this.imageConverterParameters = this.imageConverterData.getParameters(); + + MessageManager messageManager = editor.getMessageManager(); + + // Create visual elements. + composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout(1, false)); + GridData gd = new GridData(); + gd.grabExcessHorizontalSpace = false; + gd.grabExcessVerticalSpace = false; + composite.setLayoutData(gd); + + Composite topComposite = SWTFactory.createComposite(composite, 9, 1, SWT.HORIZONTAL); + + converterIdField = new ConverterIdField(topComposite, Texts.CONVERTER_PARAMETERS_CONVERTER_ID_LABEL, + ConverterDirection.IMAGE_TO_FILES); + converterIdField.addSelectionListener(new Action(Actions.CONVERTER_ID_CHANGED, editor)); + messageManager.registerField(converterIdField, ConverterCommonParameters.MessageIds.CONVERTER_ID); + + Composite toolBarcomposite = SWTFactory.createComposite(topComposite, 3, 7, GridData.FILL_HORIZONTAL); + ToolBar toolbar = new ToolBar(toolBarcomposite, SWT.HORIZONTAL); + + createConversionButton = new ToolItem(toolbar, SWT.PUSH); + createConversionButton.setImage(Icons.CREATE_CONVERSION); + createConversionButton.setToolTipText(Texts.CREATE_CONVERSION_BUTTON_TOOLTIP); + createConversionButton.addSelectionListener(new Action(Actions.CREATE_CONVERSION, editor)); + + refreshButton = new ToolItem(toolbar, SWT.PUSH); + refreshButton.setImage(Icons.REFRESH); + refreshButton.setToolTipText(Texts.REFRESH_BUTTON_TOOLTIP); + refreshButton.addSelectionListener(new Action(Actions.REFRESH, editor)); + + saveFilesButton = new ToolItem(toolbar, SWT.NONE); + saveFilesButton.setImage(Icons.SAVE_FILES); + saveFilesButton.setToolTipText(Texts.SAVE_FILES_BUTTON_TOOLTIP); + saveFilesButton.addSelectionListener(new Action(Actions.SAVE_FILES, editor)); + + imageFilePathField = new FilePathField(topComposite, Texts.CONVERTER_PARAMETERS_IMAGE_FILE_PATH_LABEL, SWT.OPEN); + imageFilePathField.addChangeListener(editor); + messageManager.registerField(imageFilePathField, ImageConverterParameters.MessageIds.IMAGE_FILE_PATH); + + // + imageAspectField = new AspectField(topComposite, Texts.CONVERTER_PARAMETERS_IMAGE_ASPECT_LABEL); + imageAspectField.addSelectionAction(new Action(Actions.PARAMETER_CHANGED, editor)); + messageManager.registerField(imageAspectField, ConverterCommonParameters.MessageIds.IMAGE_ASPECT); + + imageDataWidthField = new IntegerField(topComposite, Texts.CONVERTER_DATA_IMAGE_DATA_WIDTH_LABEL, null, false, + NumberUtility.AUTOMATIC_LENGTH, SWT.READ_ONLY); + imageDataHeightField = new IntegerField(topComposite, Texts.CONVERTER_DATA_IMAGE_DATA_HEIGHT_LABEL, null, + false, NumberUtility.AUTOMATIC_LENGTH, SWT.READ_ONLY); + + targetFileViews = new ArrayList(TARGET_FILES); + for (int i = 0; i < TARGET_FILES; i++) { + TargetFileView targetFileView; + + targetFileView = new TargetFileView(topComposite, "", SWT.SAVE); + targetFileView.addChangeListener(editor); + messageManager.registerField(targetFileView.getFilePathField(), + ImageConverterParameters.MessageIds.TARGET_FILE_PATH + i); + targetFileViews.add(targetFileView); + SWTFactory.createLabels(topComposite, 4); + + } + + useDefaultScriptField = new CheckBoxField(topComposite, Texts.CONVERTER_PARAMETERS_USE_DEFAULT_SCRIPT_LABEL, + SWT.NONE); + useDefaultScriptField.addSelectionAction(new Action(Actions.PARAMETER_CHANGED, editor)); + messageManager.registerField(useDefaultScriptField, ImageConverterParameters.MessageIds.USE_DEFAULT_SCRIPT); + SWTFactory.createLabels(topComposite, 6); + + scriptField = new MultiLineTextField(composite, SWT.H_SCROLL | SWT.V_SCROLL); + scriptField.addChangeListener(editor); + messageManager.registerField(scriptField, ImageConverterParameters.MessageIds.SCRIPT); + gd = new GridData(); + gd.horizontalSpan = 1; + gd.verticalSpan = 1; + gd.grabExcessHorizontalSpace = true; + gd.grabExcessVerticalSpace = true; + Rectangle clientArea = Display.getCurrent().getClientArea(); + gd.heightHint = clientArea.width; + gd.widthHint = clientArea.height; + StyledText styledText = scriptField.getText(); + styledText.setLayoutData(gd); + styledText.setFont(JFaceResources.getTextFont()); + styledText.setTabs(4); + + } + + public Composite getComposite() { + return composite; + } + + public void dataFromUI() { + + imageConverterParameters.setImageFilePath(imageFilePathField.getValue()); + imageConverterParameters.setImageAspect(imageAspectField.getValue()); + + // Copy the file paths before setting the new converter. + Converter converter = imageConverterData.getConverter(); + for (int i = 0; i < targetFileViews.size(); i++) { + TargetFileView targetFileView = targetFileViews.get(i); + if (converter == null) { + + } else { + List targetFileDefinitions = converter.getDefinition() + .getTargetFileDefinitions(); + if (i < targetFileDefinitions.size()) { + TargetFile targetFile = imageConverterParameters.getTargetFile(i); + targetFile.setPath(targetFileView.getFilePath()); + } + } + } + + imageConverterParameters.setConverterId(converterIdField.getValue()); + + imageConverterParameters.setUseDefaultScript(useDefaultScriptField.getValue()); + if (!imageConverterParameters.isUseDefaultScript()) { + imageConverterParameters.setScript(scriptField.getValue()); + } + } + + public void dataToUI() { + + createConversionButton.setEnabled(imageConverterData.isCreateConversionEnabled()); + refreshButton.setEnabled(imageConverterData.isRefreshEnabled()); + saveFilesButton.setEnabled(imageConverterData.isSaveFilesEnabled()); + + converterIdField.setValue(imageConverterParameters.getConverterId()); + converterIdField.setEnabled(imageConverterData.isValid()); + + imageFilePathField.setFilePathPrefix(imageConverterData.getFilePathPrefix()); + imageFilePathField.setValue(imageConverterParameters.getImageFilePath()); + imageFilePathField.setEnabled(imageConverterData.isValid()); + imageFilePathField.setEditable(true); + + imageAspectField.setValue(imageConverterParameters.getImageAspect()); + imageAspectField.setEnabled(imageConverterData.isValid()); + imageDataWidthField.setValue(imageConverterData.getImageDataWidth()); + imageDataWidthField.setEnabled(imageConverterData.isValid()); + imageDataHeightField.setValue(imageConverterData.getImageDataHeight()); + imageDataHeightField.setEnabled(imageConverterData.isValid()); + + Converter converter = imageConverterData.getConverter(); + for (int i = 0; i < targetFileViews.size(); i++) { + TargetFileView targetFileView = targetFileViews.get(i); + targetFileView.setFilePathPrefix(imageConverterData.getFilePathPrefix()); + if (converter == null) { + targetFileView.getFilePathField().setLabelText("Not used"); + targetFileView.setFilePath(""); + targetFileView.setFileBytes(null); + targetFileView.setVisible(true); + targetFileView.setEnabled(false); + } else { + List targetFileDefinitions = converter.getDefinition() + .getTargetFileDefinitions(); + if (i < targetFileDefinitions.size()) { + targetFileView.getFilePathField().setLabelText(targetFileDefinitions.get(i).getLabel()); + TargetFile targetFile = imageConverterParameters.getTargetFile(i); + targetFileView.setFilePath(targetFile.getPath()); + targetFileView.setFileBytes(imageConverterData.getTargetFileBytes(targetFile.getId())); + targetFileView.setVisible(true); + targetFileView.setEnabled(imageConverterData.isValidConversion()); + } else { + targetFileView.getFilePathField().setLabelText("Not used"); + targetFileView.setFilePath(""); + targetFileView.setFileBytes(null); + targetFileView.setVisible(true); + targetFileView.setEnabled(false); + } + } + + } + + useDefaultScriptField.setValue(imageConverterParameters.isUseDefaultScript()); + useDefaultScriptField.setEnabled(imageConverterData.isValid()); + useDefaultScriptField.setEditable(imageConverterData.isValidConversion()); + + String script = imageConverterParameters.getScript(); + scriptField.setValue(script); + scriptField.setEnabled(imageConverterData.isValid()); + scriptField.setEditable(!imageConverterParameters.isUseDefaultScript()); + + int lineNumber = imageConverterData.getConverterScriptData().geErrorLineNumber(); + if (lineNumber > 0) { + int offset = scriptField.getText().getOffsetAtLine(lineNumber - 1); + scriptField.setSelection(offset); + } + imageConverterData.getConverterScriptData().setErrorLineNumber(-1); + + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImagePaletteView.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImagePaletteView.java new file mode 100644 index 00000000..3948bf32 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImagePaletteView.java @@ -0,0 +1,829 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.editor; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuCreator; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.graphics.Region; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.ColorDialog; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.part.ViewPart; + +import com.wudsn.ide.base.common.HexUtility; +import com.wudsn.ide.base.common.NumberUtility; +import com.wudsn.ide.base.common.TextUtility; +import com.wudsn.ide.gfx.Texts; +import com.wudsn.ide.gfx.converter.ImageColorHistogram; +import com.wudsn.ide.gfx.gui.ImageCanvas; +import com.wudsn.ide.gfx.model.Palette; +import com.wudsn.ide.gfx.model.PaletteType; +import com.wudsn.ide.gfx.model.PaletteUtility; + +/** + * This class displays the palette of the image from a {@link ImageProvider}. + * + * @author Peter Dell + * @see ImageCanvas + */ + +public final class ImagePaletteView extends ViewPart implements + ISelectionListener { + + private final class PaletteMenuCreator implements IMenuCreator, + SelectionListener { + private Menu menu; + private Map images; + + public PaletteMenuCreator() { + images = new HashMap(10); + } + + @Override + public Menu getMenu(Menu parent) { + return null; + } + + @Override + public Menu getMenu(Control parent) { + if (menu != null) { + menu.dispose(); + menu = null; + } + menu = new Menu(parent); + createMenuItem("Hires-1", PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.HIRES_1, null)); + createMenuItem("Hires-2", PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.HIRES_2, null)); + + createMenuItem("Multi-1", PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.MULTI_1, null)); + createMenuItem("Multi-2", PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.MULTI_2, null)); + createMenuItem("Multi-3", PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.MULTI_3, null)); + createMenuItem("Multi-4", PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.MULTI_4, null)); + createMenuItem("Multi-5", PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.MULTI_5, null)); + createMenuItem("Multi-6", PaletteUtility.getPaletteColors( + PaletteType.ATARI_DEFAULT, Palette.MULTI_6, null)); + return menu; + } + + private void createMenuItem(String text, RGB[] rgbs) { + MenuItem item = new MenuItem(menu, SWT.NONE); + Image image = images.get(text); + if (image == null) { + int size = 16; + int width = rgbs.length * size; + int height = size; + PaletteData paletteData = new PaletteData(rgbs); + ImageData imageData = new ImageData(width, height, 8, + paletteData); + for (int i = 0; i < rgbs.length; i++) { + for (int y = 0; y < size; y++) { + for (int x = 0; x < size; x++) { + imageData.setPixel(i * size + x, y, i); + } + } + } + image = new Image(Display.getCurrent(), imageData); + images.put(text, image); + } + item.setImage(image); + item.setData(rgbs); + item.addSelectionListener(this); + } + + @Override + public void dispose() { + if (menu != null) { + menu.dispose(); + } + menu = null; + if (images != null) { + for (Image image : images.values()) { + image.dispose(); + } + images = null; + } + } + + @Override + public void widgetSelected(SelectionEvent e) { + MenuItem item = (MenuItem) e.widget; + imageProvider.setPaletteRGBs((RGB[]) item.getData()); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + + } + } + + /** + * + * @author Peter Dell + * + */ + private static final class TableView { + + /** + * Data container for a row in the table view. + * + * @author Peter Dell + * + */ + private static final class Data { + private int index; + private int pixelColor; + private RGB rgb; + private int pixelColorCount; + private int pixelColorCountPercent; + + public Data(int index, Integer pixelColor, RGB rgb, + int pixelColorCount, int pixelColorCountPercent) { + if (pixelColor == null) { + throw new IllegalArgumentException( + "Parameter 'pixelColor' must not be null."); + } + if (rgb == null) { + throw new IllegalArgumentException( + "Parameter 'rgb' must not be null."); + } + this.index = index; + this.pixelColor = pixelColor.intValue(); + this.rgb = rgb; + this.pixelColorCount = pixelColorCount; + this.pixelColorCountPercent = pixelColorCountPercent; + } + + public int getIndex() { + return index; + } + + public int getPixelColor() { + return pixelColor; + } + + public RGB getRGB() { + return rgb; + } + + public int getPixelColorCount() { + return pixelColorCount; + } + + public int getPixelColorCountPercent() { + return pixelColorCountPercent; + } + } + + /** + * Comparator to sort lists of {@link Data}. + * + * @author Peter Dell + * + */ + private class DataComparator implements Comparator { + + private TableColumn sortColumn; + private int sortDirection; + + /** + * Creates a new comparator. + * + * @param sortColumn + * The column to sort by, not null. + * @param direction + * The direction to sort by, see {@link SWT#UP} or + * {@link SWT#DOWN}. + */ + public DataComparator(TableColumn sortColumn, int direction) { + if (sortColumn == null) { + throw new IllegalArgumentException( + "Parameter 'sortColumn' must not be null."); + } + this.sortColumn = sortColumn; + this.sortDirection = direction == SWT.UP ? 1 : -1; + } + + @Override + public int compare(Data o1, Data o2) { + if (sortColumn == indexColumn) { + return (o1.getIndex() - o2.getIndex()) * sortDirection; + } else if (sortColumn == pixelColorHexColumn + || sortColumn == pixelColorBinaryColumn) { + return (o1.getPixelColor() - o2.getPixelColor()) + * sortDirection; + } else if (sortColumn == rgbColorColumn) { + // Sort by brightness + float b1 = o1.getRGB().getHSB()[2]; + float b2 = o2.getRGB().getHSB()[2]; + if (b1 > b2) { + return sortDirection; + } else if (b1 < b2) { + return -sortDirection; + } + return 0; + } else if (sortColumn == pixelColorCountColumn + || sortColumn == pixelColorCountPercentColumn) { + return (o1.getPixelColorCount() - o2.getPixelColorCount()) + * sortDirection; + } + return 0; + } + + } + + // Standard width of a column. + private static final int WIDTH = 47; + + // Objects created in the constructor. + private final ImagePaletteView owner; + private final Table table; + private final Listener defaultSelectionListener; + final TableColumn indexColumn; + final TableColumn pixelColorHexColumn; + final TableColumn pixelColorBinaryColumn; + final TableColumn rgbColorColumn; + final TableColumn pixelColorCountColumn; + final TableColumn pixelColorCountPercentColumn; + + // The image cache map. + private Map images; + + // The image color histogram containing the original data. + private ImageColorHistogram imageColorHistogram; + + // The data list containing the converted image color histogram data. + private List dataList; + + public TableView(Composite parent, final ImagePaletteView owner) { + if (parent == null) { + throw new IllegalArgumentException( + "Parameter 'parent' must not be null."); + } + if (owner == null) { + throw new IllegalArgumentException( + "Parameter 'owner' must not be null."); + } + this.owner = owner; + + table = new Table(parent, SWT.VIRTUAL | SWT.BORDER | SWT.SINGLE + | SWT.FULL_SELECTION); + table.setLayoutData(new GridData(GridData.FILL_BOTH)); + + table.setHeaderVisible(true); + + /* + * NOTE: MeasureItem, PaintItem and EraseItem are called repeatedly. + * Therefore, it is critical for performance that these methods be + * as efficient as possible. + */ + table.addListener(SWT.EraseItem, new Listener() { + @Override + public void handleEvent(Event event) { + eraseItem(event); + } + }); + + defaultSelectionListener = new Listener() { + @Override + public void handleEvent(Event e) { + editColor(); + } + }; + + // The first column is always left aligned in SWT due to a + // restriction in windows. + // This is a trick to come round this restriction. + TableColumn dummyColumn; + dummyColumn = new TableColumn(table, SWT.LEFT); + dummyColumn.setWidth(0); + + indexColumn = new TableColumn(table, SWT.RIGHT); + indexColumn.setText("Index"); + indexColumn.setText(Texts.IMAGE_PALETTE_VIEW_COLUMN_INDEX_TEXT); + pixelColorHexColumn = new TableColumn(table, SWT.RIGHT); + pixelColorHexColumn.setText("Hex"); + pixelColorHexColumn + .setText(Texts.IMAGE_PALETTE_VIEW_COLUMN_COLOR_HEX_TEXT); + pixelColorBinaryColumn = new TableColumn(table, SWT.RIGHT); + pixelColorBinaryColumn + .setText(Texts.IMAGE_PALETTE_VIEW_COLUMN_COLOR_BINARY_TEXT); + rgbColorColumn = new TableColumn(table, SWT.RIGHT); + rgbColorColumn + .setText(Texts.IMAGE_PALETTE_VIEW_COLUMN_RGB_COLOR_TEXT); + pixelColorCountColumn = new TableColumn(table, SWT.RIGHT); + pixelColorCountColumn + .setText(Texts.IMAGE_PALETTE_VIEW_COLUMN_COLOR_COUNT_TEXT); + pixelColorCountPercentColumn = new TableColumn(table, SWT.RIGHT); + pixelColorCountPercentColumn + .setText(Texts.IMAGE_PALETTE_VIEW_COLUMN_COLOR_COUNT_PERCENT_TEXT); + + indexColumn.setWidth(WIDTH); + pixelColorHexColumn.setWidth(WIDTH); + pixelColorBinaryColumn.setWidth(WIDTH); + rgbColorColumn.setWidth(90); + pixelColorCountColumn.setWidth(WIDTH); + pixelColorCountPercentColumn.setWidth(WIDTH); + + table.addListener(SWT.SetData, new Listener() { + @Override + public void handleEvent(Event event) { + + updateTableItem(event); + } + }); + + // Add sort indicator and sort data when column selected + Listener sortListener = new Listener() { + @Override + public void handleEvent(Event event) { + sortTableColumn(event); + } + }; + indexColumn.addListener(SWT.Selection, sortListener); + pixelColorHexColumn.addListener(SWT.Selection, sortListener); + pixelColorBinaryColumn.addListener(SWT.Selection, sortListener); + rgbColorColumn.addListener(SWT.Selection, sortListener); + pixelColorCountColumn.addListener(SWT.Selection, sortListener); + pixelColorCountPercentColumn.addListener(SWT.Selection, + sortListener); + + table.setSortColumn(indexColumn); + table.setSortDirection(SWT.UP); + + images = new HashMap(); + imageColorHistogram = null; + dataList = new ArrayList(); + } + + public void clear() { + if (!table.isDisposed()) { + table.setItemCount(0); + table.clearAll(); + } + + for (Image image : images.values()) { + image.dispose(); + } + images.clear(); + + imageColorHistogram = null; + dataList.clear(); + } + + public void setFocus() { + table.setFocus(); + } + + void updateTableItem(Event event) { + if (event == null) { + throw new IllegalArgumentException( + "Parameter 'event' must not be null."); + } + TableItem item = (TableItem) event.item; + Font font = JFaceResources.getTextFont(); + int i = table.indexOf(item); + Data data = dataList.get(i); + item.setData(data); + item.setText(1, + NumberUtility.getLongValueDecimalString(data.getIndex())); + + // Pixel color values are uninteresting for direct palettes. + if (!imageColorHistogram.isDirectPalette()) { + item.setText(2, + HexUtility.getLongValueHexString(data.getPixelColor())); + item.setFont(2, font); + item.setText(3, Integer.toBinaryString(data.getPixelColor())); + item.setFont(3, font); + } + RGB rgb = data.getRGB(); + + // Images are resources which have to be disposed, so handle + Image image = images.get(rgb); + if (image == null) { + PaletteData paletteData = new PaletteData(new RGB[] { rgb }); + ImageData imageData = new ImageData(32, 16, 1, paletteData); + image = new Image(table.getDisplay(), imageData); + images.put(rgb, image); + } + item.setImage(4, image); + item.setText(4, PaletteUtility.getPaletteColorText(rgb)); + item.setFont(4, font); + item.setText(5, NumberUtility.getLongValueDecimalString(data + .getPixelColorCount())); + item.setText(6, NumberUtility.getLongValueDecimalString(data + .getPixelColorCountPercent())); + + } + + void eraseItem(Event event) { + if (event == null) { + throw new IllegalArgumentException( + "Parameter 'event' must not be null."); + } + event.detail &= ~SWT.HOT; + if ((event.detail & SWT.SELECTED) != 0) { + GC gc = event.gc; + Rectangle area = table.getClientArea(); + /* + * If you wish to paint the selection beyond the end of last + * column, you must change the clipping region. + */ + int columnCount = table.getColumnCount(); + if (event.index == columnCount - 1 || columnCount == 0) { + int width = area.x + area.width - event.x; + if (width > 0) { + Region region = new Region(); + gc.getClipping(region); + region.add(event.x, event.y, width, event.height); + gc.setClipping(region); + region.dispose(); + } + } + gc.setAdvanced(true); + if (gc.getAdvanced()) { + gc.setAlpha(127); + } + Rectangle rect = event.getBounds(); + Color foreground = gc.getForeground(); + + gc.setForeground(table.getDisplay().getSystemColor( + SWT.COLOR_RED)); + gc.fillRectangle(0, rect.y, 500, rect.height - 1); + + // Restore colors for subsequent drawing + gc.setForeground(foreground); + // Mark event as handled + event.detail &= ~SWT.SELECTED; + } + } + + void sortTableColumn(Event event) { + if (event == null) { + throw new IllegalArgumentException( + "Parameter 'event' must not be null."); + } + // determine new sort column and direction + TableColumn sortColumn = table.getSortColumn(); + TableColumn currentColumn = (TableColumn) event.widget; + int direction = table.getSortDirection(); + if (sortColumn == currentColumn) { + direction = direction == SWT.UP ? SWT.DOWN : SWT.UP; + } else { + table.setSortColumn(currentColumn); + direction = SWT.UP; + } + table.setSortDirection(direction); + + Collections.sort(dataList, new DataComparator( + table.getSortColumn(), table.getSortDirection())); + // Update data displayed in table + table.clearAll(); + } + + void editColor() { + TableItem[] selection = table.getSelection(); + if (selection.length == 1) { + Data data = (Data) selection[0].getData(); + ColorDialog colorDialog = new ColorDialog(table.getShell()); + colorDialog.setRGB(data.getRGB()); + RGB newRGB = colorDialog.open(); + + if (newRGB != null) { + owner.imageProvider.setPaletteRGB(data.getPixelColor(), + newRGB); + } + } + } + + public void setImageColorHistogram( + ImageColorHistogram imageColorHistogram, + boolean paletteChangeable, boolean showUnusedColors, + boolean force) { + if (imageColorHistogram == null) { + clear(); + } else if (this.imageColorHistogram != imageColorHistogram || force) { + clear(); + this.imageColorHistogram = imageColorHistogram; + + // Register double click only if palette is changeable. + table.removeListener(SWT.DefaultSelection, + defaultSelectionListener); + if (paletteChangeable) { + table.addListener(SWT.DefaultSelection, + defaultSelectionListener); + } + + // For direct palette, display only used pixel colors. + // For indexed palette, display either all pixel colors or only + // used pixel colors. + List pixelColors; + if (imageColorHistogram.isDirectPalette()) { + pixelColors = imageColorHistogram.getUsedPixelColors(); + } else { + if (showUnusedColors) { + pixelColors = imageColorHistogram + .getPalettePixelColors(); + } else { + pixelColors = imageColorHistogram.getUsedPixelColors(); + } + } + + // Hide unused column in direct palette mode. + if (imageColorHistogram.isDirectPalette()) { + pixelColorHexColumn.setWidth(0); + pixelColorBinaryColumn.setWidth(0); + } else { + pixelColorHexColumn.setWidth(WIDTH); + pixelColorBinaryColumn.setWidth(WIDTH); + } + + // Create data list. + int size = pixelColors.size(); + int pixelCount = imageColorHistogram.getPixelCount(); + for (int i = 0; i < size; i++) { + Integer pixelColor = pixelColors.get(i); + int pixelColorCount = imageColorHistogram + .getPixelColorCount(pixelColor); + int pixelColorCountPercent = ((pixelColorCount * 100) / pixelCount); + RGB rgb = imageColorHistogram.getRGB(pixelColor); + Data data = new Data(i, pixelColor, rgb, pixelColorCount, + pixelColorCountPercent); + dataList.add(data); + } + + Collections.sort( + dataList, + new DataComparator(table.getSortColumn(), table + .getSortDirection())); + table.setItemCount(dataList.size()); + table.setSelection(0); + } + + } + } + + // ID of this view in the plugin manifest. + public static final String ID = ImagePaletteView.class.getName(); + + // UI components, not final because they are created outside of the + // constructor. + private IAction editColorAction; + private IAction showUnusedColorsAction; + private Label infoLabel; + private TableView tableView; + + // The currently active image provider or null. + ImageProvider imageProvider; + + /** + * Creation is private. + */ + public ImagePaletteView() { + } + + @Override + public void createPartControl(Composite parent) { + + IToolBarManager toolBarManager = getViewSite().getActionBars() + .getToolBarManager(); + + editColorAction = new Action( + Texts.IMAGE_PALETTE_VIEW_EDIT_COLOR_ACTION_LABEL, + IAction.AS_DROP_DOWN_MENU) { + @Override + public void run() { + editColor(); + } + }; + editColorAction + .setToolTipText(Texts.IMAGE_PALETTE_VIEW_EDIT_COLOR_ACTION_TOOLTIP); + editColorAction.setMenuCreator(new PaletteMenuCreator()); + + showUnusedColorsAction = new Action( + Texts.IMAGE_PALETTE_VIEW_UNUSED_COLORS_ACTION_LABEL, + IAction.AS_CHECK_BOX) { + @Override + public void run() { + showUnusedColors(); + } + }; + showUnusedColorsAction + .setToolTipText(Texts.IMAGE_PALETTE_VIEW_UNUSED_COLORS_ACTION_TOOLTIP); + + toolBarManager.add(editColorAction); + toolBarManager.add(showUnusedColorsAction); + + // presetColorsAction.setText("Test"); + + GridLayout gridLayout = new GridLayout(); + gridLayout.marginWidth = 0; + gridLayout.marginHeight = 0; + parent.setLayout(gridLayout); + + Composite infoComposite = new Composite(parent, SWT.NONE); + gridLayout = new GridLayout(1, false); + gridLayout.marginHeight = 0; + infoComposite.setLayout(gridLayout); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + infoComposite.setLayoutData(gd); + infoLabel = new Label(infoComposite, SWT.NONE); + infoLabel.setLayoutData(gd); + + tableView = new TableView(parent, this); + + // Add this as a global selection listener + getSite().getPage().addSelectionListener(this); + + // Preset based on current selection + selectionChanged(null, getSite().getPage().getSelection()); + + } + + void editColor() { + tableView.editColor(); + } + + void showUnusedColors() { + ImageColorHistogram imageColorHistogram = imageProvider + .getImageColorHistogram(); + boolean paletteChangeable = imageProvider.isPaletteChangeable(); + tableView.setImageColorHistogram(imageColorHistogram, + paletteChangeable, showUnusedColorsAction.isChecked(), true); + } + + @Override + public void setFocus() { + tableView.setFocus(); + } + + @Override + public void dispose() { + + if (tableView != null) { + tableView.clear(); + } + + if (imageProvider != null) { + imageProvider.setImagePaletteView(null); + imageProvider = null; + } + + editColorAction.getMenuCreator().dispose(); + getSite().getPage().removeSelectionListener(this); + super.dispose(); + } + + @Override + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + + if (part == null) { + setImageProvider(null); + } else { + if (part instanceof GraphicsEditor) { + GraphicsEditor graphicsEditor = ((GraphicsEditor) part); + setImageProvider(graphicsEditor.getImageProvider()); + } + } + } + + /** + * Sets the image provider. + * + * @param imageProvider + * The image provider or null. + */ + public void setImageProvider(ImageProvider imageProvider) { + if (imageProvider != this.imageProvider) { + // Unregister from old provider + if (this.imageProvider != null) { + this.imageProvider.setImagePaletteView(null); + this.imageProvider = null; + } + + // Register with new provider + if (imageProvider != null) { + this.imageProvider = imageProvider; + this.imageProvider.setImagePaletteView(this); + } + } + dataToUI(); + } + + /** + * Retrieve the current status from the image provider and display it. + * + */ + public void dataToUI() { + boolean enabled; + + if (imageProvider != null) { + ImageColorHistogram imageColorHistogram = imageProvider + .getImageColorHistogram(); + boolean paletteChangeable = imageProvider.isPaletteChangeable(); + editColorAction.setEnabled(paletteChangeable); + + enabled = (imageColorHistogram != null) + && !imageColorHistogram.isDirectPalette(); + showUnusedColorsAction.setEnabled(enabled); + + String text; + if (imageColorHistogram != null) { + int palettBits = imageColorHistogram.getPaletteBits(); + if (imageColorHistogram.isDirectPalette()) { + text = TextUtility + .format(Texts.IMAGE_PALETTE_VIEW_INFO_DIRECT_PALETTE_IMAGE, + NumberUtility + .getLongValueDecimalString(palettBits), + NumberUtility + .getLongValueDecimalString(imageColorHistogram + .getUsedPixelColors() + .size())); + } else { + text = TextUtility + .format(Texts.IMAGE_PALETTE_VIEW_INFO_INDEXED_PALETTE_IMAGE, + NumberUtility + .getLongValueDecimalString(palettBits), + + NumberUtility + .getLongValueDecimalString(imageColorHistogram + .getUsedPixelColors() + .size()), + NumberUtility + .getLongValueDecimalString(1 << palettBits)); + } + } else { + text = Texts.IMAGE_PALETTE_VIEW_INFO_NO_IMAGE; + } + infoLabel.setText(text); + + tableView.setImageColorHistogram(imageColorHistogram, + paletteChangeable, showUnusedColorsAction.isChecked(), + false); + } else { + editColorAction.setEnabled(false); + showUnusedColorsAction.setEnabled(false); + infoLabel.setText(Texts.IMAGE_PALETTE_VIEW_INFO_NO_IMAGE); + tableView.clear(); + } + + } + +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImageProvider.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImageProvider.java new file mode 100644 index 00000000..7cfaf7ff --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImageProvider.java @@ -0,0 +1,57 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.editor; + +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.gfx.converter.ImageColorHistogram; +import com.wudsn.ide.gfx.model.Aspect; + +public interface ImageProvider { + + public void setImageView(ImageView imageView); + + public void setImagePaletteView(ImagePaletteView imagePaletteView); + + public Aspect getAspect(); + + public void setAspect(Aspect value); + + public boolean isShrinkToFit(); + + public void setShrinkToFit(boolean value); + + public boolean isZoomToFit(); + + public void setZoomToFit(boolean value); + + public ImageData getImageData(); + + public ImageColorHistogram getImageColorHistogram(); + + public boolean isPaletteChangeable(); + + public void setPaletteRGBs(RGB[] rgbs); + + public void setPaletteRGB(int pixelColor, RGB rgb); + + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImageView.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImageView.java new file mode 100644 index 00000000..ab76ed9c --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/editor/ImageView.java @@ -0,0 +1,288 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.editor; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.action.ControlContribution; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.part.ViewPart; + +import com.wudsn.ide.base.gui.Action; +import com.wudsn.ide.base.gui.ActionListener; +import com.wudsn.ide.base.gui.MessageManager; +import com.wudsn.ide.base.gui.SWTFactory; +import com.wudsn.ide.gfx.Texts; +import com.wudsn.ide.gfx.converter.ConverterCommonParameters; +import com.wudsn.ide.gfx.gui.AspectField; +import com.wudsn.ide.gfx.gui.ImageCanvas; +import com.wudsn.ide.gfx.model.Aspect; + +/** + * This ImageView class shows the image from an {@link ImageProvider} in an + * {@link ImageCanvas}. + * + * @author Peter Dell + * @author Chengdong Li: cli4@uky.edu + * + * @see ImageCanvas + */ + +public final class ImageView extends ViewPart implements ISelectionListener { + + private final class AspectControlContribution extends ControlContribution implements ActionListener { + + private boolean enabled; + private Aspect value; + private AspectField aspectField; + private Action action; + + public AspectControlContribution() { + super("com.wudsn.ide.gfx.editor.ImageViewAspect"); + enabled = false; + value = new Aspect(1, 1); + } + + @Override + protected Control createControl(Composite parent) { + Composite composite = SWTFactory.createComposite(parent, 2, 1, GridData.FILL_HORIZONTAL); + GridLayout gridLayout = (GridLayout) composite.getLayout(); + gridLayout.marginHeight = 0; + aspectField = new AspectField(composite, Texts.IMAGE_VIEW_ASPECT_LABEL); + aspectField.setEnabled(enabled); + aspectField.setValue(value); + action = new Action(1, this); + aspectField.addSelectionAction(action); + + messageManager.registerField(aspectField, ConverterCommonParameters.MessageIds.DISPLAY_ASPECT); + return composite; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + if (aspectField != null) { + aspectField.setEnabled(enabled); + } + } + + public void setValue(Aspect value) { + this.value = value; + if (aspectField != null) { + aspectField.setValue(value); + } + } + + @Override + public void performAction(Action action) { + imageProvider.setAspect(aspectField.getValue()); + } + } + + public static final String ID = ImageView.class.getName(); + MessageManager messageManager; + + private AspectControlContribution aspectControlContribution; + IAction shrinkToFitAction; + IAction zoomToFitAction; + private ImageCanvas imageCanvas; + + ImageProvider imageProvider; + + /** + * Creation is private. + */ + public ImageView() { + messageManager = new MessageManager(this); + } + + @Override + public void createPartControl(Composite parent) { + + IToolBarManager toolBarManager = getViewSite().getActionBars().getToolBarManager(); + + aspectControlContribution = new AspectControlContribution(); + + shrinkToFitAction = new org.eclipse.jface.action.Action("Shrink", IAction.AS_CHECK_BOX) { + @Override + public void run() { + imageProvider.setShrinkToFit(shrinkToFitAction.isChecked()); + } + }; + zoomToFitAction = new org.eclipse.jface.action.Action("Zoom", IAction.AS_CHECK_BOX) { + @Override + public void run() { + imageProvider.setZoomToFit(zoomToFitAction.isChecked()); + } + }; + + toolBarManager.add(aspectControlContribution); + toolBarManager.add(shrinkToFitAction); + toolBarManager.add(zoomToFitAction); + + imageCanvas = new ImageCanvas(parent, SWT.NONE); + + // Currently there's no use-case for reacting on the mouse position. + // imageCanvas.addMouseMoveListener(new MouseMoveListener() { + // public void mouseMove(MouseEvent event) { + // Point point; + // messageManager.clearMessages(); + // + // point = imageCanvas.getPoint(event); + // messageManager.sendMessage( + // 0, + // IStatus.INFO, + // "x={0} y={1}", + // new String[] { + // NumberUtility + // .getLongValueDecimalString(point.x), + // + // NumberUtility + // .getLongValueDecimalString(point.y) }); + // messageManager.displayMessages(); + // + // } + // }); + + // Add this as a global selection listener + getSite().getPage().addSelectionListener(this); + + // Preset based on current selection + selectionChanged(null, getSite().getPage().getSelection()); + } + + @Override + public void setFocus() { + imageCanvas.setFocus(); + } + + @Override + public void dispose() { + + if (imageProvider != null) { + imageProvider.setImageView(null); + imageProvider = null; + } + + getSite().getPage().removeSelectionListener(this); + imageCanvas.dispose(); + super.dispose(); + } + + @Override + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + + if (part == null) { + setImageProvider(null); + } else { + if (part instanceof GraphicsEditor) { + GraphicsEditor graphicsEditor = ((GraphicsEditor) part); + setImageProvider(graphicsEditor.getImageProvider()); + System.out.println(this + "" + part + "" + selection); + } + } + } + + /** + * Sets the image provider. + * + * @param imageProvider + * The image provider or null. + */ + public void setImageProvider(ImageProvider imageProvider) { + if (imageProvider != this.imageProvider) { + // Unregister from old provider + if (this.imageProvider != null) { + this.imageProvider.setImageView(null); + this.imageProvider = null; + } + + // Register with new provider + if (imageProvider != null) { + this.imageProvider = imageProvider; + this.imageProvider.setImageView(this); + } + } + dataToUI(); + + } + + /** + * Retrieve the current status from the image provider and display it. + * + */ + public void dataToUI() { + ImageData imageData; + boolean enabled; + + messageManager.clearMessages(); + if (imageProvider != null) { + imageData = imageProvider.getImageData(); + enabled = (imageData != null); + + aspectControlContribution.setEnabled(enabled); + aspectControlContribution.setValue(imageProvider.getAspect()); + shrinkToFitAction.setEnabled(false); + shrinkToFitAction.setChecked(imageProvider.isShrinkToFit()); + shrinkToFitAction.setEnabled(enabled); + zoomToFitAction.setEnabled(false); + zoomToFitAction.setChecked(imageProvider.isZoomToFit()); + zoomToFitAction.setEnabled(enabled); + imageCanvas.setShrinkToFit(imageProvider.isShrinkToFit()); + imageCanvas.setZoomToFit(imageProvider.isZoomToFit()); + + boolean valid; + ImageData displayImageData; + + Aspect aspect = imageProvider.getAspect(); + if (aspect.isValid()) { + valid = true; + } else { + messageManager.sendMessage(ConverterCommonParameters.MessageIds.DISPLAY_ASPECT, IStatus.ERROR, + "Invalid display aspect"); + valid = false; + } + if (valid && imageData != null) { + int width = imageData.width; + int height = imageData.height; + displayImageData = imageData.scaledTo(width * aspect.getValidFactorX(), + height * aspect.getValidFactorY()); + } else { + displayImageData = null; + } + + imageCanvas.setImageData(displayImageData); + } else { + aspectControlContribution.setEnabled(false); + shrinkToFitAction.setEnabled(false); + zoomToFitAction.setEnabled(false); + imageCanvas.setImageData(null); + } + messageManager.displayMessages(); + } +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/AspectField.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/AspectField.java new file mode 100644 index 00000000..23e1dc0d --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/AspectField.java @@ -0,0 +1,134 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.gui; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; + +import com.wudsn.ide.base.common.StringUtility; +import com.wudsn.ide.base.gui.Action; +import com.wudsn.ide.base.gui.Field; +import com.wudsn.ide.gfx.model.Aspect; +import com.wudsn.ide.gfx.model.AspectUtility; + +public final class AspectField extends Field { + + private Label label; + private Combo combo; + private List selectionActions; + + public AspectField(Composite parent, String labelText) { + if (parent == null) { + throw new IllegalArgumentException( + "Parameter 'parent' must not be null."); + } + if (labelText == null) { + throw new IllegalArgumentException( + "Parameter 'labelText' must not be null."); + } + + label = new Label(parent, SWT.NONE); + label.setText(labelText); + combo = new Combo(parent, SWT.DROP_DOWN); + + combo.add("1x1"); + combo.add("2x1"); + combo.add("2x2"); + combo.add("4x2"); + combo.add("4x4"); + + combo.select(0); + + selectionActions = new ArrayList(1); + } + + public void setValue(Aspect value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + for (Action action : selectionActions) { + action.setEnabled(false); + } + combo.setText(AspectUtility.toString(value)); + for (Action action : selectionActions) { + action.setEnabled(true); + } + } + + public Aspect getValue() { + Aspect result; + String text = combo.getText().toLowerCase(); + if (StringUtility.isEmpty(text)) { + result = new Aspect(1, 1); + } else { + result = AspectUtility.fromString(text); + } + return result; + + } + + /** + * {@inheritDoc} + */ + @Override + public Control getControl() { + return combo; + } + + /** + * {@inheritDoc} + */ + @Override + public void setEnabled(boolean enabled) { + label.setEnabled(enabled); + combo.setEnabled(enabled); + } + + /** + * {@inheritDoc} + */ + @Override + public void setEditable(boolean editable) { + // There is only a style SWT#READ_ONLY, but no changeable property + } + + /** + * Adds a selection action which is fire when the field content changes. + * + * @param action + * The selection action, not null. + */ + public void addSelectionAction(Action action) { + if (action == null) { + throw new IllegalArgumentException( + "Parameter 'action' must not be null."); + } + selectionActions.add(action); + combo.addSelectionListener(action); + } + +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/ConverterIdField.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/ConverterIdField.java new file mode 100644 index 00000000..cba855f0 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/ConverterIdField.java @@ -0,0 +1,128 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.gui; + +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; + +import com.wudsn.ide.base.gui.Field; +import com.wudsn.ide.gfx.GraphicsPlugin; +import com.wudsn.ide.gfx.converter.ConverterDefinition; +import com.wudsn.ide.gfx.converter.ConverterRegistry; +import com.wudsn.ide.gfx.model.ConverterDirection; + +public final class ConverterIdField extends Field { + + private Label label; + private Combo combo; + private List converterDefinitions; + + public ConverterIdField(Composite parent, String labelText, + ConverterDirection converterDirection) { + if (parent == null) { + throw new IllegalArgumentException( + "Parameter 'parent' must not be null."); + } + if (labelText == null) { + throw new IllegalArgumentException( + "Parameter 'labelText' must not be null."); + } + if (converterDirection == null) { + throw new IllegalArgumentException( + "Parameter 'converterDirection' must not be null."); + } + label = new Label(parent, SWT.NONE); + label.setText(labelText); + combo = new Combo(parent, SWT.DROP_DOWN); + + GraphicsPlugin plugin = GraphicsPlugin.getInstance(); + ConverterRegistry converterRegistry = plugin.getConverterRegistry(); + converterDefinitions = converterRegistry + .getDefinitions(converterDirection); + + combo.add(""); + for (ConverterDefinition converterDefinition : converterDefinitions) { + combo.add(converterDefinition.getName()); + } + combo.select(0); + + } + + /** + * {@inheritDoc} + */ + @Override + public Control getControl() { + return combo; + } + + /** + * {@inheritDoc} + */ + @Override + public void setEnabled(boolean enabled) { + label.setEnabled(enabled); + combo.setEnabled(enabled); + + } + + /** + * {@inheritDoc} + */ + @Override + public void setEditable(boolean editable) { + // There is only an SWT.READ_ONLY style but not property + } + + public void setValue(String value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + for (int i = 0; i < converterDefinitions.size(); i++) { + if (value.equals(converterDefinitions.get(i).getId())) { + combo.select(i + 1); + return; + } + } + combo.select(0); + } + + public String getValue() { + int index; + index = combo.getSelectionIndex(); + if (index == -1 || index == 0) { + return ""; + } + String result = converterDefinitions.get(index - 1).getId(); + return result; + } + + public void addSelectionListener(SelectionListener selectionListener) { + combo.addSelectionListener(selectionListener); + + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/ImageCanvas.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/ImageCanvas.java new file mode 100644 index 00000000..ae315690 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/ImageCanvas.java @@ -0,0 +1,369 @@ +package com.wudsn.ide.gfx.gui; + +import java.awt.geom.AffineTransform; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.ScrollBar; + +/** + * A scrollable SWT image canvas that extends org.eclipse.swt.graphics.Canvas. + * + * @author Peter Dell + * @author Chengdong Li: cli4@uky.edu + */ +public final class ImageCanvas extends Canvas { + + // Zoom settings + private boolean shrinkToFit; + private boolean zoomToFit; + + // Original image + private Image sourceImage; + + // Affine transform applied to the source image. + private AffineTransform transform; + + // Screen image + private Image screenImage; + + /** + * Constructor for ScrollableCanvas. + * + * @param parent + * The parent of this control, not null. + * @param style + * The style of this control. + */ + public ImageCanvas(final Composite parent, int style) { + super(parent, style | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL + | SWT.NO_BACKGROUND); + + // Register a resize listener + addControlListener(new ControlAdapter() { + @Override + public void controlResized(ControlEvent event) { + updateSize(); + } + }); + // Register a paint listener + addPaintListener(new PaintListener() { + @Override + public void paintControl(final PaintEvent event) { + paint(event.gc); + } + }); + + // Start with the identity transformation. + transform = new AffineTransform(); + initScrollBars(); + } + + /** + * Dispose the garbage here + */ + @Override + public void dispose() { + if (sourceImage != null && !sourceImage.isDisposed()) { + sourceImage.dispose(); + sourceImage = null; + } + if (screenImage != null && !screenImage.isDisposed()) { + screenImage.dispose(); + screenImage = null; + } + } + + /* Paint function */ + void paint(GC gc) { + // Canvas' painting area + Rectangle clientRectangle = getClientArea(); + + if (sourceImage != null) { + Rectangle imageRectangle = ImageCanvasUtility + .inverseTransformRectangle(transform, clientRectangle); + // Find a better start point to render + int gap = 2; + imageRectangle.x -= gap; + imageRectangle.y -= gap; + imageRectangle.width += 2 * gap; + imageRectangle.height += 2 * gap; + + Rectangle imageBounds = sourceImage.getBounds(); + imageRectangle = imageRectangle.intersection(imageBounds); + Rectangle destRect = ImageCanvasUtility.transformRectangle( + transform, imageRectangle); + + if (screenImage != null) { + screenImage.dispose(); + } + screenImage = new Image(getDisplay(), clientRectangle.width, + clientRectangle.height); + GC newGC = new GC(screenImage); + newGC.setBackground(getBackground()); + newGC.fillRectangle(clientRectangle); + newGC.setClipping(clientRectangle); + newGC.drawImage(sourceImage, imageRectangle.x, imageRectangle.y, + imageRectangle.width, imageRectangle.height, destRect.x, + destRect.y, destRect.width, destRect.height); + newGC.dispose(); + + gc.drawImage(screenImage, 0, 0); + } else { + gc.setClipping(clientRectangle); + gc.fillRectangle(clientRectangle); + initScrollBars(); + } + } + + /** + * Initializes the scrollbars and registers the listeners. + */ + private void initScrollBars() { + ScrollBar horizontal = getHorizontalBar(); + horizontal.setEnabled(false); + horizontal.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent event) { + scrollHorizontally((ScrollBar) event.widget); + } + }); + ScrollBar vertical = getVerticalBar(); + vertical.setEnabled(false); + vertical.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent event) { + scrollVertically((ScrollBar) event.widget); + } + }); + } + + /* Scroll horizontally */ + void scrollHorizontally(ScrollBar scrollBar) { + if (sourceImage == null) + return; + + AffineTransform af = transform; + double tx = af.getTranslateX(); + double select = -scrollBar.getSelection(); + af.preConcatenate(AffineTransform.getTranslateInstance(select - tx, 0)); + transform = af; + synchronizeScrollBars(); + } + + /* Scroll vertically */ + void scrollVertically(ScrollBar scrollBar) { + if (sourceImage == null) + return; + + AffineTransform af = transform; + double ty = af.getTranslateY(); + double select = -scrollBar.getSelection(); + af.preConcatenate(AffineTransform.getTranslateInstance(0, select - ty)); + transform = af; + synchronizeScrollBars(); + } + + /** + * Synchronize the scrollbars with the image. If the transform is out of + * range, this method will correct it. This function considers only + * following factors : transform, image size, client area size. + */ + void synchronizeScrollBars() { + if (sourceImage == null) { + redraw(); + return; + } + + AffineTransform af = transform; + double sx = af.getScaleX(), sy = af.getScaleY(); + double tx = af.getTranslateX(), ty = af.getTranslateY(); + if (tx > 0) { + tx = 0; + } + if (ty > 0) { + ty = 0; + } + + Rectangle clientArea = getClientArea(); + + ScrollBar horizontal = getHorizontalBar(); + horizontal.setIncrement((clientArea.width / 100)); + horizontal.setPageIncrement(clientArea.width); + Rectangle imageBound = sourceImage.getBounds(); + if (imageBound.width * sx > clientArea.width) { + // Image is wider than client area + horizontal.setMaximum((int) (imageBound.width * sx)); + horizontal.setEnabled(true); + if (((int) -tx) > horizontal.getMaximum() - clientArea.width) { + tx = -horizontal.getMaximum() + clientArea.width; + } + } else { + // Image is narrower than client area + horizontal.setEnabled(false); + // Center if too small. + tx = (clientArea.width - imageBound.width * sx) / 2; + } + horizontal.setSelection((int) (-tx)); + horizontal.setThumb(clientArea.width); + + ScrollBar vertical = getVerticalBar(); + vertical.setIncrement(clientArea.height / 100); + vertical.setPageIncrement(clientArea.height); + if (imageBound.height * sy > clientArea.height) { + // Image is higher than client area + vertical.setMaximum((int) (imageBound.height * sy)); + vertical.setEnabled(true); + if (((int) -ty) > vertical.getMaximum() - clientArea.height) { + ty = -vertical.getMaximum() + clientArea.height; + } + } else { + // Image is not as high as the client area + vertical.setEnabled(false); + // Center if too small + ty = (clientArea.height - imageBound.height * sy) / 2; + } + vertical.setSelection((int) (-ty)); + vertical.setThumb(clientArea.height); + + // Update transform using concatenation + af = AffineTransform.getScaleInstance(sx, sy); + af.preConcatenate(AffineTransform.getTranslateInstance(tx, ty)); + transform = af; + + redraw(); + } + + /** + * Sets the shrink to fit property. This will no update the image. + * + * @param shrinkToFit + * true to activate the automatic shrinking. + */ + public void setShrinkToFit(boolean shrinkToFit) { + this.shrinkToFit = shrinkToFit; + updateSize(); + } + + /** + * Sets the zoom to fit property. This will no update the image. + * + * @param zoomToFit + * true to activate the automatic zooming. + */ + public void setZoomToFit(boolean zoomToFit) { + this.zoomToFit = zoomToFit; + updateSize(); + } + + /** + * Reset the image data and update the image + * + * @param data + * image data to be set + */ + public void setImageData(ImageData data) { + Rectangle oldBounds = new Rectangle(-1, -1, -1, -1); + + if (sourceImage != null) { + oldBounds = sourceImage.getBounds(); + sourceImage.dispose(); + sourceImage = null; + } + + if (data != null) { + sourceImage = new Image(getDisplay(), data); + + if (!sourceImage.getBounds().equals(oldBounds)) { + updateSize(); + } else { + redraw(); + } + } else { + redraw(); + } + } + + public Image getImage() { + return sourceImage; + } + + /** + * Translates the x,y coordinates from a mouse event to the point + * coordinates in the original unscaled image. + * + * @param event + * The event, not null. + * @return The point or null. + */ + public Point getPoint(MouseEvent event) { + if (event == null) { + throw new IllegalArgumentException( + "Parameter 'event' must not be null."); + } + return new Point(event.x, event.y); + } + + /** + * Update the image size and scrollbar positions. + */ + void updateSize() { + if (sourceImage == null) { + redraw(); + return; + } + Rectangle imageBounds = sourceImage.getBounds(); + Rectangle clientArea = getClientArea(); + double sx = (double) clientArea.width / (double) imageBounds.width; + double sy = (double) clientArea.height / (double) imageBounds.height; + + if (!shrinkToFit) { + sx = Math.max(sx, 1.0); + sy = Math.max(sy, 1.0); + } + if (!zoomToFit) { + sx = Math.min(sx, 1.0); + sy = Math.min(sy, 1.0); + } + double s = Math.min(sx, sy); + double dx = 0.5 * clientArea.width; + double dy = 0.5 * clientArea.height; + zoom(dx, dy, s, new AffineTransform()); + } + + /** + * Perform a zooming operation centered on the given point (dx, dy) and + * using the given scale factor. The given AffineTransform instance is + * preconcatenated. + * + * @param dx + * center x + * @param dy + * center y + * @param scale + * zoom rate + * @param af + * original affinetransform + */ + private void zoom(double dx, double dy, double scale, AffineTransform af) { + af.preConcatenate(AffineTransform.getTranslateInstance(-dx, -dy)); + af.preConcatenate(AffineTransform.getScaleInstance(scale, scale)); + af.preConcatenate(AffineTransform.getTranslateInstance(dx, dy)); + transform = af; + synchronizeScrollBars(); + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/ImageCanvasUtility.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/ImageCanvasUtility.java new file mode 100644 index 00000000..9e75a6fb --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/ImageCanvasUtility.java @@ -0,0 +1,202 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.gui; + +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Point2D; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; + +/** + * Utility for Java2d transform used by{@link ImageCanvas}. + * + * @author Peter Dell + * @author Chengdong Li: cli4@uky.edu + * + */ +final class ImageCanvasUtility { + + /** + * Creation is private. + */ + private ImageCanvasUtility() { + } + + /** + * Apply an affine transform to an SWT rectangle. The resulting SWT + * rectangle will have positive width and positive height. + * + * @param affineTransform + * The affine transform, not null. + * @param sourceRectangle + * The SWT source rectangle, not null. + * @return The SWT rectangle after transform with positive width and height, + * not null. + */ + public static Rectangle transformRectangle(AffineTransform affineTransform, + Rectangle sourceRectangle) { + if (affineTransform == null) { + throw new IllegalArgumentException( + "Parameter 'transform' must not be null."); + } + if (sourceRectangle == null) { + throw new IllegalArgumentException( + "Parameter 'sourceRectangle' must not be null."); + } + Rectangle result = new Rectangle(0, 0, 0, 0); + sourceRectangle = absoluteRectangle(sourceRectangle); + Point point = new Point(sourceRectangle.x, sourceRectangle.y); + point = transformPoint(affineTransform, point); + result.x = point.x; + result.y = point.y; + result.width = (int) (sourceRectangle.width * affineTransform + .getScaleX()); + result.height = (int) (sourceRectangle.height * affineTransform + .getScaleY()); + return result; + } + + /** + * Apply the inverse of an affine transform to an SWT rectangle. The + * resulting SWT rectangle will have positive width and positive height. + * + * @param affineTransform + * The affine transform, not null. + * @param sourceRectangle + * The SWT source rectangle, not null. + * @return The SWT rectangle after transform with positive width and height, + * not null. + */ + public static Rectangle inverseTransformRectangle( + AffineTransform affineTransform, Rectangle sourceRectangle) { + if (affineTransform == null) { + throw new IllegalArgumentException( + "Parameter 'transform' must not be null."); + } + if (sourceRectangle == null) { + throw new IllegalArgumentException( + "Parameter 'sourceRectangle' must not be null."); + } + Rectangle result = new Rectangle(0, 0, 0, 0); + sourceRectangle = absoluteRectangle(sourceRectangle); + Point p1 = new Point(sourceRectangle.x, sourceRectangle.y); + p1 = inverseTransformPoint(affineTransform, p1); + result.x = p1.x; + result.y = p1.y; + result.width = (int) (sourceRectangle.width / affineTransform + .getScaleX()); + result.height = (int) (sourceRectangle.height / affineTransform + .getScaleY()); + return result; + } + + /** + * Apply an affine transform to an SWT point. + * + * @param affineTransform + * The affine transform, not null. + * @param sourcePoint + * The SWT source point, not null. + * @return The SWT point after transform, not null. + */ + public static Point transformPoint(AffineTransform affineTransform, + Point sourcePoint) { + if (affineTransform == null) { + throw new IllegalArgumentException( + "Parameter 'affineTransform' must not be null."); + } + if (sourcePoint == null) { + throw new IllegalArgumentException( + "Parameter 'sourcePoint' must not be null."); + } + Point2D src = new Point2D.Float(sourcePoint.x, sourcePoint.y); + Point2D dest = affineTransform.transform(src, null); + Point result = new Point((int) Math.floor(dest.getX()), (int) Math + .floor(dest.getY())); + return result; + } + + /** + * Apply the inverse of an affine transform to an SWT point. + * + * @param affineTransform + * The affine transform, not null. + * @param sourcePoint + * The SWT source point, not null. + * @return The SWT point after transform, not null. + */ + public static Point inverseTransformPoint(AffineTransform affineTransform, + Point sourcePoint) { + + if (affineTransform == null) { + throw new IllegalArgumentException( + "Parameter 'affineTransform' must not be null."); + } + if (sourcePoint == null) { + throw new IllegalArgumentException( + "Parameter 'sourcePoint' must not be null."); + } + Point2D src = new Point2D.Float(sourcePoint.x, sourcePoint.y); + + Point2D dest; + try { + dest = affineTransform.inverseTransform(src, null); + } catch (NoninvertibleTransformException ex) { + throw new RuntimeException("Invalid transformation", ex); + } + Point result = new Point((int) Math.floor(dest.getX()), (int) Math + .floor(dest.getY())); + return result; + } + + /** + * Given arbitrary SWT rectangle, return a rectangle with upper-left start + * and positive width and height. + * + * @param sourceRectangle + * The SWT source rectangle, not null. + * @return result The equivalent SWT rectangle with positive width and + * height, not null. + */ + private static Rectangle absoluteRectangle(Rectangle sourceRectangle) { + if (sourceRectangle == null) { + throw new IllegalArgumentException( + "Parameter 'sourceRectangle' must not be null."); + } + Rectangle result = new Rectangle(0, 0, 0, 0); + if (sourceRectangle.width < 0) { + result.x = sourceRectangle.x + sourceRectangle.width + 1; + result.width = -sourceRectangle.width; + } else { + result.x = sourceRectangle.x; + result.width = sourceRectangle.width; + } + if (sourceRectangle.height < 0) { + result.y = sourceRectangle.y + sourceRectangle.height + 1; + result.height = -sourceRectangle.height; + } else { + result.y = sourceRectangle.y; + result.height = sourceRectangle.height; + } + return result; + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/SourceFileView.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/SourceFileView.java new file mode 100644 index 00000000..490c3a7c --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/SourceFileView.java @@ -0,0 +1,147 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.gui; + +import javax.swing.event.ChangeListener; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; + +import com.wudsn.ide.base.common.HexUtility; +import com.wudsn.ide.base.gui.FilePathField; +import com.wudsn.ide.base.gui.IntegerField; +import com.wudsn.ide.base.gui.TextField; +import com.wudsn.ide.gfx.Texts; + +public final class SourceFileView { + + private static final int[] EMPTY_DEFAULT_VALUES = new int[] { 0, 65535 }; + + private final FilePathField filePathField; + private final TextField fileSizeField; + private final IntegerField fileOffsetField; + private final Label dummyLabel; + + public SourceFileView(Composite parent, String labelText, int dialogMode) { + if (parent == null) { + throw new IllegalArgumentException("Parameter 'parent' must not be null."); + } + if (dialogMode != SWT.OPEN && dialogMode != SWT.SAVE) { + throw new IllegalArgumentException( + "Parameter 'dialogMode' must be 'SWT.OPEN' or 'SWT.SAVE'. Specified value is " + dialogMode + "-"); + } + + filePathField = new FilePathField(parent, labelText, dialogMode); + + fileSizeField = new TextField(parent, Texts.FILE_SECTION_FIELD_SIZE_LABEL, SWT.READ_ONLY); + + fileOffsetField = new IntegerField(parent, Texts.FILE_SECTION_FIELD_OFFSET_LABEL, EMPTY_DEFAULT_VALUES, true, + 4, SWT.NONE); + + dummyLabel = new Label(parent, SWT.NONE); + } + + public FilePathField getFilePathField() { + return filePathField; + } + + public IntegerField getFileOffsetField() { + return fileOffsetField; + } + + /** + * Sets the path prefix which will be stripped automatically if it is the + * prefix of the user input. + * + * @param filePathPrefix + * The file path prefix, may be empty, not null. + */ + public void setFilePathPrefix(IPath filePathPrefix) { + if (filePathPrefix == null) { + throw new IllegalArgumentException("Parameter 'filePathPrefix' must not be null."); + } + filePathField.setFilePathPrefix(filePathPrefix); + } + + public void setFilePath(String filePath) { + filePathField.setValue(filePath); + } + + public String getFilePath() { + return filePathField.getValue(); + } + + public void setFileBytes(byte[] bytes) { + if (bytes == null) { + fileSizeField.setValue(Texts.FILE_SECTION_FIELD_SIZE_NO_DATA); + fileOffsetField.setDefaultValues(EMPTY_DEFAULT_VALUES); + } else { + fileSizeField.setValue(HexUtility.getLongValueHexString(bytes.length)); + + int step = (bytes.length + 15) / 16; + int[] defaultValues = new int[16]; + + for (int i = 0; i < 16; i++) { + defaultValues[i] = i * step; + } + + fileOffsetField.setDefaultValues(defaultValues); + } + } + + public void setFileOffset(int fileOffset) { + fileOffsetField.setValue(fileOffset); + } + + public int getFileOffset() { + return fileOffsetField.getValue(); + } + + public void setVisible(boolean visible) { + filePathField.setVisible(visible); + fileSizeField.setVisible(visible); + fileOffsetField.setVisible(visible); + dummyLabel.setVisible(visible); + } + + public void setEnabled(boolean enabled) { + filePathField.setEnabled(enabled); + fileSizeField.setEnabled(enabled); + fileOffsetField.setEnabled(enabled); + dummyLabel.setEnabled(enabled); + } + + /** + * Adds a change listener. + * + * @param changeListener + * The change listener , not null. + */ + public void addChangeListener(ChangeListener changeListener) { + if (changeListener == null) { + throw new IllegalArgumentException("Parameter 'changeListener' must not be null."); + } + filePathField.addChangeListener(changeListener); + fileOffsetField.addChangeListener(changeListener); + + } +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/TargetFileView.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/TargetFileView.java new file mode 100644 index 00000000..a0c93466 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/gui/TargetFileView.java @@ -0,0 +1,119 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ +package com.wudsn.ide.gfx.gui; + +import javax.swing.event.ChangeListener; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; + +import com.wudsn.ide.base.common.HexUtility; +import com.wudsn.ide.base.gui.FilePathField; +import com.wudsn.ide.base.gui.TextField; +import com.wudsn.ide.gfx.Texts; + +public final class TargetFileView { + + private final FilePathField filePathField; + private final TextField fileSizeField; + + public TargetFileView(Composite parent, String labelText, int dialogMode) { + if (parent == null) { + throw new IllegalArgumentException( + "Parameter 'parent' must not be null."); + } + if (dialogMode != SWT.OPEN && dialogMode != SWT.SAVE) { + throw new IllegalArgumentException( + "Parameter 'dialogMode' must be 'SWT.OPEN' or 'SWT.SAVE'. Specified value is " + + dialogMode + "-"); + } + + filePathField = new FilePathField(parent, labelText, dialogMode); + + fileSizeField = new TextField(parent, + Texts.FILE_SECTION_FIELD_SIZE_LABEL, SWT.READ_ONLY); + } + + public FilePathField getFilePathField() { + return filePathField; + } + + /** + * Sets the path prefix which will be stripped automatically if it is the + * prefix of the user input. + * + * @param filePathPrefix + * The file path prefix, may be empty, not null. + */ + public void setFilePathPrefix(IPath filePathPrefix) { + if (filePathPrefix == null) { + throw new IllegalArgumentException( + "Parameter 'filePathPrefix' must not be null."); + } + filePathField.setFilePathPrefix(filePathPrefix); + } + + public void setFilePath(String filePath) { + filePathField.setValue(filePath); + } + + public String getFilePath() { + return filePathField.getValue(); + } + + public void setFileBytes(byte[] bytes) { + if (bytes == null) { + fileSizeField.setValue(Texts.FILE_SECTION_FIELD_SIZE_NO_DATA); + } else { + fileSizeField.setValue(HexUtility + .getLongValueHexString(bytes.length)); + + int step = (bytes.length + 15) / 16; + int[] defaultValues = new int[16]; + + for (int i = 0; i < 16; i++) { + defaultValues[i] = i * step; + } + } + } + + public void setVisible(boolean visible) { + filePathField.setVisible(visible); + fileSizeField.setVisible(visible); + } + + public void setEnabled(boolean enabled) { + filePathField.setEnabled(enabled); + fileSizeField.setEnabled(enabled); + } + + /** + * Adds a change listener. + * + * @param changeListener + * The change listener , not null. + */ + public void addChangeListener(ChangeListener changeListener) { + if (changeListener == null) { + throw new IllegalArgumentException("Parameter 'changeListener' must not be null."); + } + filePathField.addChangeListener(changeListener); + } +} \ No newline at end of file diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/Aspect.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/Aspect.java new file mode 100644 index 00000000..bc387ff4 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/Aspect.java @@ -0,0 +1,82 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ +package com.wudsn.ide.gfx.model; + +public final class Aspect { + + private int factorX; + private int factorY; + + public Aspect(int factorX, int factorY) { + this.factorX = factorX; + this.factorY = factorY; + } + + public int getFactorX() { + return factorX; + } + + public int getFactorY() { + return factorY; + } + + public int getValidFactorX() { + if (isValid()) { + return factorX; + } + return 1; + } + + public int getValidFactorY() { + if (isValid()) { + return factorY; + } + return 1; + } + + public boolean isValid() { + return factorX > 0 && factorX < 32 && factorY > 0 && factorY < 32; + } + + @Override + public boolean equals(Object obj) { + + if (obj instanceof Aspect) { + Aspect aspect; + aspect = (Aspect) obj; + if (aspect.getFactorX() == factorX + && aspect.getFactorY() == factorY) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + + return factorX+17*factorY; + } + + @Override + public String toString() { + return factorX + "x" + factorY; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/AspectUtility.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/AspectUtility.java new file mode 100644 index 00000000..0716ca8f --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/AspectUtility.java @@ -0,0 +1,93 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ +package com.wudsn.ide.gfx.model; + +import com.wudsn.ide.base.common.StringUtility; + +public final class AspectUtility { + + /** + * Creation is private. + */ + private AspectUtility() { + } + + /** + * Gets the language independent string representation of an aspect. + * + * @param value + * The aspect or nullnull. + */ + public static String toString(Aspect value) { + String result; + if (value == null) { + result = ""; + } else { + result = value.getFactorX() + "x" + value.getFactorY(); + } + return result; + } + + /** + * Gets the aspect for a language independent string representation. + * + * @param value + * The language independent string representation, may be empty, + * not null. + * @return The XYFactor or null in case the value was empty. + */ + public static Aspect fromString(String value) { + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + + Aspect result; + int factorX; + int factorY; + + if (StringUtility.isEmpty(value)) { + result = null; + } else { + int index = value.indexOf('x'); + if (index > 0) { + String intValue = value.substring(0, index); + try { + factorX = Integer.parseInt(intValue); + } catch (NumberFormatException ex) { + factorX = -1; + } + intValue = value.substring(index + 1, value.length()); + try { + factorY = Integer.parseInt(intValue); + } catch (NumberFormatException ex) { + factorY = -1; + } + } else { + factorX = -1; + factorY = -1; + } + result = new Aspect(factorX, factorY); + } + return result; + } + +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/ConverterDirection.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/ConverterDirection.java new file mode 100644 index 00000000..d060cd1d --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/ConverterDirection.java @@ -0,0 +1,24 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.model; + +public enum ConverterDirection { + FILES_TO_IMAGE, IMAGE_TO_FILES +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/ConverterMode.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/ConverterMode.java new file mode 100644 index 00000000..347dc690 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/ConverterMode.java @@ -0,0 +1,24 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.model; + +public enum ConverterMode { + NONE, RAW_FILE, RAW_IMAGE, CNV +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/GraphicsPropertiesSerializer.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/GraphicsPropertiesSerializer.java new file mode 100644 index 00000000..5abf5e05 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/GraphicsPropertiesSerializer.java @@ -0,0 +1,151 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.model; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.base.common.PropertiesSerializer; + +public final class GraphicsPropertiesSerializer extends PropertiesSerializer { + + /** + * Creation is public. + */ + public GraphicsPropertiesSerializer() { + + + } + + public final RGB readRGB(String key, RGB defaultValue) { + + if (key == null) { + throw new IllegalArgumentException( + "Parameter 'key' must not be null."); + } + if (defaultValue == null) { + throw new IllegalArgumentException( + "Parameter 'defaultValue' must not be null."); + } + + RGB result; + + int red = readInteger(key + ".red", 0); + int green = readInteger(key + ".green", 0); + int blue = readInteger(key + ".blue", 0); + + result = new RGB(red, green, blue); + + return result; + } + + public final void writeRGB(String key, RGB value) { + + if (key == null) { + throw new IllegalArgumentException( + "Parameter 'key' must not be null."); + } + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + + writeInteger(key + ".red", value.red); + writeInteger(key + ".green", value.green); + writeInteger(key + ".blue", value.blue); + } + + public final Aspect readXYFactor(String key, Aspect defaultValue) { + + if (key == null) { + throw new IllegalArgumentException( + "Parameter 'key' must not be null."); + } + if (defaultValue == null) { + throw new IllegalArgumentException( + "Parameter 'defaultValue' must not be null."); + } + Aspect result; + + int factorX = readInteger(key + ".factorX", 1); + int factorY = readInteger(key + ".factorY", 1); + + result = new Aspect(factorX, factorY); + return result; + } + + public final void writeAspect(String key, Aspect value) { + + if (key == null) { + throw new IllegalArgumentException( + "Parameter 'key' must not be null."); + } + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + setProperty(key + ".factorX", String.valueOf(value.getFactorX())); + setProperty(key + ".factorY", String.valueOf(value.getFactorY())); + } + + + public final RGB[] readRGBArray(String key, RGB[] defaultValue) { + if (key == null) { + throw new IllegalArgumentException( + "Parameter 'key' must not be null."); + } + if (defaultValue == null) { + throw new IllegalArgumentException( + "Parameter 'defaultValue' must not be null."); + } + RGB[] result; + + if (properties.containsKey(key)) { + int length = readInteger(key, 0); + result = new RGB[length]; + String prefix = key + "."; + RGB black = new RGB(0, 0, 0); + for (int i = 0; i < length; i++) { + String valueKey = prefix + i; + result[i] = readRGB(valueKey, black); + } + } else { + result = defaultValue; + } + return result; + + } + + public final void writeRGBArray(String key, RGB[] value) { + if (key == null) { + throw new IllegalArgumentException( + "Parameter 'key' must not be null."); + } + if (value == null) { + throw new IllegalArgumentException( + "Parameter 'value' must not be null."); + } + writeInteger(key, value.length); + String prefix = key + "."; + for (int i = 0; i < value.length; i++) { + String valueKey = prefix + i; + writeRGB(valueKey, value[i]); + } + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/Palette.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/Palette.java new file mode 100644 index 00000000..af89456e --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/Palette.java @@ -0,0 +1,24 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.model; + +public enum Palette { + TRUE_COLOR, HIRES_1, HIRES_2, HIRES_MANUAL, MULTI_1, MULTI_2, MULTI_3, MULTI_4, MULTI_5, MULTI_6, MULTI_MANUAL, GTIA_GREY_1, GTIA_GREY_2, GTIA_GREY_MANUAL +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/PaletteType.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/PaletteType.java new file mode 100644 index 00000000..980826bb --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/PaletteType.java @@ -0,0 +1,25 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.model; + + +public enum PaletteType { + TRUE_COLOR, ATARI_DEFAULT, ATARI_REAL, ATARI_XFORMER, C64_NORMAL, C64_PAL, +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/PaletteUtility.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/PaletteUtility.java new file mode 100644 index 00000000..6238642c --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/PaletteUtility.java @@ -0,0 +1,156 @@ +/** +* Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.model; + +import org.eclipse.swt.graphics.RGB; + +import com.wudsn.ide.base.common.HexUtility; + +public final class PaletteUtility { + + public static final RGB BLACK = new RGB(0, 0, 0); + public static final RGB GREY1 = new RGB(85, 85, 85); + public static final RGB GREY2 = new RGB(170, 170, 170); + public static final RGB WHITE = new RGB(255, 255, 255); + + /** + * Creation is private. + */ + private PaletteUtility() { + } + + public static RGB[] getPaletteColors(PaletteType paletteType, + Palette palette, RGB[] manualPaletteColors) { + if (paletteType == null) { + throw new IllegalArgumentException( + "Parameter 'paletteType' must not be null."); + } + if (palette == null) { + throw new IllegalArgumentException( + "Parameter 'palette' must not be null."); + } + + RGB[] result; + + switch (palette) { + case TRUE_COLOR: + result = new RGB[0]; + break; + + case HIRES_1: + result = new RGB[] { BLACK, WHITE }; + break; + case HIRES_2: + result = new RGB[] { WHITE, BLACK }; + break; + + case HIRES_MANUAL: + result = getPaletteColorsCopy(manualPaletteColors, 2); + break; + + case MULTI_1: + result = new RGB[] { BLACK, GREY1, GREY2, WHITE }; + break; + case MULTI_2: + result = new RGB[] { BLACK, GREY1, WHITE, GREY2 }; + break; + case MULTI_3: + result = new RGB[] { BLACK, GREY2, GREY1, WHITE }; + break; + case MULTI_4: + result = new RGB[] { BLACK, GREY2, WHITE, GREY1 }; + break; + case MULTI_5: + result = new RGB[] { BLACK, WHITE, GREY1, GREY2 }; + break; + case MULTI_6: + result = new RGB[] { BLACK, WHITE, GREY2, GREY1 }; + break; + case MULTI_MANUAL: + result = getPaletteColorsCopy(manualPaletteColors, + manualPaletteColors.length); + break; + + case GTIA_GREY_1: + result = new RGB[16]; + for (int i = 0; i < 16; i++) { + int c = 0x11 * i; + result[i] = new RGB(c, c, c); + } + break; + case GTIA_GREY_2: + result = new RGB[16]; + for (int i = 0; i < 16; i++) { + int c = 255 - 0x11 * i; + result[i] = new RGB(c, c, c); + } + break; + case GTIA_GREY_MANUAL: + result = getPaletteColorsCopy(manualPaletteColors, 16); + break; + + default: + throw new IllegalStateException("Unknown palette '" + palette + + "'."); + } + return result; + } + + /** + * Gets an array of colors with the given size based on the current palette + * colors. + * + * @param paletteColors + * The original palette colors or null. + * @param size + * The size of the palette, a positive integer. + * @return The new array with palette colors of the given size. + * + */ + private static RGB[] getPaletteColorsCopy(RGB[] paletteColors, int size) { + + if (size < 1) { + throw new IllegalArgumentException( + "Parameter 'size' must be positive. Specified value is " + + size + "."); + } + + RGB[] result; + result = new RGB[size]; + for (int i = 0; i < size; i++) { + if (paletteColors != null && i < paletteColors.length) { + result[i] = paletteColors[i]; + } else { + result[i] = new RGB(0, 0, 0); + } + } + return result; + } + + public static String getPaletteColorText(RGB rgb) { + if (rgb == null) { + throw new IllegalArgumentException( + "Parameter 'rgb' must not be null."); + } + return HexUtility.getByteValueHexString(rgb.red) + + HexUtility.getByteValueHexString(rgb.green) + + HexUtility.getByteValueHexString(rgb.blue); + } +} diff --git a/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/RBGUtility.java b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/RBGUtility.java new file mode 100644 index 00000000..dc300180 --- /dev/null +++ b/com.wudsn.ide.gfx/src/com/wudsn/ide/gfx/model/RBGUtility.java @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2009 - 2014 Peter Dell + * + * This file is part of WUDSN IDE. + * + * WUDSN IDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * WUDSN IDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WUDSN IDE. If not, see . + */ + +package com.wudsn.ide.gfx.model; + +import org.eclipse.swt.graphics.RGB; + +public final class RBGUtility { + + /** + * Creation is private. + */ + private RBGUtility() { + } + + /** + * Combines to RBG color values to a mixed color value. + * + * @param color1 + * The first color, not null. + * @param color2 + * The second color, not null. + * @return The mixed color, not null. + */ + public static RGB combineRGB(RGB color1, RGB color2) { + return new RGB((color1.red + color2.red) >>> 1, (color1.green + color2.green) >>> 1, + (color1.blue + color2.blue) >>> 1); + } + + /** + * Combines to RBG color values to a mixed color value. + * + * @param color1 + * The first color. + * @param color2 + * The second color. + * @return The mixed color. + */ + public static int combineRGBColor(int color1, int color2) { + int r = (((color1 >>> 16) & 0xff) + ((color2 >>> 16) & 0xff)) >>> 1; + int g = (((color1 >>> 8) & 0xff) + ((color2 >>> 8) & 0xff)) >>> 1; + int b = (((color1 >>> 0) & 0xff) + ((color2 >>> 0) & 0xff)) >>> 1; + return r << 16 | g << 8 | b; + + } + +}