You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

HwmfPalette.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hwmf.record;
  16. import java.awt.Color;
  17. import java.io.IOException;
  18. import java.util.ArrayList;
  19. import java.util.List;
  20. import org.apache.poi.hwmf.draw.HwmfDrawProperties;
  21. import org.apache.poi.hwmf.draw.HwmfGraphics;
  22. import org.apache.poi.util.BitField;
  23. import org.apache.poi.util.BitFieldFactory;
  24. import org.apache.poi.util.LittleEndianConsts;
  25. import org.apache.poi.util.LittleEndianInputStream;
  26. public class HwmfPalette {
  27. public static class PaletteEntry {
  28. private static final BitField PC_RESERVED = BitFieldFactory.getInstance(0x01);
  29. private static final BitField PC_EXPLICIT = BitFieldFactory.getInstance(0x02);
  30. private static final BitField PC_NOCOLLAPSE = BitFieldFactory.getInstance(0x04);
  31. private int values;
  32. private Color colorRef;
  33. public PaletteEntry() {
  34. this.values = PC_RESERVED.set(0);
  35. this.colorRef = Color.BLACK;
  36. }
  37. public PaletteEntry(PaletteEntry other) {
  38. this.values = other.values;
  39. this.colorRef = other.colorRef;
  40. }
  41. public int init(LittleEndianInputStream leis) throws IOException {
  42. // Values (1 byte): An 8-bit unsigned integer that defines how the palette entry is to be used.
  43. // The Values field MUST be 0x00 or one of the values in the PaletteEntryFlag Enumeration table.
  44. values = leis.readUByte();
  45. // Blue (1 byte): An 8-bit unsigned integer that defines the blue intensity value for the palette entry.
  46. int blue = leis.readUByte();
  47. // Green (1 byte): An 8-bit unsigned integer that defines the green intensity value for the palette entry.
  48. int green = leis.readUByte();
  49. // Red (1 byte): An 8-bit unsigned integer that defines the red intensity value for the palette entry.
  50. int red = leis.readUByte();
  51. colorRef = new Color(red, green, blue);
  52. return 4*LittleEndianConsts.BYTE_SIZE;
  53. }
  54. /**
  55. * Specifies that the logical palette entry be used for palette animation. This value
  56. * prevents other windows from matching colors to the palette entry because the color frequently
  57. * changes. If an unused system-palette entry is available, the color is placed in that entry.
  58. * Otherwise, the color is not available for animation.
  59. */
  60. public boolean isReserved() {
  61. return PC_RESERVED.isSet(values);
  62. }
  63. /**
  64. * Specifies that the low-order word of the logical palette entry designates a hardware
  65. * palette index. This value allows the application to show the contents of the display device palette.
  66. */
  67. public boolean isExplicit() {
  68. return PC_EXPLICIT.isSet(values);
  69. }
  70. /**
  71. * Specifies that the color be placed in an unused entry in the system palette
  72. * instead of being matched to an existing color in the system palette. If there are no unused entries
  73. * in the system palette, the color is matched normally. Once this color is in the system palette,
  74. * colors in other logical palettes can be matched to this color.
  75. */
  76. public boolean isNoCollapse() {
  77. return PC_NOCOLLAPSE.isSet(values);
  78. }
  79. }
  80. public static abstract class WmfPaletteParent implements HwmfRecord, HwmfObjectTableEntry {
  81. /**
  82. * Start (2 bytes): A 16-bit unsigned integer that defines the offset into the Palette Object when
  83. * used with the META_SETPALENTRIES and META_ANIMATEPALETTE record types.
  84. * When used with META_CREATEPALETTE, it MUST be 0x0300
  85. */
  86. protected int start;
  87. protected final List<PaletteEntry> palette = new ArrayList<>();
  88. @Override
  89. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  90. start = leis.readUShort();
  91. int size = readPaletteEntries(leis, -1);
  92. return size + LittleEndianConsts.SHORT_SIZE;
  93. }
  94. protected int readPaletteEntries(LittleEndianInputStream leis, int nbrOfEntries) throws IOException {
  95. /**
  96. * NumberOfEntries (2 bytes): A 16-bit unsigned integer that defines the number of objects in
  97. * aPaletteEntries.
  98. */
  99. final int numberOfEntries = (nbrOfEntries > -1) ? nbrOfEntries : leis.readUShort();
  100. int size = (nbrOfEntries > -1) ? 0 : LittleEndianConsts.SHORT_SIZE;
  101. for (int i=0; i<numberOfEntries; i++) {
  102. PaletteEntry pe = new PaletteEntry();
  103. size += pe.init(leis);
  104. palette.add(pe);
  105. }
  106. return size;
  107. }
  108. @Override
  109. public final void draw(HwmfGraphics ctx) {
  110. ctx.addObjectTableEntry(this);
  111. }
  112. protected List<PaletteEntry> getPaletteCopy() {
  113. List<PaletteEntry> newPalette = new ArrayList<>();
  114. for (PaletteEntry et : palette) {
  115. newPalette.add(new PaletteEntry(et));
  116. }
  117. return newPalette;
  118. }
  119. protected int getPaletteStart() {
  120. return start;
  121. }
  122. }
  123. /**
  124. * The META_CREATEPALETTE record creates a Palette Object
  125. */
  126. public static class WmfCreatePalette extends WmfPaletteParent implements HwmfObjectTableEntry {
  127. @Override
  128. public HwmfRecordType getWmfRecordType() {
  129. return HwmfRecordType.createPalette;
  130. }
  131. @Override
  132. public void applyObject(HwmfGraphics ctx) {
  133. ctx.getProperties().setPalette(getPaletteCopy());
  134. }
  135. }
  136. /**
  137. * The META_SETPALENTRIES record defines RGB color values in a range of entries in the logical
  138. * palette that is defined in the playback device context.
  139. */
  140. public static class WmfSetPaletteEntries extends WmfPaletteParent {
  141. @Override
  142. public HwmfRecordType getWmfRecordType() {
  143. return HwmfRecordType.setPalEntries;
  144. }
  145. @Override
  146. public void applyObject(HwmfGraphics ctx) {
  147. HwmfDrawProperties props = ctx.getProperties();
  148. List<PaletteEntry> palette = props.getPalette();
  149. if (palette == null) {
  150. palette = new ArrayList<>();
  151. }
  152. int start = getPaletteStart();
  153. for (int i=palette.size(); i<start; i++) {
  154. palette.add(new PaletteEntry());
  155. }
  156. int index = start;
  157. for (PaletteEntry palCopy : getPaletteCopy()) {
  158. if (palette.size() <= index) {
  159. palette.add(palCopy);
  160. } else {
  161. palette.set(index, palCopy);
  162. }
  163. index++;
  164. }
  165. props.setPalette(palette);
  166. }
  167. }
  168. /**
  169. * The META_RESIZEPALETTE record redefines the size of the logical palette that is defined in the
  170. * playback device context.
  171. */
  172. public static class WmfResizePalette implements HwmfRecord, HwmfObjectTableEntry {
  173. /**
  174. * A 16-bit unsigned integer that defines the number of entries in
  175. * the logical palette.
  176. */
  177. protected int numberOfEntries;
  178. @Override
  179. public HwmfRecordType getWmfRecordType() {
  180. return HwmfRecordType.resizePalette;
  181. }
  182. @Override
  183. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  184. numberOfEntries = leis.readUShort();
  185. return LittleEndianConsts.SHORT_SIZE;
  186. }
  187. @Override
  188. public void draw(HwmfGraphics ctx) {
  189. ctx.addObjectTableEntry(this);
  190. }
  191. @Override
  192. public void applyObject(HwmfGraphics ctx) {
  193. HwmfDrawProperties props = ctx.getProperties();
  194. List<PaletteEntry> palette = props.getPalette();
  195. if (palette == null) {
  196. palette = new ArrayList<>();
  197. }
  198. for (int i=palette.size(); i<numberOfEntries; i++) {
  199. palette.add(new PaletteEntry());
  200. }
  201. palette = palette.subList(0, numberOfEntries);
  202. props.setPalette(palette);
  203. }
  204. }
  205. /**
  206. * The META_SELECTPALETTE record defines the current logical palette with a specified Palette Object.
  207. */
  208. public static class WmfSelectPalette implements HwmfRecord {
  209. /**
  210. * A 16-bit unsigned integer used to index into the WMF Object Table to get
  211. * the Palette Object to be selected.
  212. */
  213. protected int paletteIndex;
  214. @Override
  215. public HwmfRecordType getWmfRecordType() {
  216. return HwmfRecordType.selectPalette;
  217. }
  218. @Override
  219. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  220. paletteIndex = leis.readUShort();
  221. return LittleEndianConsts.SHORT_SIZE;
  222. }
  223. @Override
  224. public void draw(HwmfGraphics ctx) {
  225. ctx.applyObjectTableEntry(paletteIndex);
  226. }
  227. }
  228. /**
  229. * The META_REALIZEPALETTE record maps entries from the logical palette that
  230. * is defined in the playback device context to the system palette.
  231. */
  232. public static class WmfRealizePalette implements HwmfRecord {
  233. @Override
  234. public HwmfRecordType getWmfRecordType() {
  235. return HwmfRecordType.realizePalette;
  236. }
  237. @Override
  238. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  239. return 0;
  240. }
  241. @Override
  242. public void draw(HwmfGraphics ctx) {
  243. }
  244. }
  245. /**
  246. * The META_ANIMATEPALETTE record redefines entries in the logical palette that
  247. * is defined in the playback device context with the specified Palette object
  248. *
  249. * The logical palette that is specified by the Palette object in this record is the
  250. * source of the palette changes, and the logical palette that is currently selected
  251. * into the playback device context is the destination. Entries in the destination
  252. * palette with the PC_RESERVED PaletteEntryFlag set SHOULD be modified by this record,
  253. * and entries with that flag clear SHOULD NOT be modified.
  254. * If none of the entries in the destination palette have the PC_RESERVED flag set, then
  255. * this record SHOULD have no effect.
  256. */
  257. public static class WmfAnimatePalette extends WmfPaletteParent {
  258. @Override
  259. public HwmfRecordType getWmfRecordType() {
  260. return HwmfRecordType.animatePalette;
  261. }
  262. @Override
  263. public void applyObject(HwmfGraphics ctx) {
  264. HwmfDrawProperties props = ctx.getProperties();
  265. List<PaletteEntry> dest = props.getPalette();
  266. List<PaletteEntry> src = getPaletteCopy();
  267. int start = getPaletteStart();
  268. if (dest == null) {
  269. dest = new ArrayList<>();
  270. }
  271. for (int i=dest.size(); i<start; i++) {
  272. dest.add(new PaletteEntry());
  273. }
  274. for (int i=0; i<src.size(); i++) {
  275. PaletteEntry pe = src.get(i);
  276. if (dest.size() <= start+i) {
  277. dest.add(pe);
  278. } else {
  279. PaletteEntry peDst = dest.get(start+i);
  280. if (peDst.isReserved()) {
  281. dest.set(start+i, pe);
  282. }
  283. }
  284. }
  285. props.setPalette(dest);
  286. }
  287. }
  288. }