├── .gitignore ├── LICENSE ├── pom.xml ├── psd-analizer ├── build.xml └── src │ └── analizer │ └── PsdAnalizer.java ├── psd-image ├── .classpath ├── .project ├── .settings │ └── org.eclipse.jdt.core.prefs ├── pom.xml ├── psd-image.iml └── src │ └── psd │ ├── Layer.java │ ├── LayersContainer.java │ └── Psd.java ├── psd-parser ├── .classpath ├── .project ├── pom.xml ├── psd-parser.iml └── src │ └── psd │ ├── parser │ ├── BlendMode.java │ ├── ColorMode.java │ ├── ColorModeSectionParser.java │ ├── PsdFileParser.java │ ├── PsdInputStream.java │ ├── header │ │ ├── Header.java │ │ ├── HeaderSectionHandler.java │ │ └── HeaderSectionParser.java │ ├── imageresource │ │ ├── ImageResourceSectionHandler.java │ │ └── ImageResourceSectionParser.java │ ├── layer │ │ ├── BlendingRanges.java │ │ ├── Channel.java │ │ ├── ImagePlaneParser.java │ │ ├── LayerAdditionalInformationParser.java │ │ ├── LayerHandler.java │ │ ├── LayerParser.java │ │ ├── LayerType.java │ │ ├── LayersSectionHandler.java │ │ ├── LayersSectionParser.java │ │ ├── Mask.java │ │ └── additional │ │ │ ├── LayerEffectsHandler.java │ │ │ ├── LayerEffectsParser.java │ │ │ ├── LayerIdHandler.java │ │ │ ├── LayerIdParser.java │ │ │ ├── LayerMetaDataHandler.java │ │ │ ├── LayerMetaDataParser.java │ │ │ ├── LayerSectionDividerHandler.java │ │ │ ├── LayerSectionDividerParser.java │ │ │ ├── LayerTypeToolHandler.java │ │ │ ├── LayerTypeToolParser.java │ │ │ ├── LayerUnicodeNameHandler.java │ │ │ ├── LayerUnicodeNameParser.java │ │ │ ├── Matrix.java │ │ │ └── effects │ │ │ ├── BevelEffect.java │ │ │ ├── DropShadowEffect.java │ │ │ ├── GlowEffect.java │ │ │ ├── PSDEffect.java │ │ │ └── SolidFillEffect.java │ └── object │ │ ├── PsdBoolean.java │ │ ├── PsdDescriptor.java │ │ ├── PsdDouble.java │ │ ├── PsdEnum.java │ │ ├── PsdList.java │ │ ├── PsdLong.java │ │ ├── PsdObject.java │ │ ├── PsdObjectFactory.java │ │ ├── PsdText.java │ │ ├── PsdTextData.java │ │ └── PsdUnitFloat.java │ └── util │ └── BufferedImageBuilder.java └── psd-tool ├── .classpath ├── .project ├── pom.xml ├── psd-tool.iml └── src └── psdtool ├── MainFrame.java ├── PsdView.java ├── TreeLayerModel.java └── UiLauncher.java /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | psd-library 5 | psd-library-parent 6 | 2.0-SNAPSHOT 7 | pom 8 | 9 | psd-image 10 | psd-parser 11 | psd-tool 12 | 13 | 14 | 15 | encontra-snapshots 16 | http://nexus.inevo.pt/content/repositories/encontra-snapshots 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /psd-analizer/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /psd-analizer/src/analizer/PsdAnalizer.java: -------------------------------------------------------------------------------- 1 | package analizer; 2 | 3 | import java.io.BufferedWriter; 4 | import java.io.File; 5 | import java.io.FileWriter; 6 | import java.io.IOException; 7 | import java.util.Map; 8 | import java.util.logging.ConsoleHandler; 9 | import java.util.logging.Handler; 10 | import java.util.logging.Level; 11 | import java.util.logging.LogRecord; 12 | import java.util.logging.Logger; 13 | 14 | import javax.imageio.ImageIO; 15 | 16 | import psd.base.PsdImage; 17 | import psd.layer.PsdLayer; 18 | import psd.layer.PsdLayerType; 19 | import psd.layer.PsdTextLayerTypeTool; 20 | import psd.rawObjects.PsdTextData; 21 | 22 | public class PsdAnalizer { 23 | private static Logger logger = Logger.getLogger("app"); 24 | 25 | public static void main(String[] args) { 26 | if (args.length < 2) { 27 | System.out.println("java -jar psd-analizer.jar source.psd dest.dir"); 28 | return; 29 | } 30 | configureLogs(); 31 | 32 | long startTime = System.currentTimeMillis(); 33 | logger.info("reading: " + args[0]); 34 | 35 | try { 36 | processPsd(new File(args[0]), new File(args[1])); 37 | } catch (Exception e) { 38 | e.printStackTrace(); 39 | } 40 | 41 | long finishTime = System.currentTimeMillis(); 42 | long time = finishTime - startTime; 43 | String timeStr = "" + (time / 1000) + "." + (time % 1000); 44 | logger.info("Time: " + timeStr + " sec."); 45 | } 46 | 47 | private static void configureLogs() { 48 | Logger psdLogger = Logger.getLogger(""); 49 | psdLogger.setLevel(Level.ALL); 50 | Handler[] handlers = psdLogger.getHandlers(); 51 | for (Handler handler : handlers) { 52 | psdLogger.removeHandler(handler); 53 | } 54 | 55 | psdLogger.addHandler(new ConsoleHandler() { 56 | public void publish(LogRecord rec) { 57 | System.out.println(rec.getLevel() + ": " + rec.getMessage()); 58 | } 59 | }); 60 | } 61 | 62 | private static void processPsd(File inputFile, File outputDir) throws IOException { 63 | PsdImage psdFile = new PsdImage(inputFile); 64 | outputDir.mkdirs(); 65 | 66 | int num = 0; 67 | int total = psdFile.getLayers().size(); 68 | for (PsdLayer layer : psdFile.getLayers()) { 69 | logger.info("processing: " + layer.getName() + " - " + (num * 100 / total) + "%"); 70 | writeLayer(psdFile, layer, outputDir); 71 | num++; 72 | } 73 | } 74 | 75 | private static void writeLayer(PsdImage psd, PsdLayer layer, File baseDir) throws IOException { 76 | if (layer.getType() == PsdLayerType.NORMAL) { 77 | String path = getPath(layer); 78 | File outFile = new File(baseDir, path + ".png"); 79 | outFile.getParentFile().mkdirs(); 80 | if (layer.getImage() != null) { 81 | ImageIO.write(layer.getImage(), "png", outFile); 82 | } else { 83 | logger.warning("!!!!NULL layer: " + layer.getName()); 84 | } 85 | BufferedWriter writer = new BufferedWriter(new FileWriter(new File(baseDir, path + ".txt"))); 86 | writer.write("psd"); writer.newLine(); 87 | writer.write("width: " + psd.getWidth()); writer.newLine(); 88 | writer.write("height: " + psd.getHeight()); writer.newLine(); 89 | writer.newLine(); 90 | writer.write("layer"); writer.newLine(); 91 | writer.write("left: " + layer.getLeft()); writer.newLine(); 92 | writer.write("top: " + layer.getTop()); writer.newLine(); 93 | writer.newLine(); 94 | writer.write("right: " + (layer.getLeft() + layer.getWidth())); writer.newLine(); 95 | writer.write("bottom: " + (layer.getTop() + layer.getHeight())); writer.newLine(); 96 | writer.newLine(); 97 | writer.write("width: " + layer.getWidth()); writer.newLine(); 98 | writer.write("height: " + layer.getHeight()); writer.newLine(); 99 | 100 | if (layer.getTypeTool() != null) { 101 | writeTypeTool(writer, layer.getTypeTool()); 102 | } 103 | writer.close(); 104 | } 105 | } 106 | 107 | private static void writeTypeTool(BufferedWriter writer, PsdTextLayerTypeTool typeTool) throws IOException { 108 | writer.newLine(); 109 | writer.newLine(); 110 | writer.write("-*- text layer -*-"); 111 | writer.newLine(); 112 | 113 | writer.write("TEXT: " + typeTool.get("Txt ")); 114 | writer.newLine(); 115 | writer.write("METRICS: "); 116 | writer.newLine(); 117 | 118 | PsdTextData textData = (PsdTextData) typeTool.get("EngineData"); 119 | Map properties = textData.getProperties(); 120 | writeMap(writer, properties, 0); 121 | } 122 | 123 | private static void writeMap(BufferedWriter writer, Map map, int level) throws IOException { 124 | writeTabs(writer, level); writer.write("{"); writer.newLine(); 125 | 126 | for (String key : map.keySet()) { 127 | writeTabs(writer, level + 1); writer.write(key + ": "); 128 | Object value = map.get(key); 129 | if (value instanceof Map) { 130 | writer.newLine(); 131 | writeMap(writer, (Map) value, level + 1); 132 | } else { 133 | writer.write(String.valueOf(value)); 134 | writer.newLine(); 135 | } 136 | } 137 | writeTabs(writer, level); writer.write("}"); writer.newLine(); 138 | } 139 | 140 | private static void writeTabs(BufferedWriter writer, int tabsCount) throws IOException { 141 | while (tabsCount > 0) { 142 | writer.write("\t"); 143 | tabsCount--; 144 | } 145 | } 146 | 147 | private static String getPath(PsdLayer layer) { 148 | String dir = ""; 149 | if (layer.getParent() != null) { 150 | dir = getPath(layer.getParent()) + "/"; 151 | } 152 | return dir + layer.getName(); 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /psd-image/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /psd-image/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | psd-image 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /psd-image/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | #Sat Nov 27 14:24:01 EET 2010 2 | eclipse.preferences.version=1 3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.6 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.source=1.6 13 | -------------------------------------------------------------------------------- /psd-image/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | psd-library 5 | psd-image 6 | 2.0-SNAPSHOT 7 | jar 8 | 9 | .. 10 | psd-library 11 | psd-library-parent 12 | 2.0-SNAPSHOT 13 | 14 | 15 | src 16 | 17 | 18 | maven-compiler-plugin 19 | 20 | 1.6 21 | 1.6 22 | 23 | 24 | 25 | 26 | 27 | 28 | psd-library 29 | psd-parser 30 | 2.0-SNAPSHOT 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /psd-image/psd-image.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /psd-image/src/psd/Layer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd; 20 | 21 | import psd.parser.BlendMode; 22 | import psd.parser.layer.*; 23 | import psd.parser.layer.additional.*; 24 | import psd.parser.layer.additional.effects.PSDEffect; 25 | import psd.util.BufferedImageBuilder; 26 | 27 | import java.awt.image.*; 28 | import java.util.*; 29 | 30 | public class Layer implements LayersContainer { 31 | private int top = 0; 32 | private int left = 0; 33 | private int bottom = 0; 34 | private int right = 0; 35 | 36 | private int alpha = 255; 37 | 38 | private boolean visible = true; 39 | private boolean clippingLoaded; 40 | 41 | private String name; 42 | 43 | private BufferedImage image; 44 | private LayerType type = LayerType.NORMAL; 45 | 46 | private BlendMode layerBlendMode; 47 | private BlendingRanges layerBlendingRanges; 48 | private Mask mask; 49 | 50 | private ArrayList layers = new ArrayList(); 51 | 52 | private ArrayList layerEffects = new ArrayList(); 53 | 54 | public Layer(LayerParser parser) { 55 | parser.setHandler(new LayerHandler() { 56 | @Override 57 | public void boundsLoaded(int left, int top, int right, int bottom) { 58 | Layer.this.left = left; 59 | Layer.this.top = top; 60 | Layer.this.right = right; 61 | Layer.this.bottom = bottom; 62 | } 63 | 64 | @Override 65 | public void blendModeLoaded(BlendMode blendMode) { 66 | Layer.this.setLayerBlendMode(blendMode); 67 | } 68 | 69 | @Override 70 | public void blendingRangesLoaded(BlendingRanges ranges) { 71 | Layer.this.setLayerBlendingRanges(ranges); 72 | } 73 | 74 | @Override 75 | public void opacityLoaded(int opacity) { 76 | Layer.this.alpha = opacity; 77 | } 78 | 79 | @Override 80 | public void clippingLoaded(boolean clipping) { 81 | Layer.this.setClippingLoaded(clipping); 82 | } 83 | 84 | @Override 85 | public void flagsLoaded(boolean transparencyProtected, boolean visible, boolean obsolete, boolean isPixelDataIrrelevantValueUseful, boolean pixelDataIrrelevant) { 86 | Layer.this.visible = visible; 87 | } 88 | 89 | @Override 90 | public void nameLoaded(String name) { 91 | Layer.this.name = name; 92 | } 93 | 94 | @Override 95 | public void channelsLoaded(List channels) { 96 | BufferedImageBuilder imageBuilder = new BufferedImageBuilder(channels, getWidth(), getHeight()); 97 | image = imageBuilder.makeImage(); 98 | } 99 | 100 | @Override 101 | public void maskLoaded(Mask mask) { 102 | Layer.this.setMask(mask); 103 | } 104 | 105 | }); 106 | 107 | parser.putAdditionalInformationParser(LayerSectionDividerParser.TAG, new LayerSectionDividerParser(new LayerSectionDividerHandler() { 108 | @Override 109 | public void sectionDividerParsed(LayerType type) { 110 | Layer.this.type = type; 111 | } 112 | })); 113 | 114 | parser.putAdditionalInformationParser(LayerEffectsParser.TAG, new LayerEffectsParser(new LayerEffectsHandler() { 115 | @Override 116 | public void handleEffects(List effects) { 117 | layerEffects.addAll(effects); 118 | } 119 | })); 120 | 121 | parser.putAdditionalInformationParser(LayerUnicodeNameParser.TAG, new LayerUnicodeNameParser(new LayerUnicodeNameHandler() { 122 | @Override 123 | public void layerUnicodeNameParsed(String unicodeName) { 124 | name = unicodeName; 125 | } 126 | })); 127 | } 128 | 129 | public void addLayer(Layer layer) { 130 | layers.add(layer); 131 | } 132 | 133 | @Override 134 | public Layer getLayer(int index) { 135 | return layers.get(index); 136 | } 137 | 138 | @Override 139 | public int indexOfLayer(Layer layer) { 140 | return layers.indexOf(layer); 141 | } 142 | 143 | @Override 144 | public int getLayersCount() { 145 | return layers.size(); 146 | } 147 | 148 | public BufferedImage getImage() { 149 | return image; 150 | } 151 | 152 | public List getEffectsList() { 153 | return layerEffects; 154 | } 155 | 156 | public int getX() { 157 | return left; 158 | } 159 | 160 | public int getY() { 161 | return top; 162 | } 163 | 164 | public int getWidth() { 165 | return right - left; 166 | } 167 | 168 | public int getHeight() { 169 | return bottom - top; 170 | } 171 | 172 | public LayerType getType() { 173 | return type; 174 | } 175 | 176 | public boolean isVisible() { 177 | return visible; 178 | } 179 | 180 | @Override 181 | public String toString() { 182 | return name; 183 | } 184 | 185 | public int getAlpha() { 186 | return alpha; 187 | } 188 | 189 | public boolean isClippingLoaded() { 190 | return clippingLoaded; 191 | } 192 | 193 | public void setClippingLoaded(boolean clippingLoaded) { 194 | this.clippingLoaded = clippingLoaded; 195 | } 196 | 197 | public BlendMode getLayerBlendMode() { 198 | return layerBlendMode; 199 | } 200 | 201 | public void setLayerBlendMode(BlendMode layerBlendMode) { 202 | this.layerBlendMode = layerBlendMode; 203 | } 204 | 205 | public BlendingRanges getLayerBlendingRanges() { 206 | return layerBlendingRanges; 207 | } 208 | 209 | public void setLayerBlendingRanges(BlendingRanges layerBlendingRanges) { 210 | this.layerBlendingRanges = layerBlendingRanges; 211 | } 212 | 213 | public Mask getMask() { 214 | return mask; 215 | } 216 | 217 | public void setMask(Mask mask) { 218 | this.mask = mask; 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /psd-image/src/psd/LayersContainer.java: -------------------------------------------------------------------------------- 1 | package psd; 2 | 3 | public interface LayersContainer { 4 | public Layer getLayer(int index); 5 | public int indexOfLayer(Layer layer); 6 | public int getLayersCount(); 7 | } 8 | -------------------------------------------------------------------------------- /psd-image/src/psd/Psd.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd; 20 | 21 | import java.io.*; 22 | import java.util.*; 23 | 24 | import psd.parser.*; 25 | import psd.parser.header.*; 26 | import psd.parser.layer.*; 27 | 28 | public class Psd implements LayersContainer { 29 | private Header header; 30 | private List layers = new ArrayList(); 31 | private Layer baseLayer; 32 | private String name; 33 | 34 | public Psd(InputStream stream) throws IOException { 35 | name = "unknown name"; 36 | 37 | PsdFileParser parser = new PsdFileParser(); 38 | parser.getHeaderSectionParser().setHandler(new HeaderSectionHandler() { 39 | @Override 40 | public void headerLoaded(Header header) { 41 | Psd.this.header = header; 42 | } 43 | }); 44 | 45 | final List fullLayersList = new ArrayList(); 46 | parser.getLayersSectionParser().setHandler(new LayersSectionHandler() { 47 | @Override 48 | public void createLayer(LayerParser parser) { 49 | fullLayersList.add(new Layer(parser)); 50 | } 51 | 52 | @Override 53 | public void createBaseLayer(LayerParser parser) { 54 | baseLayer = new Layer(parser); 55 | if (fullLayersList.isEmpty()) { 56 | fullLayersList.add(baseLayer); 57 | } 58 | } 59 | }); 60 | 61 | parser.parse(stream); 62 | 63 | layers = makeLayersHierarchy(fullLayersList); 64 | } 65 | 66 | public Psd(File psdFile) throws IOException { 67 | name = psdFile.getName(); 68 | 69 | PsdFileParser parser = new PsdFileParser(); 70 | parser.getHeaderSectionParser().setHandler(new HeaderSectionHandler() { 71 | @Override 72 | public void headerLoaded(Header header) { 73 | Psd.this.header = header; 74 | } 75 | }); 76 | 77 | final List fullLayersList = new ArrayList(); 78 | parser.getLayersSectionParser().setHandler(new LayersSectionHandler() { 79 | @Override 80 | public void createLayer(LayerParser parser) { 81 | fullLayersList.add(new Layer(parser)); 82 | } 83 | 84 | @Override 85 | public void createBaseLayer(LayerParser parser) { 86 | baseLayer = new Layer(parser); 87 | if (fullLayersList.isEmpty()) { 88 | fullLayersList.add(baseLayer); 89 | } 90 | } 91 | }); 92 | 93 | BufferedInputStream stream = new BufferedInputStream(new FileInputStream(psdFile)); 94 | parser.parse(stream); 95 | stream.close(); 96 | 97 | layers = makeLayersHierarchy(fullLayersList); 98 | } 99 | 100 | private List makeLayersHierarchy(List layers) { 101 | LinkedList> layersStack = new LinkedList>(); 102 | ArrayList rootLayers = new ArrayList(); 103 | for (Layer layer : layers) { 104 | switch (layer.getType()) { 105 | case HIDDEN: { 106 | layersStack.addFirst(new LinkedList()); 107 | break; 108 | } 109 | case FOLDER: { 110 | assert !layersStack.isEmpty(); 111 | LinkedList folderLayers = layersStack.removeFirst(); 112 | for (Layer l : folderLayers) { 113 | layer.addLayer(l); 114 | } 115 | } 116 | // break isn't needed 117 | case NORMAL: { 118 | if (layersStack.isEmpty()) { 119 | rootLayers.add(layer); 120 | } else { 121 | layersStack.getFirst().add(layer); 122 | } 123 | break; 124 | } 125 | default: 126 | assert false; 127 | } 128 | } 129 | return rootLayers; 130 | } 131 | 132 | public int getWidth() { 133 | return header.getWidth(); 134 | } 135 | 136 | public int getHeight() { 137 | return header.getHeight(); 138 | } 139 | 140 | public int getChannelsCount() { 141 | return header.getChannelsCount(); 142 | } 143 | 144 | public int getDepth(){ 145 | return header.getDepth(); 146 | } 147 | 148 | public ColorMode getColorMode() { 149 | return header.getColorMode(); 150 | } 151 | 152 | @Override 153 | public Layer getLayer(int index) { 154 | return layers.get(index); 155 | } 156 | 157 | @Override 158 | public int indexOfLayer(Layer layer) { 159 | return layers.indexOf(layer); 160 | } 161 | 162 | @Override 163 | public int getLayersCount() { 164 | return layers.size(); 165 | } 166 | 167 | @Override 168 | public String toString() { 169 | return name; 170 | } 171 | 172 | public Layer getBaseLayer() { 173 | return this.baseLayer; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /psd-parser/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /psd-parser/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | psd-parser 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /psd-parser/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | psd-library 5 | psd-parser 6 | 2.0-SNAPSHOT 7 | jar 8 | 9 | .. 10 | psd-library 11 | psd-library-parent 12 | 2.0-SNAPSHOT 13 | 14 | 15 | src 16 | 17 | 18 | maven-compiler-plugin 19 | 20 | 1.6 21 | 1.6 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /psd-parser/psd-parser.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/BlendMode.java: -------------------------------------------------------------------------------- 1 | package psd.parser; 2 | 3 | public enum BlendMode { 4 | NORMAL("norm"), 5 | DISSOLVE("diss"), 6 | DARKEN("dark"), 7 | MULTIPLY("mul "), 8 | COLOR_BURN("idiv"), 9 | LINEAR_BURN("lbrn"), 10 | LIGHTEN("lite"), 11 | SCREEN("scrn"), 12 | COLOR_DODGE("div "), 13 | LINEAR_DODGE("lddg"), 14 | OVERLAY("over"), 15 | SOFT_LIGHT("sLit"), 16 | HARD_LIGHT("hLit"), 17 | VIVID_LIGHT("vLit"), 18 | LINEAR_LIGHT("lLit"), 19 | PIN_LIGHT("pLit"), 20 | HARD_MIX("hMix"), 21 | DIFFERENCE("diff"), 22 | EXCLUSION("smud"), 23 | HUE("hue "), 24 | SATURATION("sat "), 25 | COLOR("colr"), 26 | LUMINOSITY("lum "), 27 | PASS_THROUGH("pass"); 28 | 29 | private String name; 30 | 31 | private BlendMode(String name) { 32 | this.name = name; 33 | } 34 | 35 | public static BlendMode getByName(String name) { 36 | for (BlendMode mode : values()) { 37 | if (mode.name.equals(name)) { 38 | return mode; 39 | } 40 | } 41 | return null; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/ColorMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser; 20 | 21 | public enum ColorMode { 22 | BITMAP, // 0 23 | GRAYSCALE, // 1 24 | INDEXED, // 2 25 | RGB, // 3 26 | CMYK, // 4 27 | UNKNOWN_5, // 5, 28 | UNKNOWN_6, // 6 29 | MULTICHANNEL, // 7 30 | DUOTONE, // 8 31 | LAB, // 9 32 | } 33 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/ColorModeSectionParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser; 2 | 3 | import java.io.IOException; 4 | 5 | public class ColorModeSectionParser { 6 | 7 | public void parse(PsdInputStream stream) throws IOException { 8 | int colorMapLength = stream.readInt(); 9 | stream.skipBytes(colorMapLength); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/PsdFileParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser; 2 | 3 | import java.io.*; 4 | 5 | import psd.parser.header.HeaderSectionParser; 6 | import psd.parser.imageresource.ImageResourceSectionParser; 7 | import psd.parser.layer.LayersSectionParser; 8 | 9 | public class PsdFileParser { 10 | private HeaderSectionParser headerParser; 11 | private ColorModeSectionParser colorModeSectionParser; 12 | private ImageResourceSectionParser imageResourceSectionParser; 13 | private LayersSectionParser layersSectionParser; 14 | 15 | public PsdFileParser() { 16 | headerParser = new HeaderSectionParser(); 17 | colorModeSectionParser = new ColorModeSectionParser(); 18 | imageResourceSectionParser = new ImageResourceSectionParser(); 19 | layersSectionParser = new LayersSectionParser(headerParser.getHeader()); 20 | } 21 | 22 | public HeaderSectionParser getHeaderSectionParser() { 23 | return headerParser; 24 | } 25 | 26 | public ImageResourceSectionParser getImageResourceSectionParser() { 27 | return imageResourceSectionParser; 28 | } 29 | 30 | public LayersSectionParser getLayersSectionParser() { 31 | return layersSectionParser; 32 | } 33 | 34 | public void parse(InputStream inputStream) throws IOException { 35 | PsdInputStream stream = new PsdInputStream(inputStream); 36 | headerParser.parse(stream); 37 | colorModeSectionParser.parse(stream); 38 | imageResourceSectionParser.parse(stream); 39 | layersSectionParser.parse(stream); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/PsdInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser; 20 | 21 | import java.io.DataInputStream; 22 | import java.io.EOFException; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | 26 | public class PsdInputStream extends InputStream { 27 | 28 | private int pos; 29 | private int markPos; 30 | private final DataInputStream in; 31 | 32 | public PsdInputStream(InputStream in) { 33 | this.in = new DataInputStream(in); 34 | pos = 0; 35 | markPos = 0; 36 | } 37 | 38 | @Override 39 | public int available() throws IOException { 40 | return in.available(); 41 | } 42 | 43 | @Override 44 | public void close() throws IOException { 45 | in.close(); 46 | } 47 | 48 | @Override 49 | public synchronized void mark(int readlimit) { 50 | in.mark(readlimit); 51 | markPos = pos; 52 | } 53 | 54 | @Override 55 | public synchronized void reset() throws IOException { 56 | in.reset(); 57 | pos = markPos; 58 | } 59 | 60 | @Override 61 | public boolean markSupported() { 62 | return in.markSupported(); 63 | } 64 | 65 | @Override 66 | public int read(byte[] b, int off, int len) throws IOException { 67 | int res = in.read(b, off, len); 68 | if (res != -1) { 69 | pos += res; 70 | } 71 | return res; 72 | } 73 | 74 | @Override 75 | public int read(byte[] b) throws IOException { 76 | int res = in.read(b); 77 | if (res != -1) { 78 | pos += res; 79 | } 80 | return res; 81 | } 82 | 83 | @Override 84 | public int read() throws IOException { 85 | int res = in.read(); 86 | if (res != -1) { 87 | pos++; 88 | } 89 | return res; 90 | } 91 | 92 | @Override 93 | public long skip(long n) throws IOException { 94 | long skip = in.skip(n); 95 | pos += skip; 96 | return skip; 97 | } 98 | 99 | public String readString(int len) throws IOException { 100 | // read string of specified length 101 | byte[] bytes = new byte[len]; 102 | read(bytes); 103 | return new String(bytes, "ISO-8859-1"); 104 | } 105 | 106 | public String readPsdString() throws IOException { 107 | int size = readInt(); 108 | if (size == 0) { 109 | size = 4; 110 | } 111 | return readString(size); 112 | } 113 | 114 | public int readBytes(byte[] bytes, int n) throws IOException { 115 | // read multiple bytes from input 116 | if (bytes == null) 117 | return 0; 118 | int r = 0; 119 | r = read(bytes, 0, n); 120 | if (r < n) { 121 | throw new IOException("format error. readed=" + r + " needed=" + n); 122 | } 123 | return r; 124 | } 125 | 126 | public byte readByte() throws IOException { 127 | int ch = read(); 128 | if (ch < 0) { 129 | throw new EOFException(); 130 | } 131 | return (byte) (ch); 132 | } 133 | 134 | public int readUnsignedByte() throws IOException { 135 | int res = in.readUnsignedByte(); 136 | if (res != -1) { 137 | pos++; 138 | } 139 | return res; 140 | } 141 | 142 | public short readShort() throws IOException { 143 | int ch1 = read(); 144 | int ch2 = read(); 145 | if ((ch1 | ch2) < 0) { 146 | throw new EOFException(); 147 | } 148 | return (short) ((ch1 << 8) + (ch2 << 0)); 149 | } 150 | 151 | public int readInt() throws IOException { 152 | int ch1 = read(); 153 | int ch2 = read(); 154 | int ch3 = read(); 155 | int ch4 = read(); 156 | if ((ch1 | ch2 | ch3 | ch4) < 0) { 157 | throw new EOFException(); 158 | } 159 | return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); 160 | } 161 | 162 | public boolean readBoolean() throws IOException { 163 | int ch = read(); 164 | if (ch < 0) { 165 | throw new EOFException(); 166 | } 167 | return (ch != 0); 168 | } 169 | 170 | public final long readLong() throws IOException { 171 | int c1 = read(); 172 | int c2 = read(); 173 | int c3 = read(); 174 | int c4 = read(); 175 | int c5 = read(); 176 | int c6 = read(); 177 | int c7 = read(); 178 | int c8 = read(); 179 | return (((long) c1 << 56) + ((long) (c2 & 255) << 48) 180 | + ((long) (c3 & 255) << 40) + ((long) (c4 & 255) << 32) 181 | + ((long) (c5 & 255) << 24) + ((c6 & 255) << 16) 182 | + ((c7 & 255) << 8) + (c8 & 255)); 183 | } 184 | 185 | public final double readDouble() throws IOException { 186 | return Double.longBitsToDouble(readLong()); 187 | } 188 | 189 | public int skipBytes(int n) throws IOException { 190 | int total = 0; 191 | int cur; 192 | while ((total < n) && ((cur = (int) skip(n - total)) > 0)) { 193 | total += cur; 194 | } 195 | return total; 196 | } 197 | 198 | public int getPos() { 199 | return pos; 200 | } 201 | 202 | } 203 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/header/Header.java: -------------------------------------------------------------------------------- 1 | package psd.parser.header; 2 | 3 | import psd.parser.ColorMode; 4 | 5 | public class Header { 6 | int channelsCount; 7 | int width; 8 | int height; 9 | int depth; 10 | ColorMode colorMode; 11 | 12 | public int getChannelsCount() { 13 | return channelsCount; 14 | } 15 | 16 | public int getWidth() { 17 | return width; 18 | } 19 | 20 | public int getHeight() { 21 | return height; 22 | } 23 | 24 | public int getDepth() { 25 | return depth; 26 | } 27 | 28 | public ColorMode getColorMode() { 29 | return colorMode; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/header/HeaderSectionHandler.java: -------------------------------------------------------------------------------- 1 | package psd.parser.header; 2 | 3 | public interface HeaderSectionHandler { 4 | public void headerLoaded(Header header); 5 | } 6 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/header/HeaderSectionParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser.header; 2 | 3 | import java.io.IOException; 4 | 5 | import psd.parser.ColorMode; 6 | import psd.parser.PsdInputStream; 7 | 8 | public class HeaderSectionParser { 9 | 10 | private static final String FILE_SIGNATURE = "8BPS"; 11 | private static final int FILE_VERSION = 1; 12 | 13 | private HeaderSectionHandler handler; 14 | private Header header = new Header(); 15 | 16 | public void setHandler(HeaderSectionHandler handler) { 17 | this.handler = handler; 18 | } 19 | 20 | public void parse(PsdInputStream psdStream) throws IOException { 21 | String fileSignature = psdStream.readString(4); 22 | if (!fileSignature.equals(FILE_SIGNATURE)) { 23 | throw new IOException("file signature error"); 24 | } 25 | 26 | int ver = psdStream.readShort(); 27 | if (ver != FILE_VERSION) { 28 | throw new IOException("file version error "); 29 | } 30 | 31 | psdStream.skipBytes(6); // reserved 32 | 33 | header.channelsCount = psdStream.readShort(); 34 | header.height = psdStream.readInt(); 35 | header.width = psdStream.readInt(); 36 | header.depth = psdStream.readShort(); 37 | int colorModeIndex = psdStream.readShort(); 38 | header.colorMode = ColorMode.values()[colorModeIndex]; 39 | if (handler != null) { 40 | handler.headerLoaded(header); 41 | } 42 | } 43 | 44 | public Header getHeader() { 45 | return header; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/imageresource/ImageResourceSectionHandler.java: -------------------------------------------------------------------------------- 1 | package psd.parser.imageresource; 2 | 3 | import psd.parser.object.PsdDescriptor; 4 | 5 | 6 | public interface ImageResourceSectionHandler { 7 | public void imageResourceManiSectionParsed(PsdDescriptor descriptor); 8 | } 9 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/imageresource/ImageResourceSectionParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser.imageresource; 2 | 3 | import java.io.IOException; 4 | 5 | import psd.parser.PsdInputStream; 6 | import psd.parser.object.PsdDescriptor; 7 | 8 | public class ImageResourceSectionParser { 9 | private static final String PSD_TAG = "8BIM"; 10 | private ImageResourceSectionHandler handler; 11 | 12 | public void setHandler(ImageResourceSectionHandler handler) { 13 | this.handler = handler; 14 | } 15 | 16 | public void parse(PsdInputStream stream) throws IOException { 17 | int length = stream.readInt(); 18 | int pos = stream.getPos(); 19 | while (length > 0) { 20 | String tag = stream.readString(4); 21 | if (!tag.equals(PSD_TAG) && !tag.equals("MeSa")) { 22 | throw new IOException("Format error: Invalid image resources section.: " + tag); 23 | } 24 | length -= 4; 25 | int id = stream.readShort(); 26 | length -= 2; 27 | 28 | int sizeOfName = stream.readByte() & 0xFF; 29 | if ((sizeOfName & 0x01) == 0) 30 | sizeOfName++; 31 | @SuppressWarnings("unused") 32 | String name = stream.readString(sizeOfName); 33 | length -= sizeOfName + 1; 34 | 35 | int sizeOfData = stream.readInt(); 36 | length -= 4; 37 | if ((sizeOfData & 0x01) == 1) 38 | sizeOfData++; 39 | length -= sizeOfData; 40 | int storePos = stream.getPos(); 41 | 42 | // TODO FIXME Is id correct? 43 | if (sizeOfData > 0 && tag.equals(PSD_TAG) && id >= 4000 && id < 5000) { 44 | String key = stream.readString(4); 45 | if (key.equals("mani")) { 46 | stream.skipBytes(12 + 12); // unknown data 47 | PsdDescriptor descriptor = new PsdDescriptor(stream); 48 | if (handler != null) { 49 | handler.imageResourceManiSectionParsed(descriptor); 50 | } 51 | } 52 | } 53 | stream.skipBytes(sizeOfData - (stream.getPos() - storePos)); 54 | } 55 | stream.skipBytes(length - (stream.getPos() - pos)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/BlendingRanges.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer; 2 | 3 | public class BlendingRanges { 4 | int grayBlackSrc; // Composite gray blend source. Contains 2 black values followed by 2 white values. Present but irrelevant for Lab & Grayscale. 5 | int grayWhiteSrc; 6 | int grayBlackDst; // Composite gray blend destination range 7 | int grayWhiteDst; 8 | int numberOfBlendingChannels; 9 | int[] channelBlackSrc;// channel source range 10 | int[] channelWhiteSrc; 11 | int[] channelBlackDst;// First channel destination range 12 | int[] channelWhiteDst; 13 | } 14 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/Channel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.layer; 20 | 21 | import java.io.IOException; 22 | 23 | import psd.parser.PsdInputStream; 24 | 25 | public class Channel { 26 | public static final int ALPHA = -1; 27 | public static final int RED = 0; 28 | public static final int GREEN = 1; 29 | public static final int BLUE = 2; 30 | 31 | private int id; 32 | private int dataLength; 33 | private byte[] data; 34 | 35 | public Channel(PsdInputStream stream) throws IOException { 36 | id = stream.readShort(); 37 | dataLength = stream.readInt(); 38 | } 39 | 40 | public Channel(int id) { 41 | this.id = id; 42 | } 43 | 44 | public int getId() { 45 | return id; 46 | } 47 | 48 | public int getDataLength() { 49 | return dataLength; 50 | } 51 | 52 | public void setData(byte[] data) { 53 | this.data = data; 54 | } 55 | 56 | public byte[] getData() { 57 | return data; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/ImagePlaneParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer; 2 | 3 | import java.io.IOException; 4 | 5 | import psd.parser.PsdInputStream; 6 | 7 | public class ImagePlaneParser { 8 | 9 | private final PsdInputStream stream; 10 | 11 | public ImagePlaneParser(PsdInputStream stream) { 12 | this.stream = stream; 13 | } 14 | 15 | public byte[] readPlane(int w, int h) throws IOException { 16 | int compression = stream.readShort(); 17 | switch (compression) { 18 | case 0: 19 | return readPlaneUncompressed(w, h); 20 | case 1: 21 | return parsePlaneRleCompressed(w, h, readLineLengths(h), 0); 22 | default: 23 | throw new IOException("invalid compression: " + compression); 24 | } 25 | } 26 | 27 | private short[] readLineLengths(int h) throws IOException { 28 | short[] lineLengths = new short[h]; 29 | for (int i = 0; i < h; i++) { 30 | lineLengths[i] = stream.readShort(); 31 | } 32 | return lineLengths; 33 | } 34 | 35 | public byte[] readPlane(int w, int h, short[] lineLengths, int planeNum) throws IOException { 36 | boolean rleEncoded = lineLengths != null; 37 | 38 | if (rleEncoded) { 39 | return parsePlaneRleCompressed(w, h, lineLengths, planeNum); 40 | } else { 41 | return readPlaneUncompressed(w, h); 42 | } 43 | } 44 | 45 | private byte[] parsePlaneRleCompressed(int w, int h, short[] lineLengths, int planeNum) throws IOException { 46 | 47 | byte[] b = new byte[w * h]; 48 | byte[] s = new byte[w * 2]; 49 | int pos = 0; 50 | int lineIndex = planeNum * h; 51 | for (int i = 0; i < h; i++) { 52 | int len = lineLengths[lineIndex++]; 53 | stream.readBytes(s, len); 54 | decodeRLE(s, 0, len, b, pos); 55 | pos += w; 56 | } 57 | return b; 58 | } 59 | 60 | private void decodeRLE(byte[] src, int srcIndex, int slen, byte[] dst, int dstIndex) throws IOException { 61 | int sIndex = srcIndex; 62 | int dIndex = dstIndex; 63 | try { 64 | int max = sIndex + slen; 65 | while (sIndex < max) { 66 | byte b = src[sIndex++]; 67 | int n = (int) b; 68 | if (n < 0) { 69 | n = 1 - n; 70 | b = src[sIndex++]; 71 | for (int i = 0; i < n; i++) { 72 | dst[dIndex++] = b; 73 | } 74 | } else { 75 | n = n + 1; 76 | System.arraycopy(src, sIndex, dst, dIndex, n); 77 | dIndex += n; 78 | sIndex += n; 79 | } 80 | } 81 | } catch (Exception e) { 82 | throw new IOException("format error " + e); 83 | } 84 | } 85 | 86 | private byte[] readPlaneUncompressed(int w, int h) throws IOException { 87 | int size = w * h; 88 | byte[] b = new byte[size]; 89 | stream.readBytes(b, size); 90 | return b; 91 | } 92 | 93 | 94 | } 95 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/LayerAdditionalInformationParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer; 2 | 3 | import java.io.IOException; 4 | 5 | import psd.parser.PsdInputStream; 6 | 7 | public interface LayerAdditionalInformationParser { 8 | public void parse(PsdInputStream stream, String tag, int size) throws IOException; 9 | } 10 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/LayerHandler.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer; 2 | 3 | import psd.parser.BlendMode; 4 | 5 | import java.util.List; 6 | 7 | public interface LayerHandler { 8 | public void boundsLoaded(int left, int top, int right, int bottom); 9 | 10 | public void blendModeLoaded(BlendMode blendMode); 11 | 12 | public void opacityLoaded(int opacity); 13 | 14 | public void clippingLoaded(boolean clipping); 15 | 16 | public void flagsLoaded(boolean transparencyProtected, boolean visible, boolean obsolete, boolean isPixelDataIrrelevantValueUseful, boolean pixelDataIrrelevant); 17 | 18 | public void nameLoaded(String name); 19 | 20 | public void channelsLoaded(List channels); 21 | 22 | public void maskLoaded(Mask mask); 23 | 24 | public void blendingRangesLoaded(BlendingRanges ranges); 25 | } 26 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/LayerParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer; 2 | 3 | import java.io.IOException; 4 | import java.util.*; 5 | 6 | import psd.parser.BlendMode; 7 | import psd.parser.PsdInputStream; 8 | 9 | public class LayerParser { 10 | 11 | private List channels; 12 | private LayerHandler handler; 13 | private Map additionalInformationParsers; 14 | private LayerAdditionalInformationParser defaultAdditionalInformationParser; 15 | private int width = -1; 16 | private int height = -1; 17 | 18 | public LayerParser() { 19 | handler = null; 20 | additionalInformationParsers = new HashMap(); 21 | defaultAdditionalInformationParser = null; 22 | } 23 | 24 | public void putAdditionalInformationParser(String tag, LayerAdditionalInformationParser parser) { 25 | additionalInformationParsers.put(tag, parser); 26 | } 27 | 28 | public void setDefaultAdditionalInformationParser(LayerAdditionalInformationParser parser) { 29 | defaultAdditionalInformationParser = parser; 30 | } 31 | 32 | public void setHandler(LayerHandler handler) { 33 | this.handler = handler; 34 | } 35 | 36 | public void parse(PsdInputStream stream) throws IOException { 37 | parseBounds(stream); 38 | parseChannelsInfo(stream); 39 | 40 | String tag = stream.readString(4); 41 | if (!tag.equals("8BIM")) { 42 | throw new IOException("format error"); 43 | } 44 | parseBlendMode(stream); 45 | parseOpacity(stream); 46 | parseClipping(stream); 47 | parseFlags(stream); 48 | int filler = stream.readByte(); // filler. must be zero 49 | assert filler == 0; 50 | parseExtraData(stream); 51 | } 52 | 53 | public void fireBoundsChanged(int left, int top, int right, int bottom) { 54 | if (handler != null) { 55 | handler.boundsLoaded(left, top, right, bottom); 56 | } 57 | } 58 | 59 | public void fireChannelsLoaded(List channels) { 60 | if (handler != null) { 61 | handler.channelsLoaded(channels); 62 | } 63 | } 64 | 65 | private void parseBounds(PsdInputStream stream) throws IOException { 66 | int top = stream.readInt(); 67 | int left = stream.readInt(); 68 | int bottom = stream.readInt(); 69 | int right = stream.readInt(); 70 | width = right - left; 71 | height = bottom - top; 72 | if (handler != null) { 73 | handler.boundsLoaded(left, top, right, bottom); 74 | } 75 | } 76 | 77 | private void parseChannelsInfo(PsdInputStream stream) throws IOException { 78 | int channelsCount = stream.readShort(); 79 | channels = new ArrayList(); 80 | for (int j = 0; j < channelsCount; j++) { 81 | channels.add(new Channel(stream)); 82 | } 83 | } 84 | 85 | private void parseBlendMode(PsdInputStream stream) throws IOException { 86 | String blendMode = stream.readString(4); 87 | if (handler != null) { 88 | handler.blendModeLoaded(BlendMode.getByName(blendMode)); 89 | } 90 | } 91 | 92 | private void parseOpacity(PsdInputStream stream) throws IOException { 93 | int opacity = stream.readByte() & 0xff; 94 | if (handler != null) { 95 | handler.opacityLoaded(opacity); 96 | } 97 | } 98 | 99 | private void parseClipping(PsdInputStream stream) throws IOException { 100 | boolean clipping = stream.readBoolean(); 101 | if (handler != null) { 102 | handler.clippingLoaded(clipping); 103 | } 104 | } 105 | 106 | private void parseFlags(PsdInputStream stream) throws IOException { 107 | int flags = stream.readByte(); 108 | boolean transparencyProtected = (flags & 0x01) != 0; 109 | boolean visible = ((flags >> 1) & 0x01) == 0; 110 | boolean obsolete = ((flags >> 2) & 0x01) != 0; 111 | boolean isPixelDataIrrelevantValueUseful = ((flags >> 3) & 0x01) != 0; 112 | boolean pixelDataIrrelevant = false; 113 | if (isPixelDataIrrelevantValueUseful) { // tells if bit 4 has useful information 114 | pixelDataIrrelevant = ((flags >> 4) & 0x01) != 0; 115 | } 116 | 117 | if (handler != null) { 118 | handler.flagsLoaded(transparencyProtected, visible, obsolete, 119 | isPixelDataIrrelevantValueUseful, pixelDataIrrelevant); 120 | } 121 | } 122 | 123 | private void parseExtraData(PsdInputStream stream) throws IOException { 124 | int extraSize = stream.readInt(); 125 | int extraPos = stream.getPos(); 126 | 127 | parseMaskAndAdjustmentData(stream); 128 | parseBlendingRangesData(stream); 129 | parseName(stream); 130 | parseAdditionalSections(stream, extraSize + extraPos); 131 | 132 | stream.skipBytes(extraSize - (stream.getPos() - extraPos)); 133 | } 134 | 135 | private void parseMaskAndAdjustmentData(PsdInputStream stream) throws IOException { 136 | int size = stream.readInt(); 137 | assert size == 0 || size == 20 || size == 36; 138 | if (size > 0) { 139 | Mask mask = new Mask(); 140 | mask.top = stream.readInt(); 141 | mask.left = stream.readInt(); 142 | mask.bottom = stream.readInt(); 143 | mask.right = stream.readInt(); 144 | mask.defaultColor = stream.readByte() & 0xff; 145 | assert mask.defaultColor == 0 || mask.defaultColor == 255; 146 | 147 | byte flags = stream.readByte(); 148 | mask.relative = (flags & 0x01) != 0; 149 | mask.disabled = ((flags >> 1) & 0x01) != 0; 150 | mask.invert = ((flags >> 2) & 0x01) != 0; 151 | if (size == 20) { 152 | stream.skipBytes(2); 153 | } else { 154 | byte realFlags = stream.readByte(); 155 | mask.relative = (realFlags & 0x01) != 0; 156 | mask.disabled = ((realFlags >> 1) & 0x01) != 0; 157 | mask.invert = ((realFlags >> 2) & 0x01) != 0; 158 | 159 | mask.defaultColor = stream.readByte() & 0xff; 160 | assert mask.defaultColor == 0 || mask.defaultColor == 255; 161 | 162 | mask.top = stream.readInt(); 163 | mask.left = stream.readInt(); 164 | mask.bottom = stream.readInt(); 165 | mask.right = stream.readInt(); 166 | } 167 | if (handler != null) { 168 | handler.maskLoaded(mask); 169 | } 170 | } 171 | } 172 | 173 | private void parseBlendingRangesData(PsdInputStream stream) throws IOException { 174 | int size = stream.readInt(); 175 | int pos = stream.getPos(); 176 | BlendingRanges ranges = new BlendingRanges(); 177 | 178 | // Composite gray blend source. Contains 2 black values followed by 2 179 | // white values. Present but irrelevant for Lab & Grayscale. 180 | ranges.grayBlackSrc = stream.readShort() & 0xffff; 181 | ranges.grayWhiteSrc = stream.readShort() & 0xffff; 182 | 183 | // Composite gray blend destination range 184 | ranges.grayBlackDst = stream.readShort() & 0xffff; 185 | ranges.grayWhiteDst = stream.readShort() & 0xffff; 186 | 187 | ranges.numberOfBlendingChannels = (size - 8) / 8; 188 | if (ranges.numberOfBlendingChannels > 0) { 189 | ranges.channelBlackSrc = new int[ranges.numberOfBlendingChannels]; 190 | ranges.channelWhiteSrc = new int[ranges.numberOfBlendingChannels]; 191 | ranges.channelBlackDst = new int[ranges.numberOfBlendingChannels]; 192 | ranges.channelWhiteDst = new int[ranges.numberOfBlendingChannels]; 193 | 194 | for (int i = 0; i < ranges.numberOfBlendingChannels; i++) { 195 | // channel source range 196 | ranges.channelBlackSrc[i] = stream.readShort() & 0xffff; 197 | ranges.channelWhiteSrc[i] = stream.readShort() & 0xffff; 198 | 199 | // channel destination range 200 | ranges.channelBlackDst[i] = stream.readShort() & 0xffff; 201 | ranges.channelWhiteDst[i] = stream.readShort() & 0xffff; 202 | } 203 | 204 | if (handler != null) { 205 | handler.blendingRangesLoaded(ranges); 206 | } 207 | } else { 208 | // invalid blending channels 209 | stream.skipBytes(size - (stream.getPos() - pos)); 210 | } 211 | } 212 | 213 | private void parseName(PsdInputStream stream) throws IOException { 214 | // Layer name: Pascal string, padded to a multiple of 4 bytes. 215 | int size = stream.readByte() & 0xFF; 216 | size = ((size + 1 + 3) & ~0x03) - 1; 217 | byte[] str = new byte[size]; 218 | int strSize = str.length; 219 | int readBytesCount = stream.read(str); 220 | assert readBytesCount == size; 221 | for (int i = 0; i < str.length; i++) { 222 | if (str[i] == 0) { 223 | strSize = i; 224 | break; 225 | } 226 | } 227 | String name = new String(str, 0, strSize, "ISO-8859-1"); 228 | if (handler != null) { 229 | handler.nameLoaded(name); 230 | } 231 | } 232 | 233 | private void parseAdditionalSections(PsdInputStream stream, int endPos) throws IOException { 234 | while (stream.getPos() < endPos) { 235 | String tag = stream.readString(4); 236 | if (!tag.equals("8BIM")) { 237 | throw new IOException("layer information signature error"); 238 | } 239 | tag = stream.readString(4); 240 | 241 | int size = stream.readInt(); 242 | size = (size + 1) & ~0x01; 243 | int prevPos = stream.getPos(); 244 | 245 | LayerAdditionalInformationParser additionalParser = additionalInformationParsers.get(tag); 246 | if (additionalParser == null) { 247 | additionalParser = defaultAdditionalInformationParser; 248 | } 249 | 250 | if (additionalParser != null) { 251 | additionalParser.parse(stream, tag, size); 252 | } 253 | 254 | stream.skipBytes(prevPos + size - stream.getPos()); 255 | } 256 | } 257 | 258 | public void parseImageSection(PsdInputStream stream) throws IOException { 259 | ImagePlaneParser planeParser = new ImagePlaneParser(stream); 260 | for (Channel channel : channels) { 261 | switch (channel.getId()) { 262 | case Channel.ALPHA: 263 | case Channel.RED: 264 | case Channel.GREEN: 265 | case Channel.BLUE: 266 | channel.setData(planeParser.readPlane(width, height)); 267 | break; 268 | default: 269 | stream.skipBytes(channel.getDataLength()); 270 | // layer mask 271 | } 272 | } 273 | if (handler != null) { 274 | handler.channelsLoaded(channels); 275 | } 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/LayerType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.layer; 20 | 21 | public enum LayerType { 22 | NORMAL, 23 | FOLDER, 24 | HIDDEN 25 | } 26 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/LayersSectionHandler.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer; 2 | 3 | public interface LayersSectionHandler { 4 | public void createLayer(LayerParser parser); 5 | public void createBaseLayer(LayerParser parser); 6 | } 7 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/LayersSectionParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import psd.parser.*; 8 | import psd.parser.header.Header; 9 | 10 | public class LayersSectionParser { 11 | 12 | private LayersSectionHandler handler; 13 | private final Header header; 14 | 15 | public LayersSectionParser(Header header) { 16 | this.header = header; 17 | } 18 | 19 | public void setHandler(LayersSectionHandler handler) { 20 | this.handler = handler; 21 | } 22 | 23 | public void parse(PsdInputStream stream) throws IOException { 24 | // read layer header info 25 | int length = stream.readInt(); 26 | int pos = stream.getPos(); 27 | 28 | if (length > 0) { 29 | int size = stream.readInt(); 30 | if ((size & 0x01) != 0) { 31 | size++; 32 | } 33 | if (size > 0) { 34 | int layersCount = stream.readShort(); 35 | if (layersCount < 0) { 36 | layersCount = -layersCount; 37 | } 38 | 39 | List parsers = new ArrayList(layersCount); 40 | for (int i = 0; i < layersCount; i++) { 41 | LayerParser layerParser = new LayerParser(); 42 | parsers.add(layerParser); 43 | if (handler != null) { 44 | handler.createLayer(layerParser); 45 | } 46 | layerParser.parse(stream); 47 | } 48 | 49 | for (LayerParser layerParser : parsers) { 50 | layerParser.parseImageSection(stream); 51 | } 52 | } 53 | 54 | int maskSize = length - (stream.getPos() - pos); 55 | stream.skipBytes(maskSize); 56 | } 57 | 58 | parseBaseLayer(stream); 59 | } 60 | 61 | private void parseBaseLayer(PsdInputStream stream) throws IOException { 62 | LayerParser baseLayerParser = new LayerParser(); 63 | if (handler != null) { 64 | handler.createBaseLayer(baseLayerParser); 65 | } 66 | baseLayerParser.fireBoundsChanged(0, 0, header.getWidth(), header.getHeight()); 67 | 68 | ArrayList channels = new ArrayList(header.getChannelsCount()); 69 | for (int j = 0; j < header.getChannelsCount(); j++) { 70 | channels.add(new Channel(j == 3 ? -1 : j)); 71 | } 72 | //run-length-encoding 73 | boolean rle = stream.readShort() == 1; 74 | short[] lineLengths = null; 75 | if (rle) { 76 | int nLines = header.getHeight() * header.getChannelsCount(); 77 | lineLengths = new short[nLines]; 78 | 79 | for (int i = 0; i < nLines; i++) { 80 | lineLengths[i] = stream.readShort(); 81 | } 82 | } 83 | 84 | ImagePlaneParser planeParser = new ImagePlaneParser(stream); 85 | int planeNumber = 0; 86 | for (Channel c : channels) { 87 | c.setData(planeParser.readPlane(header.getWidth(), header.getHeight(), lineLengths, planeNumber)); 88 | planeNumber++; 89 | } 90 | baseLayerParser.fireChannelsLoaded(channels); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/Mask.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer; 2 | 3 | public class Mask { 4 | int top; // Rectangle enclosing layer mask: Top, left, bottom, right 5 | int left; 6 | int bottom; 7 | int right; 8 | int defaultColor; // 0 or 255 9 | boolean relative; // position relative to layer 10 | boolean disabled; // layer mask disabled 11 | boolean invert; // invert layer mask when blending 12 | //byte*mask_data; 13 | 14 | public int getLeft() { 15 | return left; 16 | } 17 | 18 | public int getTop() { 19 | return top; 20 | } 21 | 22 | public int getRight() { 23 | return right; 24 | } 25 | 26 | public int getBottom() { 27 | return bottom; 28 | } 29 | 30 | public int getWidth() { 31 | return right - left; 32 | } 33 | 34 | public int getHeight() { 35 | return bottom - top; 36 | } 37 | 38 | public int getDefaultColor() { 39 | return defaultColor; 40 | } 41 | 42 | public boolean isRelative() { 43 | return relative; 44 | } 45 | 46 | public boolean isDisabled() { 47 | return disabled; 48 | } 49 | 50 | public boolean isInvert() { 51 | return invert; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerEffectsHandler.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional; 2 | 3 | import psd.parser.layer.additional.effects.PSDEffect; 4 | 5 | import java.util.List; 6 | 7 | public interface LayerEffectsHandler { 8 | 9 | public void handleEffects(List effects); 10 | } 11 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerEffectsParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.layer.additional; 20 | 21 | import psd.parser.BlendMode; 22 | import psd.parser.PsdInputStream; 23 | import psd.parser.layer.LayerAdditionalInformationParser; 24 | import psd.parser.layer.additional.effects.*; 25 | 26 | import java.awt.*; 27 | import java.io.IOException; 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | /** 32 | * Contains the effects applied in this layer. 33 | * For now it only supports some effects. 34 | */ 35 | public class LayerEffectsParser implements LayerAdditionalInformationParser { 36 | 37 | /** 38 | * Tag that represents the layer effects section. 39 | */ 40 | public static final String TAG = "lrFX"; 41 | 42 | /** 43 | * Layer effects handler (will receive the parsed effects). 44 | */ 45 | private final LayerEffectsHandler handler; 46 | 47 | public LayerEffectsParser(LayerEffectsHandler handler) { 48 | this.handler = handler; 49 | } 50 | 51 | public void parse(PsdInputStream stream, String tag, int size) throws IOException { 52 | 53 | List effects = new ArrayList(); 54 | 55 | int version = stream.readShort(); 56 | int numEffects = stream.readShort(); 57 | int remainingSize = 0; 58 | 59 | for (int i = 0; i < numEffects ; i++) { 60 | 61 | //check signature 62 | String sig = stream.readString(4); 63 | if (!sig.equals("8BIM")) { 64 | throw new Error("layer effect information signature error"); 65 | } 66 | 67 | //check effect ID 68 | String effID = stream.readString(4); 69 | 70 | if (effID.equals("cmnS")) { 71 | //common state info 72 | //skip 73 | /* 74 | 4 Size of next three items: 7 75 | 4 Version: 0 76 | 1 Visible: always true 77 | 2 Unused: always 0 78 | */ 79 | stream.skipBytes(11); 80 | } else if (effID.equals("dsdw")) { 81 | //drop shadow 82 | remainingSize = stream.readInt(); 83 | PSDEffect ef = parseDropShadow(stream,false); 84 | effects.add(ef); 85 | } else if (effID.equals("isdw")) { 86 | //inner drop shadow 87 | remainingSize = stream.readInt(); 88 | PSDEffect ef = parseDropShadow(stream,true); 89 | effects.add(ef); 90 | } else if (effID.equals("oglw")) { 91 | //outer glow 92 | remainingSize = stream.readInt(); 93 | PSDEffect ef = parseGlow(stream,false); 94 | effects.add(ef); 95 | } else if (effID.equals("iglw")) { 96 | //inner glow 97 | remainingSize = stream.readInt(); 98 | PSDEffect ef = parseGlow(stream,true); 99 | effects.add(ef); 100 | } else if (effID.equals("bevl")) { 101 | //bevel 102 | remainingSize = stream.readInt(); 103 | PSDEffect ef = parseBevel(stream); 104 | effects.add(ef); 105 | } else if (effID.equals("sofi")) { 106 | //solid fill 107 | remainingSize = stream.readInt(); 108 | PSDEffect ef = parseSolidFill(stream); 109 | effects.add(ef); 110 | } else { 111 | remainingSize = stream.readInt(); 112 | stream.skipBytes(remainingSize); 113 | if (handler != null) { 114 | handler.handleEffects(effects); 115 | } 116 | return; 117 | } 118 | } 119 | 120 | if (handler != null) { 121 | handler.handleEffects(effects); 122 | } 123 | } 124 | 125 | /** 126 | * Parses the stream to create a DropShadow effect (outer and inner). 127 | * @param stream 128 | * @param inner 129 | * @return 130 | * @throws IOException 131 | */ 132 | private PSDEffect parseDropShadow(PsdInputStream stream, boolean inner) throws IOException { 133 | 134 | int version = stream.readInt(); //0 (Photoshop 5.0) or 2 (Photoshop 5.5) 135 | int blur = stream.readShort(); //Blur value in pixels (8) 136 | int intensity = stream.readInt(); //Intensity as a percent (10?) 137 | int angle = stream.readInt(); //Angle in degrees (120) 138 | int distance = stream.readInt(); //Distance in pixels (25) 139 | 140 | //2 bytes for space 141 | stream.skipBytes(4); 142 | 143 | int colorR = stream.readUnsignedByte(); 144 | stream.skipBytes(1); 145 | int colorG = stream.readUnsignedByte(); 146 | stream.skipBytes(1); 147 | int colorB = stream.readUnsignedByte(); 148 | 149 | Color colorValue = new Color(colorR, colorG, colorB); 150 | 151 | stream.skipBytes(3); 152 | 153 | String blendSig = stream.readString(4); 154 | if (!blendSig.equals("8BIM")){ 155 | throw new Error("Invalid Blend mode signature for Effect: " + blendSig ); 156 | } 157 | 158 | /* 159 | 4 bytes. 160 | Blend mode key. 161 | */ 162 | String blendModeKey = stream.readString(4); 163 | boolean effectIsEnabled = stream.readBoolean(); //1 Effect enabled 164 | boolean useInAllEFX = stream.readBoolean(); //1 Use this angle in all of the layer effects 165 | float alpha = new Float(stream.readUnsignedByte()/255.0); //1 Opacity as a percent 166 | 167 | //get native color 168 | stream.skipBytes(4); //2 bytes for space 169 | colorR = stream.readUnsignedByte(); 170 | stream.skipBytes(1); 171 | colorG = stream.readUnsignedByte(); 172 | stream.skipBytes(1); 173 | colorB = stream.readUnsignedByte(); 174 | stream.skipBytes(1); 175 | 176 | Color nativeColor = new Color(colorR, colorG, colorB); 177 | 178 | /*create a dropshadow effect*/ 179 | DropShadowEffect effect = new DropShadowEffect(inner); 180 | effect.setAlpha(alpha); 181 | effect.setAngle(180-angle); 182 | effect.setBlur(blur); 183 | effect.setColor(colorValue); 184 | effect.setDistance(distance); 185 | effect.setIntensity(intensity); 186 | effect.setQuality(4); 187 | effect.setStrength(1); 188 | effect.setUseInAllEFX(useInAllEFX); 189 | effect.setEnabled(effectIsEnabled); 190 | effect.setBlendMode(BlendMode.getByName(blendModeKey)); 191 | 192 | return effect; 193 | } 194 | 195 | /** 196 | * Parses the stream to create a Glow effect (outer and inner). 197 | * @param stream 198 | * @param inner 199 | * @return 200 | * @throws IOException 201 | */ 202 | private PSDEffect parseGlow(PsdInputStream stream, boolean inner) throws IOException { 203 | 204 | int version = stream.readInt(); //0 (Photoshop 5.0) or 2 (Photoshop 5.5) 205 | int blur = stream.readShort(); //Blur value in pixels (8) 206 | int intensity = stream.readInt(); //Intensity as a percent (10?) (not working) 207 | 208 | //2 bytes for space 209 | stream.skipBytes(4); 210 | int colorR = stream.readUnsignedByte(); 211 | stream.skipBytes(1); 212 | int colorG = stream.readUnsignedByte(); 213 | stream.skipBytes(1); 214 | int colorB = stream.readUnsignedByte(); 215 | 216 | Color colorValue = new Color(colorR, colorG, colorB); 217 | 218 | stream.skipBytes(3); 219 | 220 | String blendSig = stream.readString(4); 221 | if (!blendSig.equals("8BIM")){ 222 | throw new Error("Invalid Blend mode signature for Effect: " + blendSig ); 223 | } 224 | 225 | /* 226 | 4 bytes. 227 | Blend mode key. 228 | */ 229 | String blendModeKey = stream.readString(4); 230 | boolean effectIsEnabled = stream.readBoolean(); //1 Effect enabled 231 | float alpha = new Float(stream.readUnsignedByte()/255.0); //1 Opacity as a percent 232 | 233 | if (version == 2){ 234 | 235 | boolean invert = false; 236 | if (inner) invert = stream.readBoolean(); 237 | 238 | //get native color 239 | stream.skipBytes(3); 240 | colorR = stream.readUnsignedByte(); 241 | stream.skipBytes(1); 242 | colorG = stream.readUnsignedByte(); 243 | stream.skipBytes(1); 244 | colorB = stream.readUnsignedByte(); 245 | stream.skipBytes(2); 246 | 247 | Color nativeColor = new Color(colorR, colorG, colorB); 248 | } 249 | 250 | /*Create the glow effect*/ 251 | GlowEffect effect = new GlowEffect(inner); 252 | effect.setAlpha(alpha); 253 | effect.setBlendMode(BlendMode.getByName(blendModeKey)); 254 | effect.setBlur(blur); 255 | effect.setColor(colorValue); 256 | effect.setEnabled(effectIsEnabled); 257 | effect.setQuality(4); 258 | effect.setStrength(1); 259 | effect.setVersion(version); 260 | effect.setIntensity(intensity); 261 | 262 | return effect; 263 | } 264 | 265 | /** 266 | * Parses the stream to create a Bevel effect 267 | * @param stream 268 | * @return 269 | * @throws IOException 270 | */ 271 | private PSDEffect parseBevel(PsdInputStream stream) throws IOException { 272 | 273 | int version = stream.readInt(); //0 (Photoshop 5.0) or 2 (Photoshop 5.5) 274 | int angle = stream.readShort(); //Angle in degrees 275 | int strength = stream.readInt(); //Strength. Depth in pixels 276 | int blur = stream.readInt(); //Blur value in pixels 277 | 278 | stream.skipBytes(2); 279 | 280 | // Highlight blend mode: 4 bytes for signature and 4 bytes for the key 281 | String blendSig = stream.readString(4); 282 | if (!blendSig.equals("8BIM")){ 283 | throw new Error("Invalid Blend mode signature for Effect: " + blendSig ); 284 | } 285 | 286 | /* 287 | 4 bytes. 288 | Blend mode key. 289 | */ 290 | String blendModeKey = stream.readString(4); 291 | 292 | //Shadow blend mode: 4 bytes for signature and 4 bytes for the key 293 | String blendSigShadow = stream.readString(4); 294 | if (!blendSigShadow.equals("8BIM")){ 295 | throw new Error("Invalid Blend mode signature for Effect: " + blendSigShadow ); 296 | } 297 | 298 | /* 299 | 4 bytes. 300 | Blend mode Shadow key. 301 | */ 302 | String blendModeShadowKey = stream.readString(4); 303 | 304 | //Highlight color: 2 bytes for space followed by 4 * 2 byte color component 305 | stream.skipBytes(3); 306 | 307 | int colorR = stream.readUnsignedByte(); 308 | stream.skipBytes(1); 309 | int colorG = stream.readUnsignedByte(); 310 | stream.skipBytes(1); 311 | int colorB = stream.readUnsignedByte(); 312 | 313 | stream.skipBytes(2); 314 | 315 | Color highlightColor = new Color(colorR, colorG, colorB); 316 | 317 | //Shadow color: 2 bytes for space followed by 4 * 2 byte color component 318 | stream.skipBytes(3); 319 | 320 | colorR = stream.readUnsignedByte(); 321 | stream.skipBytes(1); 322 | colorG = stream.readUnsignedByte(); 323 | stream.skipBytes(1); 324 | colorB = stream.readUnsignedByte(); 325 | 326 | Color shadowColor = new Color(colorR, colorG, colorB); 327 | 328 | stream.skipBytes(2); 329 | 330 | //Bevel style 331 | int bevelStyle = stream.readUnsignedByte(); 332 | 333 | //Hightlight opacity as a percent 334 | float highlightOpacity = new Float(stream.readUnsignedByte()/255.0); 335 | 336 | //Shadow opacity as a percent 337 | float shadowOpacity = new Float(stream.readUnsignedByte()/255.0); 338 | 339 | //Effect enabled 340 | boolean isEffectEnabled = stream.readBoolean(); 341 | 342 | //Use this angle in all of the layer effects 343 | boolean useInAllLayerEffects = stream.readBoolean(); 344 | 345 | //Bevel Up or down 346 | int direction = stream.readUnsignedByte(); 347 | 348 | Color realHighlightColor = null, realShadowColor = null; 349 | if (version == 2) { 350 | //Real Highlight color: 2 bytes for space followed by 4 * 2 byte color component 351 | stream.skipBytes(3); 352 | 353 | int realColorR = stream.readUnsignedByte(); 354 | stream.skipBytes(1); 355 | int realColorG = stream.readUnsignedByte(); 356 | stream.skipBytes(1); 357 | int realColorB = stream.readUnsignedByte(); 358 | 359 | realHighlightColor = new Color(realColorR, realColorG, realColorB); 360 | 361 | stream.skipBytes(2); 362 | 363 | //Real Shadow color: 2 bytes for space followed by 4 * 2 byte color component 364 | stream.skipBytes(3); 365 | 366 | int realShadowColorR = stream.readUnsignedByte(); 367 | stream.skipBytes(1); 368 | int realShadowColorG = stream.readUnsignedByte(); 369 | stream.skipBytes(1); 370 | int realShadowColorB = stream.readUnsignedByte(); 371 | 372 | realShadowColor = new Color(realShadowColorR, realShadowColorG, realShadowColorB); 373 | 374 | stream.skipBytes(2); 375 | } 376 | 377 | BevelEffect effect = new BevelEffect(); 378 | effect.setAngle(angle); 379 | effect.setVersion(version); 380 | effect.setUseInAllLayerEffects(useInAllLayerEffects); 381 | effect.setStrength(strength); 382 | effect.setBevelStyle(bevelStyle); 383 | effect.setBlendMode(BlendMode.getByName(blendModeKey)); 384 | effect.setBlendShadowMode(BlendMode.getByName(blendModeShadowKey)); 385 | effect.setBlur(blur); 386 | effect.setDirection(direction); 387 | effect.setEnabled(isEffectEnabled); 388 | effect.setHighlightColor(highlightColor); 389 | effect.setHighlightOpacity(highlightOpacity); 390 | effect.setShadowColor(shadowColor); 391 | effect.setShadowOpacity(shadowOpacity); 392 | 393 | if (realHighlightColor != null) { 394 | effect.setRealHighlightColor(realHighlightColor); 395 | effect.setRealShadowColor(realShadowColor); 396 | } 397 | 398 | return effect; 399 | } 400 | 401 | /** 402 | * Parses the stream to create a SolidFill effect. 403 | * @param stream 404 | * @return 405 | * @throws IOException 406 | */ 407 | private PSDEffect parseSolidFill(PsdInputStream stream) throws IOException { 408 | 409 | int version = stream.readInt(); //Version: 2 410 | 411 | String blendSig = stream.readString(4); 412 | if (!blendSig.equals("8BIM")){ 413 | throw new Error("Invalid Blend mode signature for Effect: " + blendSig ); 414 | } 415 | 416 | String blendModeKey = stream.readString(4); 417 | 418 | //Highlight color: 2 bytes for space followed by 4 * 2 byte color component 419 | stream.skipBytes(3); 420 | 421 | int colorR = stream.readUnsignedByte(); 422 | stream.skipBytes(1); 423 | int colorG = stream.readUnsignedByte(); 424 | stream.skipBytes(1); 425 | int colorB = stream.readUnsignedByte(); 426 | 427 | Color highlightColor = new Color(colorR, colorG, colorB); 428 | 429 | stream.skipBytes(2); 430 | 431 | float opacity = new Float(stream.readUnsignedByte()/255.0); 432 | 433 | boolean effectEnabled = stream.readBoolean(); 434 | 435 | //Highlight color: 2 bytes for space followed by 4 * 2 byte color component 436 | stream.skipBytes(3); 437 | 438 | colorR = stream.readUnsignedByte(); 439 | stream.skipBytes(1); 440 | colorG = stream.readUnsignedByte(); 441 | stream.skipBytes(1); 442 | colorB = stream.readUnsignedByte(); 443 | 444 | Color nativeColor = new Color(colorR, colorG, colorB); 445 | 446 | stream.skipBytes(2); 447 | 448 | SolidFillEffect effect = new SolidFillEffect(); 449 | effect.setVersion(version); 450 | effect.setBlendMode(BlendMode.getByName(blendModeKey)); 451 | effect.setEnabled(effectEnabled); 452 | effect.setHighlightColor(highlightColor); 453 | effect.setOpacity(opacity); 454 | effect.setNativeColor(nativeColor); 455 | 456 | return effect; 457 | } 458 | } 459 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerIdHandler.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional; 2 | 3 | public interface LayerIdHandler { 4 | public void layerIdParsed(int id); 5 | } 6 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerIdParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional; 2 | 3 | import java.io.IOException; 4 | 5 | import psd.parser.PsdInputStream; 6 | import psd.parser.layer.LayerAdditionalInformationParser; 7 | 8 | public class LayerIdParser implements LayerAdditionalInformationParser { 9 | 10 | public static final String TAG = "lyid"; 11 | private final LayerIdHandler handler; 12 | 13 | public LayerIdParser(LayerIdHandler handler) { 14 | this.handler = handler; 15 | } 16 | 17 | @Override 18 | public void parse(PsdInputStream stream, String tag, int size) throws IOException { 19 | int layerId = stream.readInt(); 20 | if (handler != null) { 21 | handler.layerIdParsed(layerId); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerMetaDataHandler.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional; 2 | 3 | import psd.parser.object.PsdDescriptor; 4 | 5 | public interface LayerMetaDataHandler { 6 | 7 | public void metaDataMlstSectionParsed(PsdDescriptor descriptor); 8 | } 9 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerMetaDataParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.layer.additional; 20 | 21 | import java.io.IOException; 22 | 23 | import psd.parser.PsdInputStream; 24 | import psd.parser.layer.LayerAdditionalInformationParser; 25 | import psd.parser.object.*; 26 | 27 | public class LayerMetaDataParser implements LayerAdditionalInformationParser { 28 | 29 | public static final String TAG = "shmd"; 30 | private final LayerMetaDataHandler handler; 31 | 32 | public LayerMetaDataParser(LayerMetaDataHandler handler) { 33 | this.handler = handler; 34 | } 35 | 36 | @Override 37 | public void parse(PsdInputStream stream, String tag, int size) throws IOException { 38 | int countOfMetaData = stream.readInt(); 39 | for (int i = 0; i < countOfMetaData; i++) { 40 | String dataTag = stream.readString(4); 41 | if (!dataTag.equals("8BIM")) { 42 | throw new IOException("layer meta data section signature error"); 43 | } 44 | String key = stream.readString(4); 45 | 46 | @SuppressWarnings("unused") 47 | int copyOnSheetDuplication = stream.readByte(); 48 | 49 | stream.skipBytes(3); // padding 50 | int len = stream.readInt(); 51 | int pos = stream.getPos(); 52 | if (key.equals("mlst")) { 53 | parseMlstSection(stream); 54 | } else { 55 | } 56 | 57 | stream.skipBytes(len - (stream.getPos() - pos)); 58 | } 59 | } 60 | 61 | private void parseMlstSection(PsdInputStream stream) throws IOException { 62 | stream.skipBytes(4); // ??? 63 | PsdDescriptor descriptor = new PsdDescriptor(stream); 64 | if (handler != null) { 65 | handler.metaDataMlstSectionParsed(descriptor); 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerSectionDividerHandler.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional; 2 | 3 | import psd.parser.layer.LayerType; 4 | 5 | public interface LayerSectionDividerHandler { 6 | public void sectionDividerParsed(LayerType type); 7 | } 8 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerSectionDividerParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional; 2 | 3 | import java.io.IOException; 4 | 5 | import psd.parser.PsdInputStream; 6 | import psd.parser.layer.LayerAdditionalInformationParser; 7 | import psd.parser.layer.LayerType; 8 | 9 | public class LayerSectionDividerParser implements LayerAdditionalInformationParser { 10 | 11 | public static final String TAG = "lsct"; 12 | 13 | private final LayerSectionDividerHandler handler; 14 | 15 | public LayerSectionDividerParser(LayerSectionDividerHandler handler) { 16 | this.handler = handler; 17 | } 18 | 19 | @Override 20 | public void parse(PsdInputStream stream, String tag, int size) throws IOException { 21 | int dividerType = stream.readInt(); 22 | LayerType type = LayerType.NORMAL; 23 | switch (dividerType) { 24 | case 1: 25 | case 2: 26 | type = LayerType.FOLDER; 27 | break; 28 | case 3: 29 | type = LayerType.HIDDEN; 30 | break; 31 | } 32 | handler.sectionDividerParsed(type); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerTypeToolHandler.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional; 2 | 3 | import psd.parser.object.PsdDescriptor; 4 | 5 | public interface LayerTypeToolHandler { 6 | 7 | public void typeToolTransformParsed(Matrix transform); 8 | public void typeToolDescriptorParsed(int version, PsdDescriptor descriptor); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerTypeToolParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.layer.additional; 20 | 21 | import psd.parser.PsdInputStream; 22 | import psd.parser.layer.LayerAdditionalInformationParser; 23 | import psd.parser.object.*; 24 | import java.io.*; 25 | 26 | /** 27 | * contains meta data of a text layer like font type, font size, raw text ...) 28 | */ 29 | public class LayerTypeToolParser implements LayerAdditionalInformationParser { 30 | 31 | public static final String TAG = "TySh"; 32 | 33 | private final LayerTypeToolHandler handler; 34 | 35 | public LayerTypeToolParser(LayerTypeToolHandler handler) { 36 | this.handler = handler; 37 | } 38 | 39 | @Override 40 | public void parse(PsdInputStream stream, String tag, int size) throws IOException { 41 | byte[] data = new byte[size]; 42 | stream.readBytes(data, size); 43 | 44 | PsdInputStream dataStream = new PsdInputStream(new ByteArrayInputStream(data)); 45 | int version = dataStream.readShort(); 46 | assert version == 1; 47 | Matrix transform = new Matrix(dataStream); 48 | if (handler != null) { 49 | handler.typeToolTransformParsed(transform); 50 | } 51 | 52 | int descriptorVersion = dataStream.readShort(); 53 | if (descriptorVersion == 50) { 54 | int xTextDescriptorVersion = dataStream.readInt(); 55 | PsdDescriptor descriptor = new PsdDescriptor(new PsdInputStream(dataStream)); 56 | if (handler != null) { 57 | handler.typeToolDescriptorParsed(xTextDescriptorVersion, descriptor); 58 | } 59 | } else { 60 | // unknown data 61 | assert false; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerUnicodeNameHandler.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional; 2 | 3 | public interface LayerUnicodeNameHandler { 4 | public void layerUnicodeNameParsed(String unicodeName); 5 | } 6 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/LayerUnicodeNameParser.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional; 2 | 3 | import java.io.IOException; 4 | 5 | import psd.parser.PsdInputStream; 6 | import psd.parser.layer.LayerAdditionalInformationParser; 7 | 8 | public class LayerUnicodeNameParser implements LayerAdditionalInformationParser { 9 | 10 | public static final String TAG = "luni"; 11 | private final LayerUnicodeNameHandler handler; 12 | 13 | public LayerUnicodeNameParser(LayerUnicodeNameHandler handler) { 14 | this.handler = handler; 15 | } 16 | 17 | @Override 18 | public void parse(PsdInputStream stream, String tag, int size) throws IOException { 19 | int len = stream.readInt(); 20 | StringBuilder name = new StringBuilder(len); 21 | for (int i = 0; i < len; i++) { 22 | name.append((char) stream.readShort()); 23 | } 24 | if (handler != null) { 25 | handler.layerUnicodeNameParsed(name.toString()); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/Matrix.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional; 2 | 3 | import java.io.*; 4 | 5 | public class Matrix { 6 | 7 | private double m11, m12, m13; 8 | private double m21, m22, m23; 9 | 10 | public Matrix() { 11 | m11 = 1; 12 | m12 = 0; 13 | m13 = 0; 14 | m21 = 0; 15 | m22 = 1; 16 | m23 = 0; 17 | } 18 | 19 | public Matrix(InputStream stream) throws IOException { 20 | DataInputStream dataStream; 21 | if (stream instanceof DataInputStream) { 22 | dataStream = (DataInputStream) stream; 23 | } else { 24 | dataStream = new DataInputStream(stream); 25 | } 26 | m11 = dataStream.readDouble(); 27 | m12 = dataStream.readDouble(); 28 | m13 = dataStream.readDouble(); 29 | m21 = dataStream.readDouble(); 30 | m22 = dataStream.readDouble(); 31 | m23 = dataStream.readDouble(); 32 | } 33 | 34 | public double m11() { 35 | return m11; 36 | } 37 | 38 | public double m12() { 39 | return m12; 40 | } 41 | 42 | public double m13() { 43 | return m13; 44 | } 45 | 46 | public double m21() { 47 | return m21; 48 | } 49 | 50 | public double m22() { 51 | return m22; 52 | } 53 | 54 | public double m23() { 55 | return m23; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/effects/BevelEffect.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional.effects; 2 | 3 | import psd.parser.BlendMode; 4 | 5 | import java.awt.*; 6 | 7 | public class BevelEffect extends PSDEffect { 8 | 9 | private int angle; 10 | private int strength; 11 | private int blur; 12 | private BlendMode blendMode; 13 | private BlendMode blendShadowMode; 14 | private Color highlightColor; 15 | private Color shadowColor; 16 | private int bevelStyle; 17 | private float highlightOpacity; 18 | private float shadowOpacity; 19 | private boolean useInAllLayerEffects; 20 | private int direction; 21 | private Color realHighlightColor; 22 | private Color realShadowColor; 23 | 24 | public BevelEffect(){ 25 | super("bevl"); 26 | } 27 | 28 | public int getAngle() { 29 | return angle; 30 | } 31 | 32 | public void setAngle(int angle) { 33 | this.angle = angle; 34 | } 35 | 36 | public int getStrength() { 37 | return strength; 38 | } 39 | 40 | public void setStrength(int strength) { 41 | this.strength = strength; 42 | } 43 | 44 | public int getBlur() { 45 | return blur; 46 | } 47 | 48 | public void setBlur(int blur) { 49 | this.blur = blur; 50 | } 51 | 52 | public BlendMode getBlendMode() { 53 | return blendMode; 54 | } 55 | 56 | public void setBlendMode(BlendMode blendMode) { 57 | this.blendMode = blendMode; 58 | } 59 | 60 | public BlendMode getBlendShadowMode() { 61 | return blendShadowMode; 62 | } 63 | 64 | public void setBlendShadowMode(BlendMode blendShadowMode) { 65 | this.blendShadowMode = blendShadowMode; 66 | } 67 | 68 | public Color getHighlightColor() { 69 | return highlightColor; 70 | } 71 | 72 | public void setHighlightColor(Color highlightColor) { 73 | this.highlightColor = highlightColor; 74 | } 75 | 76 | public Color getShadowColor() { 77 | return shadowColor; 78 | } 79 | 80 | public void setShadowColor(Color shadowColor) { 81 | this.shadowColor = shadowColor; 82 | } 83 | 84 | public int getBevelStyle() { 85 | return bevelStyle; 86 | } 87 | 88 | public void setBevelStyle(int bevelStyle) { 89 | this.bevelStyle = bevelStyle; 90 | } 91 | 92 | public float getHighlightOpacity() { 93 | return highlightOpacity; 94 | } 95 | 96 | public void setHighlightOpacity(float highlightOpacity) { 97 | this.highlightOpacity = highlightOpacity; 98 | } 99 | 100 | public float getShadowOpacity() { 101 | return shadowOpacity; 102 | } 103 | 104 | public void setShadowOpacity(float shadowOpacity) { 105 | this.shadowOpacity = shadowOpacity; 106 | } 107 | 108 | public boolean isUseInAllLayerEffects() { 109 | return useInAllLayerEffects; 110 | } 111 | 112 | public void setUseInAllLayerEffects(boolean useInAllLayerEffects) { 113 | this.useInAllLayerEffects = useInAllLayerEffects; 114 | } 115 | 116 | public int getDirection() { 117 | return direction; 118 | } 119 | 120 | public void setDirection(int direction) { 121 | this.direction = direction; 122 | } 123 | 124 | public Color getRealHighlightColor() { 125 | return realHighlightColor; 126 | } 127 | 128 | public void setRealHighlightColor(Color realHighlightColor) { 129 | this.realHighlightColor = realHighlightColor; 130 | } 131 | 132 | public Color getRealShadowColor() { 133 | return realShadowColor; 134 | } 135 | 136 | public void setRealShadowColor(Color realShadowColor) { 137 | this.realShadowColor = realShadowColor; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/effects/DropShadowEffect.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional.effects; 2 | 3 | import psd.parser.BlendMode; 4 | 5 | import java.awt.*; 6 | 7 | public class DropShadowEffect extends PSDEffect { 8 | 9 | public static String REGULAR = "dsdw"; 10 | public static String INNER = "isdw"; 11 | 12 | private boolean inner = false; 13 | 14 | private float alpha; 15 | private int angle; 16 | private int blur; 17 | private Color color; 18 | private int quality; 19 | private int distance; 20 | private int strength; 21 | private int intensity; 22 | private boolean useInAllEFX; 23 | private BlendMode blendMode; 24 | 25 | public DropShadowEffect() {} 26 | 27 | public DropShadowEffect(boolean inner){ 28 | super(); 29 | this.setInner(inner); 30 | if (inner){ 31 | setName(INNER); 32 | } else { 33 | setName(REGULAR); 34 | } 35 | } 36 | 37 | public boolean isInner(){ 38 | return inner; 39 | } 40 | 41 | public void setInner(boolean inner) { 42 | this.inner = inner; 43 | if (inner){ 44 | setName(INNER); 45 | } else { 46 | setName(REGULAR); 47 | } 48 | } 49 | 50 | public float getAlpha() { 51 | return alpha; 52 | } 53 | 54 | public void setAlpha(float alpha) { 55 | this.alpha = alpha; 56 | } 57 | 58 | public int getAngle() { 59 | return angle; 60 | } 61 | 62 | public void setAngle(int angle) { 63 | this.angle = angle; 64 | } 65 | 66 | public int getBlur() { 67 | return blur; 68 | } 69 | 70 | public void setBlur(int blur) { 71 | this.blur = blur; 72 | } 73 | 74 | public Color getColor() { 75 | return color; 76 | } 77 | 78 | public void setColor(Color color) { 79 | this.color = color; 80 | } 81 | 82 | public int getQuality() { 83 | return quality; 84 | } 85 | 86 | public void setQuality(int quality) { 87 | this.quality = quality; 88 | } 89 | 90 | public int getDistance() { 91 | return distance; 92 | } 93 | 94 | public BlendMode getBlendMode(){ 95 | return this.blendMode; 96 | } 97 | 98 | public void setDistance(int distance) { 99 | this.distance = distance; 100 | } 101 | 102 | public int getStrength() { 103 | return strength; 104 | } 105 | 106 | public int getVersion() { 107 | return version; 108 | } 109 | 110 | public void setStrength(int strength) { 111 | this.strength = strength; 112 | } 113 | 114 | public int getIntensity() { 115 | return intensity; 116 | } 117 | 118 | public void setIntensity(int intensity) { 119 | this.intensity = intensity; 120 | } 121 | 122 | public boolean isUseInAllEFX() { 123 | return useInAllEFX; 124 | } 125 | 126 | public void setUseInAllEFX(boolean useInAllEFX) { 127 | this.useInAllEFX = useInAllEFX; 128 | } 129 | 130 | public void setBlendMode(BlendMode mode){ 131 | this.blendMode = mode; 132 | } 133 | 134 | public void setVersion(int version) { 135 | this.version = version; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/effects/GlowEffect.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional.effects; 2 | 3 | import psd.parser.BlendMode; 4 | 5 | import java.awt.*; 6 | 7 | public class GlowEffect extends PSDEffect { 8 | 9 | public static String REGULAR = "oglw"; 10 | public static String INNER = "iglw"; 11 | 12 | private boolean inner = false; 13 | private int version; 14 | 15 | private float alpha; 16 | private int blur; 17 | private Color color; 18 | private int quality; 19 | private int strength; 20 | private int intensity; 21 | private BlendMode blendMode; 22 | 23 | public GlowEffect() {} 24 | 25 | public GlowEffect(boolean inner){ 26 | super(); 27 | this.setInner(inner); 28 | if (inner){ 29 | setName(INNER); 30 | } else { 31 | setName(REGULAR); 32 | } 33 | } 34 | 35 | public boolean isInner(){ 36 | return inner; 37 | } 38 | 39 | public void setInner(boolean inner) { 40 | this.inner = inner; 41 | if (inner){ 42 | setName(INNER); 43 | } else { 44 | setName(REGULAR); 45 | } 46 | } 47 | 48 | public float getAlpha() { 49 | return alpha; 50 | } 51 | 52 | public void setAlpha(float alpha) { 53 | this.alpha = alpha; 54 | } 55 | 56 | public int getBlur() { 57 | return blur; 58 | } 59 | 60 | public void setBlur(int blur) { 61 | this.blur = blur; 62 | } 63 | 64 | public Color getColor() { 65 | return color; 66 | } 67 | 68 | public void setColor(Color color) { 69 | this.color = color; 70 | } 71 | 72 | public int getQuality() { 73 | return quality; 74 | } 75 | 76 | public void setQuality(int quality) { 77 | this.quality = quality; 78 | } 79 | 80 | public BlendMode getBlendMode(){ 81 | return this.blendMode; 82 | } 83 | 84 | public int getStrength() { 85 | return strength; 86 | } 87 | 88 | public int getVersion() { 89 | return version; 90 | } 91 | 92 | public void setStrength(int strength) { 93 | this.strength = strength; 94 | } 95 | 96 | public void setBlendMode(BlendMode mode){ 97 | this.blendMode = mode; 98 | } 99 | 100 | public void setVersion(int version) { 101 | this.version = version; 102 | } 103 | 104 | public int getIntensity() { 105 | return intensity; 106 | } 107 | 108 | public void setIntensity(int intensity) { 109 | this.intensity = intensity; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/effects/PSDEffect.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional.effects; 2 | 3 | /** 4 | * Generic Effect class. 5 | * Holds the common properties of all the PSD effects. 6 | */ 7 | public abstract class PSDEffect { 8 | 9 | protected String name; 10 | protected boolean isEnabled; 11 | protected int version; 12 | 13 | public PSDEffect(String name){ 14 | this.name = name; 15 | } 16 | 17 | public PSDEffect() {} 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public boolean isEnabled() { 24 | return isEnabled; 25 | } 26 | 27 | public void setName(String name) { 28 | this.name = name; 29 | } 30 | 31 | public void setEnabled(boolean enabled){ 32 | this.isEnabled = enabled; 33 | } 34 | 35 | public void setVersion(int version) { 36 | this.version = version; 37 | } 38 | 39 | public int getVersion() { 40 | return version; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/layer/additional/effects/SolidFillEffect.java: -------------------------------------------------------------------------------- 1 | package psd.parser.layer.additional.effects; 2 | 3 | import psd.parser.BlendMode; 4 | 5 | import java.awt.*; 6 | 7 | public class SolidFillEffect extends PSDEffect { 8 | 9 | private BlendMode blendMode; 10 | private Color highlightColor; 11 | private float opacity; 12 | private Color nativeColor; 13 | 14 | public SolidFillEffect(){ 15 | super("sofi"); 16 | } 17 | 18 | public BlendMode getBlendMode() { 19 | return blendMode; 20 | } 21 | 22 | public void setBlendMode(BlendMode blendMode) { 23 | this.blendMode = blendMode; 24 | } 25 | 26 | public Color getHighlightColor() { 27 | return highlightColor; 28 | } 29 | 30 | public void setHighlightColor(Color highlightColor) { 31 | this.highlightColor = highlightColor; 32 | } 33 | 34 | public float getOpacity() { 35 | return opacity; 36 | } 37 | 38 | public void setOpacity(float opacity) { 39 | this.opacity = opacity; 40 | } 41 | 42 | public Color getNativeColor() { 43 | return nativeColor; 44 | } 45 | 46 | public void setNativeColor(Color nativeColor) { 47 | this.nativeColor = nativeColor; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdBoolean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.object; 20 | 21 | import java.io.IOException; 22 | 23 | import psd.parser.PsdInputStream; 24 | 25 | /** 26 | * The Class PsdBoolean. 27 | */ 28 | public class PsdBoolean extends PsdObject { 29 | 30 | /** The value. */ 31 | private final boolean value; 32 | 33 | /** 34 | * Instantiates a new psd boolean. 35 | * 36 | * @param stream the stream 37 | * @throws IOException Signals that an I/O exception has occurred. 38 | */ 39 | public PsdBoolean(PsdInputStream stream) throws IOException { 40 | value = stream.readBoolean(); 41 | logger.finest("PsdBoolean.value: " + value ); 42 | } 43 | 44 | /** 45 | * Gets the value. 46 | * 47 | * @return the value 48 | */ 49 | public boolean getValue() { 50 | return value; 51 | } 52 | 53 | /* (non-Javadoc) 54 | * @see java.lang.Object#toString() 55 | */ 56 | @Override 57 | public String toString() { 58 | return "bool:" + value; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdDescriptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.object; 20 | 21 | import java.io.IOException; 22 | import java.util.*; 23 | 24 | import psd.parser.PsdInputStream; 25 | 26 | /** 27 | * The Class PsdDescriptor holds meta data of a layer. 28 | * 29 | * @author Dmitry Belsky 30 | */ 31 | public class PsdDescriptor extends PsdObject { 32 | 33 | /** The class id or layer type. */ 34 | private final String classId; 35 | 36 | /** a map containing all values of the descriptor */ 37 | private final HashMap objects = new HashMap(); 38 | 39 | /** 40 | * Instantiates a new psd descriptor. 41 | * 42 | * @param stream the stream 43 | * @throws IOException Signals that an I/O exception has occurred. 44 | */ 45 | public PsdDescriptor(PsdInputStream stream) throws IOException { 46 | // Unicode string: name from classID 47 | int nameLen = stream.readInt() * 2; 48 | stream.skipBytes(nameLen); 49 | 50 | classId = stream.readPsdString(); 51 | int itemsCount = stream.readInt(); 52 | logger.finest("PsdDescriptor.itemsCount: " + itemsCount); 53 | for (int i = 0; i < itemsCount; i++) { 54 | String key = stream.readPsdString().trim(); 55 | logger.finest("PsdDescriptor.key: " + key); 56 | objects.put(key, PsdObjectFactory.loadPsdObject(stream)); 57 | } 58 | } 59 | 60 | /** 61 | * Gets the class id. 62 | * 63 | * @return the class id 64 | */ 65 | public String getClassId() { 66 | return classId; 67 | } 68 | 69 | /** 70 | * Gets the objects. 71 | * 72 | * @return the objects 73 | */ 74 | public Map getObjects() { 75 | return objects; 76 | } 77 | 78 | /** 79 | * Gets the. 80 | * 81 | * @param key the key 82 | * @return the psd object 83 | */ 84 | public PsdObject get(String key) { 85 | return objects.get(key); 86 | } 87 | 88 | /** 89 | * Contains key. 90 | * 91 | * @param key the key 92 | * @return true, if successful 93 | */ 94 | public boolean containsKey(String key) { 95 | return objects.containsKey(key); 96 | } 97 | 98 | /* (non-Javadoc) 99 | * @see java.lang.Object#toString() 100 | */ 101 | @Override 102 | public String toString() { 103 | return "Objc:" + objects.toString(); 104 | } 105 | 106 | } -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdDouble.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.object; 20 | 21 | import java.io.IOException; 22 | 23 | import psd.parser.PsdInputStream; 24 | 25 | // TODO: Auto-generated Javadoc 26 | /** 27 | * The Class PsdDouble. 28 | * 29 | * @author Dmitry Belsky 30 | */ 31 | public class PsdDouble extends PsdObject { 32 | 33 | /** The value. */ 34 | private final double value; 35 | 36 | /** 37 | * Instantiates a new psd double. 38 | * 39 | * @param stream the stream 40 | * @throws IOException Signals that an I/O exception has occurred. 41 | */ 42 | public PsdDouble(PsdInputStream stream) throws IOException { 43 | value = stream.readDouble(); 44 | logger.finest("PsdDouble.value: " + value); 45 | } 46 | 47 | /** 48 | * Gets the value. 49 | * 50 | * @return the value 51 | */ 52 | public double getValue() { 53 | return value; 54 | } 55 | 56 | /* (non-Javadoc) 57 | * @see java.lang.Object#toString() 58 | */ 59 | @Override 60 | public String toString() { 61 | return "doub:" + value; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdEnum.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.object; 20 | 21 | import java.io.IOException; 22 | 23 | import psd.parser.PsdInputStream; 24 | 25 | // TODO: Auto-generated Javadoc 26 | /** 27 | * The Class PsdEnum. 28 | * 29 | * @author Dmitry Belsky 30 | */ 31 | public class PsdEnum extends PsdObject { 32 | 33 | /** The type id. */ 34 | private final String typeId; 35 | 36 | /** The value. */ 37 | private final String value; 38 | 39 | /** 40 | * Instantiates a new psd enum. 41 | * 42 | * @param stream the stream 43 | * @throws IOException Signals that an I/O exception has occurred. 44 | */ 45 | public PsdEnum(PsdInputStream stream) throws IOException { 46 | 47 | typeId = stream.readPsdString(); 48 | value = stream.readPsdString(); 49 | logger.finest("PsdEnum.typeId " + typeId + " PsdEnum.value: " + value); 50 | } 51 | 52 | /** 53 | * Gets the type id. 54 | * 55 | * @return the type id 56 | */ 57 | public String getTypeId() { 58 | return typeId; 59 | } 60 | 61 | /** 62 | * Gets the value. 63 | * 64 | * @return the value 65 | */ 66 | public String getValue() { 67 | return value; 68 | } 69 | 70 | /* (non-Javadoc) 71 | * @see java.lang.Object#toString() 72 | */ 73 | @Override 74 | public String toString() { 75 | return "enum:<" + typeId + ":" + value + ">"; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.object; 20 | 21 | import java.io.IOException; 22 | import java.util.ArrayList; 23 | import java.util.Iterator; 24 | 25 | import psd.parser.PsdInputStream; 26 | 27 | // TODO: Auto-generated Javadoc 28 | /** 29 | * The Class PsdList. 30 | * 31 | * @author Dmitry Belsky 32 | */ 33 | public class PsdList extends PsdObject implements Iterable { 34 | 35 | /** The objects. */ 36 | private ArrayList objects = new ArrayList(); 37 | 38 | /** 39 | * Instantiates a new psd list. 40 | * 41 | * @param stream the stream 42 | * @throws IOException Signals that an I/O exception has occurred. 43 | */ 44 | public PsdList(PsdInputStream stream) throws IOException { 45 | int itemsCount = stream.readInt(); 46 | logger.finest("PsdList.itemsCount: " + itemsCount); 47 | for (int i = 0; i < itemsCount; i++) { 48 | objects.add(PsdObjectFactory.loadPsdObject(stream)); 49 | } 50 | } 51 | 52 | /* (non-Javadoc) 53 | * @see java.lang.Iterable#iterator() 54 | */ 55 | @Override 56 | public Iterator iterator() { 57 | return objects.iterator(); 58 | } 59 | 60 | /** 61 | * Size. 62 | * 63 | * @return the int 64 | */ 65 | public int size() { 66 | return objects.size(); 67 | } 68 | 69 | /** 70 | * Gets the. 71 | * 72 | * @param i the i 73 | * @return the psd object 74 | */ 75 | public PsdObject get(int i) { 76 | return objects.get(i); 77 | } 78 | 79 | /* (non-Javadoc) 80 | * @see java.lang.Object#toString() 81 | */ 82 | @Override 83 | public String toString() { 84 | return "VlLs:" + objects.toString(); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdLong.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.object; 20 | 21 | import java.io.IOException; 22 | 23 | import psd.parser.PsdInputStream; 24 | 25 | // TODO: Auto-generated Javadoc 26 | /** 27 | * The Class PsdLong. 28 | * 29 | * @author Dmitry Belsky 30 | */ 31 | public class PsdLong extends PsdObject { 32 | 33 | /** The value. */ 34 | private final int value; 35 | 36 | /** 37 | * Instantiates a new psd long. 38 | * 39 | * @param stream the stream 40 | * @throws IOException Signals that an I/O exception has occurred. 41 | */ 42 | public PsdLong(PsdInputStream stream) throws IOException { 43 | value = stream.readInt(); 44 | logger.finest("PsdLong.value: " + value); 45 | } 46 | 47 | /** 48 | * Gets the value. 49 | * 50 | * @return the value 51 | */ 52 | public int getValue() { 53 | return value; 54 | } 55 | 56 | /* (non-Javadoc) 57 | * @see java.lang.Object#toString() 58 | */ 59 | @Override 60 | public String toString() { 61 | return "long:" + value; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.object; 20 | 21 | import java.util.logging.Logger; 22 | 23 | 24 | public class PsdObject { 25 | 26 | /** The Constant logger. */ 27 | protected static final Logger logger = Logger.getLogger("psd.objects"); 28 | 29 | protected PsdObject() { 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdObjectFactory.java: -------------------------------------------------------------------------------- 1 | package psd.parser.object; 2 | 3 | import java.io.IOException; 4 | 5 | import psd.parser.PsdInputStream; 6 | 7 | public class PsdObjectFactory { 8 | 9 | /** 10 | * Load psd object. 11 | * 12 | * @param stream the stream 13 | * @return the psd object 14 | * @throws IOException Signals that an I/O exception has occurred. 15 | */ 16 | public static PsdObject loadPsdObject(PsdInputStream stream) 17 | throws IOException { 18 | 19 | String type = stream.readString(4); 20 | PsdObject.logger.finest("loadPsdObject.type: " + type); 21 | if (type.equals("Objc")) { 22 | return new PsdDescriptor(stream); 23 | } else if (type.equals("VlLs")) { 24 | return new PsdList(stream); 25 | } else if (type.equals("doub")) { 26 | return new PsdDouble(stream); 27 | } else if (type.equals("long")) { 28 | return new PsdLong(stream); 29 | } else if (type.equals("bool")) { 30 | return new PsdBoolean(stream); 31 | } else if (type.equals("UntF")) { 32 | return new PsdUnitFloat(stream); 33 | } else if (type.equals("enum")) { 34 | return new PsdEnum(stream); 35 | } else if (type.equals("TEXT")) { 36 | return new PsdText(stream); 37 | } else if (type.equals("tdta")) { 38 | return new PsdTextData(stream); 39 | } else { 40 | throw new IOException("UNKNOWN TYPE <" + type + ">"); 41 | } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdText.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.object; 20 | 21 | import java.io.IOException; 22 | 23 | import psd.parser.PsdInputStream; 24 | 25 | // TODO: Auto-generated Javadoc 26 | /** 27 | * The Class PsdText. 28 | * 29 | * @author Dmitry Belsky 30 | */ 31 | public class PsdText extends PsdObject { 32 | 33 | /** The value. */ 34 | private final String value; 35 | 36 | /** 37 | * Instantiates a new psd text. 38 | * 39 | * @param stream the stream 40 | * @throws IOException Signals that an I/O exception has occurred. 41 | */ 42 | public PsdText(PsdInputStream stream) throws IOException { 43 | int textSize = stream.readInt(); 44 | StringBuffer buffer = new StringBuffer(textSize); 45 | boolean stopReading = false; 46 | for (int ti = 0; ti < textSize; ti++) { 47 | char b = (char) stream.readShort(); 48 | if (b == 0) { 49 | stopReading = true; 50 | } 51 | if (!stopReading) { 52 | if (b == 13 || b == 10) { 53 | buffer.append('\n'); 54 | } else { 55 | buffer.append(b); 56 | } 57 | } 58 | } 59 | value = buffer.toString(); 60 | 61 | logger.finest("PsdText.value: " + value); 62 | } 63 | 64 | /** 65 | * Gets the value. 66 | * 67 | * @return the value 68 | */ 69 | public String getValue() { 70 | return value; 71 | } 72 | 73 | /* (non-Javadoc) 74 | * @see java.lang.Object#toString() 75 | */ 76 | @Override 77 | public String toString() { 78 | return value; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdTextData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.object; 20 | 21 | import java.io.*; 22 | import java.util.*; 23 | import psd.parser.PsdInputStream; 24 | 25 | public class PsdTextData extends PsdObject { 26 | 27 | private Map properties; 28 | private int cachedByte = -1; 29 | private boolean useCachedByte; 30 | 31 | public PsdTextData(PsdInputStream stream) throws IOException { 32 | int size = stream.readInt(); 33 | int startPos = stream.getPos(); 34 | properties = readMap(stream); 35 | assert startPos + size == stream.getPos(); 36 | } 37 | 38 | /** 39 | * Gets the properties. 40 | * 41 | * @return the properties 42 | */ 43 | public Map getProperties() { 44 | return properties; 45 | } 46 | 47 | private Map readMap(PsdInputStream stream) throws IOException { 48 | skipWhitespaces(stream); 49 | char c = (char) readByte(stream); 50 | 51 | if (c == ']') { 52 | return null; 53 | } else if (c == '<') { 54 | skipString(stream, "<"); 55 | } 56 | HashMap map = new HashMap(); 57 | while (true) { 58 | skipWhitespaces(stream); 59 | c = (char) readByte(stream); 60 | if (c == '>') { 61 | skipString(stream, ">"); 62 | return map; 63 | } else { 64 | assert c == '/' : "unknown char: " + c + ", byte: " + (byte) c; 65 | String name = readName(stream); 66 | skipWhitespaces(stream); 67 | c = (char) lookForwardByte(stream); 68 | if (c == '<') { 69 | map.put(name, readMap(stream)); 70 | } else { 71 | map.put(name, readValue(stream)); 72 | } 73 | } 74 | } 75 | } 76 | 77 | private String readName(PsdInputStream stream) throws IOException { 78 | String name = ""; 79 | while (true) { 80 | char c = (char) readByte(stream); 81 | if (c == ' ' || c == 10) { 82 | break; 83 | } 84 | name += c; 85 | } 86 | return name; 87 | } 88 | 89 | private Object readValue(PsdInputStream stream) throws IOException { 90 | char c = (char) readByte(stream); 91 | if (c == ']') { 92 | return null; 93 | } else if (c == '(') { 94 | // unicode string 95 | String string = ""; 96 | int stringSignature = readShort(stream) & 0xFFFF; 97 | assert stringSignature == 0xFEFF; 98 | while (true) { 99 | byte b1 = readByte(stream); 100 | if (b1 == ')') { 101 | return string; 102 | } 103 | byte b2 = readByte(stream); 104 | if (b2 == '\\') { 105 | b2 = readByte(stream); 106 | } 107 | if (b2 == 13) { 108 | string += '\n'; 109 | } else { 110 | string += (char) ((b1 << 8) | b2); 111 | } 112 | } 113 | } else if (c == '[') { 114 | ArrayList list = new ArrayList(); 115 | // array 116 | c = (char) readByte(stream); 117 | while (true) { 118 | skipWhitespaces(stream); 119 | c = (char) lookForwardByte(stream); 120 | if (c == '<') { 121 | Object val = readMap(stream); 122 | if (val == null) { 123 | return list; 124 | } else { 125 | list.add(val); 126 | } 127 | } else { 128 | Object val = readValue(stream); 129 | if (val == null) { 130 | return list; 131 | } else { 132 | list.add(val); 133 | } 134 | } 135 | } 136 | } else { 137 | String val = ""; 138 | do { 139 | val += c; 140 | c = (char) readByte(stream); 141 | } while (c != 10 && c != ' '); 142 | if (val.equals("true") || val.equals("false")) { 143 | return Boolean.valueOf(val); 144 | } else { 145 | return Double.valueOf(val); 146 | } 147 | } 148 | } 149 | 150 | private void skipWhitespaces(PsdInputStream stream) throws IOException { 151 | byte b; 152 | do { 153 | b = readByte(stream); 154 | } while (b == ' ' || b == 10 || b == 9); 155 | putBack(); 156 | } 157 | 158 | private void skipString(PsdInputStream stream, String string) throws IOException { 159 | for (int i = 0; i < string.length(); i++) { 160 | char streamCh = (char) readByte(stream); 161 | assert streamCh == string.charAt(i) : "char " + streamCh + " mustBe " + string.charAt(i); 162 | } 163 | } 164 | 165 | /* (non-Javadoc) 166 | * @see java.lang.Object#toString() 167 | */ 168 | @Override 169 | public String toString() { 170 | return properties.toString(); 171 | } 172 | 173 | private byte readByte(PsdInputStream stream) throws IOException { 174 | if (useCachedByte) { 175 | assert cachedByte != -1; 176 | useCachedByte = false; 177 | return (byte) cachedByte; 178 | } else { 179 | cachedByte = stream.read(); 180 | return (byte) cachedByte; 181 | } 182 | } 183 | 184 | private short readShort(PsdInputStream stream) throws IOException { 185 | cachedByte = -1; 186 | useCachedByte = false; 187 | return stream.readShort(); 188 | } 189 | 190 | private void putBack() { 191 | assert cachedByte != -1; 192 | assert !useCachedByte; 193 | useCachedByte = true; 194 | } 195 | 196 | private byte lookForwardByte(PsdInputStream stream) throws IOException { 197 | byte b = readByte(stream); 198 | putBack(); 199 | return b; 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /psd-parser/src/psd/parser/object/PsdUnitFloat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of java-psd-library. 3 | * 4 | * This library is free software: you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public License 6 | * as published by the Free Software Foundation, either version 3 of 7 | * the License, or (at your option) any later version. 8 | 9 | * This library is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see 16 | * . 17 | */ 18 | 19 | package psd.parser.object; 20 | 21 | import java.io.IOException; 22 | 23 | import psd.parser.PsdInputStream; 24 | 25 | // TODO: Auto-generated Javadoc 26 | /** 27 | * The Class PsdUnitFloat. 28 | * 29 | * @author Dmitry Belsky 30 | */ 31 | public class PsdUnitFloat extends PsdObject { 32 | 33 | /** The unit. */ 34 | private final String unit; 35 | 36 | /** The value. */ 37 | private final double value; 38 | 39 | /** 40 | * Instantiates a new psd unit float. 41 | * 42 | * @param stream the stream 43 | * @throws IOException Signals that an I/O exception has occurred. 44 | */ 45 | public PsdUnitFloat(PsdInputStream stream) throws IOException { 46 | unit = stream.readString(4); 47 | value = stream.readDouble(); 48 | logger.finest("PsdUnitFloat.unit: " + unit + " PsdUnitFloat.value: " + value ); 49 | } 50 | 51 | /** 52 | * Gets the unit. 53 | * 54 | * @return the unit 55 | */ 56 | public String getUnit() { 57 | return unit; 58 | } 59 | 60 | /** 61 | * Gets the value. 62 | * 63 | * @return the value 64 | */ 65 | public double getValue() { 66 | return value; 67 | } 68 | 69 | /* (non-Javadoc) 70 | * @see java.lang.Object#toString() 71 | */ 72 | @Override 73 | public String toString() { 74 | return "UntF:<" + unit + ":" + value + ">"; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /psd-parser/src/psd/util/BufferedImageBuilder.java: -------------------------------------------------------------------------------- 1 | package psd.util; 2 | 3 | import java.awt.image.*; 4 | import java.util.List; 5 | 6 | import psd.parser.layer.Channel; 7 | 8 | public class BufferedImageBuilder { 9 | 10 | private final List channels; 11 | private final int width; 12 | private final int height; 13 | private int opacity = -1; 14 | 15 | public BufferedImageBuilder(List channels, int width, int height) { 16 | this.channels = channels; 17 | this.width = width; 18 | this.height = height; 19 | } 20 | 21 | public void setOpacity(int opacity) { 22 | this.opacity = opacity; 23 | } 24 | 25 | public BufferedImage makeImage() { 26 | if (width == 0 || height == 0) { 27 | return null; 28 | } 29 | 30 | byte[] rChannel = getChannelData(Channel.RED); 31 | byte[] gChannel = getChannelData(Channel.GREEN); 32 | byte[] bChannel = getChannelData(Channel.BLUE); 33 | byte[] aChannel = getChannelData(Channel.ALPHA); 34 | applyOpacity(aChannel); 35 | 36 | BufferedImage im = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 37 | int[] data = ((DataBufferInt) im.getRaster().getDataBuffer()).getData(); 38 | int n = width * height - 1; 39 | while (n >= 0) { 40 | int a = aChannel[n] & 0xff; 41 | int r = rChannel[n] & 0xff; 42 | int g = gChannel[n] & 0xff; 43 | int b = bChannel[n] & 0xff; 44 | data[n] = a << 24 | r << 16 | g << 8 | b; 45 | n--; 46 | } 47 | return im; 48 | } 49 | 50 | private void applyOpacity(byte[] a) { 51 | if (opacity != -1) { 52 | double o = (opacity & 0xff) / 256.0; 53 | for (int i = 0; i < a.length; i++) { 54 | a[i] = (byte) ((a[i] & 0xff) * o); 55 | } 56 | } 57 | } 58 | 59 | private byte[] getChannelData(int channelId) { 60 | for (Channel c : channels) { 61 | if (channelId == c.getId() && c.getData() != null) { 62 | return c.getData(); 63 | } 64 | } 65 | return fillBytes(width * height, (byte) (channelId == Channel.ALPHA ? 255 : 0)); 66 | } 67 | 68 | private byte[] fillBytes(int size, byte value) { 69 | byte[] result = new byte[size]; 70 | if (value != 0) { 71 | for (int i = 0; i < size; i++) { 72 | result[i] = value; 73 | } 74 | } 75 | return result; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /psd-tool/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /psd-tool/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | psd-tool 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /psd-tool/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | psd-library 5 | psd-tool 6 | 2.0-SNAPSHOT 7 | jar 8 | 9 | .. 10 | psd-library 11 | psd-library-parent 12 | 2.0-SNAPSHOT 13 | 14 | 15 | src 16 | 17 | 18 | maven-compiler-plugin 19 | 20 | 1.6 21 | 1.6 22 | 23 | 24 | 25 | org.apache.maven.plugins 26 | maven-shade-plugin 27 | 1.4 28 | 29 | 30 | package 31 | 32 | shade 33 | 34 | 35 | 36 | 37 | psdtool.UiLauncher 38 | 39 | 40 | 41 | 42 | psd-library:psd-image 43 | psd-library:psd-parser 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | psd-library 55 | psd-image 56 | 2.0-SNAPSHOT 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /psd-tool/psd-tool.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /psd-tool/src/psdtool/MainFrame.java: -------------------------------------------------------------------------------- 1 | package psdtool; 2 | 3 | import psd.Psd; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | import java.awt.event.ActionEvent; 8 | import java.io.File; 9 | import java.io.FilenameFilter; 10 | import java.io.IOException; 11 | 12 | public class MainFrame { 13 | 14 | private JFrame frame; 15 | private TreeLayerModel treeLayerModel = new TreeLayerModel(); 16 | private PsdView psdView; 17 | 18 | public MainFrame() { 19 | frame = new JFrame("Psd Tool"); 20 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 21 | 22 | JTree tree = new JTree(treeLayerModel); 23 | tree.setBorder(null); 24 | tree.setPreferredSize(new Dimension(300, 400)); 25 | 26 | psdView = new PsdView(); 27 | 28 | JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 29 | split.setLeftComponent(new JScrollPane(tree)); 30 | split.setRightComponent(new JScrollPane(psdView)); 31 | frame.getContentPane().add(split); 32 | frame.setJMenuBar(buildMenu()); 33 | 34 | frame.pack(); 35 | 36 | } 37 | 38 | public JFrame getFrame() { 39 | return frame; 40 | } 41 | 42 | private JMenuBar buildMenu() { 43 | JMenuBar bar = new JMenuBar(); 44 | 45 | JMenu fileMenu = new JMenu("File"); 46 | fileMenu.add(new OpenFileAction()).setAccelerator(KeyStroke.getKeyStroke("meta O")); 47 | bar.add(fileMenu); 48 | 49 | return bar; 50 | } 51 | 52 | private class OpenFileAction extends AbstractAction { 53 | private static final long serialVersionUID = 1L; 54 | 55 | public OpenFileAction() { 56 | super("Open file"); 57 | } 58 | 59 | @Override 60 | public void actionPerformed(ActionEvent e) { 61 | FileDialog fileDialog = new FileDialog(frame, "Open psd file", FileDialog.LOAD); 62 | fileDialog.setDirectory("~/Downloads"); 63 | fileDialog.setFilenameFilter(new FilenameFilter() { 64 | @Override 65 | public boolean accept(File dir, String name) { 66 | return name.toLowerCase().endsWith(".psd"); 67 | } 68 | }); 69 | 70 | fileDialog.setVisible(true); 71 | if (fileDialog.getFile() != null) { 72 | File directory = new File(fileDialog.getDirectory()); 73 | File psdFile = new File(directory, fileDialog.getFile()); 74 | try { 75 | Psd psd = new Psd(psdFile); 76 | treeLayerModel.setPsd(psd); 77 | psdView.setPsd(psd); 78 | } catch (IOException ex) { 79 | throw new RuntimeException(ex); 80 | } 81 | } 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /psd-tool/src/psdtool/PsdView.java: -------------------------------------------------------------------------------- 1 | package psdtool; 2 | 3 | import psd.Layer; 4 | import psd.LayersContainer; 5 | import psd.Psd; 6 | import psd.parser.layer.additional.effects.PSDEffect; 7 | 8 | import javax.swing.*; 9 | import java.awt.*; 10 | 11 | public class PsdView extends JComponent { 12 | private static final long serialVersionUID = 1L; 13 | 14 | private Psd psd; 15 | 16 | public PsdView() { 17 | setPreferredSize(new Dimension(400, 400)); 18 | } 19 | 20 | public void setPsd(Psd psd) { 21 | this.psd = psd; 22 | setPreferredSize(new Dimension(psd.getWidth(), psd.getHeight())); 23 | repaint(); 24 | revalidate(); 25 | } 26 | 27 | @Override 28 | public void paintComponent(Graphics g) { 29 | if (psd != null) { 30 | paintLayersContainer((Graphics2D) g, psd, 1.0f); 31 | } 32 | } 33 | 34 | private void paintLayersContainer(Graphics2D g, LayersContainer container, float alpha) { 35 | for (int i = 0; i < container.getLayersCount(); i++) { 36 | Layer layer = container.getLayer(i); 37 | if (!layer.isVisible()) { 38 | continue; 39 | } 40 | 41 | Composite composite = g.getComposite(); 42 | float layerAlpha = alpha * layer.getAlpha() / 255.0f; 43 | g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, layerAlpha)); 44 | 45 | if (layer.getImage() != null) { 46 | g.drawImage(layer.getImage(), layer.getX(), layer.getY(), null); 47 | } 48 | g.setComposite(composite); 49 | 50 | paintLayersContainer(g, layer, layerAlpha); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /psd-tool/src/psdtool/TreeLayerModel.java: -------------------------------------------------------------------------------- 1 | package psdtool; 2 | 3 | import psd.Layer; 4 | import psd.LayersContainer; 5 | import psd.Psd; 6 | import psd.parser.layer.LayerType; 7 | 8 | import javax.swing.event.TreeModelEvent; 9 | import javax.swing.event.TreeModelListener; 10 | import javax.swing.tree.TreeModel; 11 | import javax.swing.tree.TreePath; 12 | import java.util.LinkedList; 13 | 14 | public class TreeLayerModel implements TreeModel { 15 | 16 | private Psd psd; 17 | private LinkedList listeners = new LinkedList(); 18 | 19 | public TreeLayerModel() { 20 | } 21 | 22 | public void setPsd(Psd psd) { 23 | this.psd = psd; 24 | if (!listeners.isEmpty()) { 25 | TreeModelEvent event = new TreeModelEvent(this, new TreePath(psd)); 26 | for (TreeModelListener l : listeners) { 27 | l.treeStructureChanged(event); 28 | } 29 | } 30 | } 31 | 32 | @Override 33 | public Object getRoot() { 34 | return psd; 35 | } 36 | 37 | @Override 38 | public Object getChild(Object parent, int index) { 39 | return ((LayersContainer) parent).getLayer(index); 40 | } 41 | 42 | @Override 43 | public int getChildCount(Object parent) { 44 | return ((LayersContainer) parent).getLayersCount(); 45 | } 46 | 47 | @Override 48 | public boolean isLeaf(Object node) { 49 | return node instanceof Layer && ((Layer) node).getType() == LayerType.NORMAL; 50 | } 51 | 52 | @Override 53 | public void valueForPathChanged(TreePath path, Object newValue) { 54 | } 55 | 56 | @Override 57 | public int getIndexOfChild(Object parent, Object child) { 58 | return ((LayersContainer) parent).indexOfLayer((Layer) child); 59 | } 60 | 61 | @Override 62 | public void addTreeModelListener(TreeModelListener l) { 63 | listeners.add(l); 64 | } 65 | 66 | @Override 67 | public void removeTreeModelListener(TreeModelListener l) { 68 | listeners.remove(l); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /psd-tool/src/psdtool/UiLauncher.java: -------------------------------------------------------------------------------- 1 | package psdtool; 2 | 3 | import javax.swing.*; 4 | import java.io.PrintStream; 5 | import java.util.logging.*; 6 | 7 | public class UiLauncher { 8 | 9 | public static void main(String[] args) { 10 | setupLogging(); 11 | setupOutputStream(); 12 | initializeSystemProperties(); 13 | setupLookAndFeel(); 14 | startUi(); 15 | } 16 | 17 | private static void setupLogging() { 18 | Logger rootLogger = Logger.getLogger(""); 19 | rootLogger.setLevel(Level.CONFIG); 20 | Handler[] handlers = rootLogger.getHandlers(); 21 | for (Handler handler : handlers) { 22 | rootLogger.removeHandler(handler); 23 | } 24 | rootLogger.addHandler(new ConsoleHandler() { 25 | @Override 26 | public void publish(LogRecord rec) { 27 | System.out.println(rec.getLevel() + ": " + rec.getMessage()); 28 | } 29 | }); 30 | } 31 | 32 | private static void setupOutputStream() { 33 | try { 34 | System.setOut(new PrintStream(System.out, true, "utf-8")); 35 | } catch (java.io.UnsupportedEncodingException ex) { 36 | ex.printStackTrace(); 37 | } 38 | } 39 | 40 | private static void initializeSystemProperties() { 41 | System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Psd Tool"); 42 | System.setProperty("apple.laf.useScreenMenuBar", "true"); 43 | } 44 | 45 | private static void setupLookAndFeel() { 46 | try { 47 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 48 | //UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | 54 | private static void startUi() { 55 | SwingUtilities.invokeLater(new Runnable() { 56 | @Override 57 | public void run() { 58 | showFrame(); 59 | } 60 | }); 61 | } 62 | 63 | private static void showFrame() { 64 | JFrame frame = new MainFrame().getFrame(); 65 | frame.setExtendedState(JFrame.MAXIMIZED_BOTH); 66 | frame.doLayout(); 67 | frame.setVisible(true); 68 | } 69 | 70 | } 71 | --------------------------------------------------------------------------------