001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.hslf.usermodel;
019:
020: import java.util.*;
021: import java.awt.Dimension;
022: import java.io.*;
023:
024: import org.apache.poi.ddf.EscherBSERecord;
025: import org.apache.poi.ddf.EscherContainerRecord;
026: import org.apache.poi.ddf.EscherOptRecord;
027: import org.apache.poi.ddf.EscherRecord;
028: import org.apache.poi.hslf.*;
029: import org.apache.poi.hslf.model.*;
030: import org.apache.poi.hslf.model.Notes;
031: import org.apache.poi.hslf.model.Slide;
032: import org.apache.poi.hslf.record.SlideListWithText.*;
033: import org.apache.poi.hslf.record.*;
034: import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
035: import org.apache.poi.hslf.exceptions.HSLFException;
036: import org.apache.poi.util.ArrayUtil;
037: import org.apache.poi.util.POILogFactory;
038: import org.apache.poi.util.POILogger;
039:
040: /**
041: * This class is a friendly wrapper on top of the more scary HSLFSlideShow.
042: *
043: * TODO:
044: * - figure out how to match notes to their correct sheet
045: * (will involve understanding DocSlideList and DocNotesList)
046: * - handle Slide creation cleaner
047: *
048: * @author Nick Burch
049: * @author Yegor kozlov
050: */
051:
052: public class SlideShow {
053: // What we're based on
054: private HSLFSlideShow _hslfSlideShow;
055:
056: // Low level contents, as taken from HSLFSlideShow
057: private Record[] _records;
058:
059: // Pointers to the most recent versions of the core records
060: // (Document, Notes, Slide etc)
061: private Record[] _mostRecentCoreRecords;
062: // Lookup between the PersitPtr "sheet" IDs, and the position
063: // in the mostRecentCoreRecords array
064: private Hashtable _sheetIdToCoreRecordsLookup;
065: // Used when adding new core records
066: private int _highestSheetId;
067:
068: // Records that are interesting
069: private Document _documentRecord;
070:
071: // Friendly objects for people to deal with
072: private SlideMaster[] _masters;
073: private TitleMaster[] _titleMasters;
074: private Slide[] _slides;
075: private Notes[] _notes;
076: private FontCollection _fonts;
077:
078: // For logging
079: private POILogger logger = POILogFactory.getLogger(this .getClass());
080:
081: /* ===============================================================
082: * Setup Code
083: * ===============================================================
084: */
085:
086: /**
087: * Constructs a Powerpoint document from the underlying
088: * HSLFSlideShow object. Finds the model stuff from this
089: *
090: * @param hslfSlideShow the HSLFSlideShow to base on
091: */
092: public SlideShow(HSLFSlideShow hslfSlideShow) throws IOException {
093: // Get useful things from our base slideshow
094: _hslfSlideShow = hslfSlideShow;
095: _records = _hslfSlideShow.getRecords();
096:
097: // Handle Parent-aware Reocrds
098: for (int i = 0; i < _records.length; i++) {
099: handleParentAwareRecords(_records[i]);
100: }
101:
102: // Find the versions of the core records we'll want to use
103: findMostRecentCoreRecords();
104:
105: // Build up the model level Slides and Notes
106: buildSlidesAndNotes();
107: }
108:
109: /**
110: * Constructs a new, empty, Powerpoint document.
111: */
112: public SlideShow() throws IOException {
113: this (new HSLFSlideShow());
114: }
115:
116: /**
117: * Constructs a Powerpoint document from an input stream.
118: */
119: public SlideShow(InputStream inputStream) throws IOException {
120: this (new HSLFSlideShow(inputStream));
121: }
122:
123: /**
124: * Find the records that are parent-aware, and tell them
125: * who their parent is
126: */
127: private void handleParentAwareRecords(Record baseRecord) {
128: // Only need to do something if this is a container record
129: if (baseRecord instanceof RecordContainer) {
130: RecordContainer br = (RecordContainer) baseRecord;
131: Record[] childRecords = br.getChildRecords();
132:
133: // Loop over child records, looking for interesting ones
134: for (int i = 0; i < childRecords.length; i++) {
135: Record record = childRecords[i];
136: // Tell parent aware records of their parent
137: if (record instanceof ParentAwareRecord) {
138: ((ParentAwareRecord) record).setParentRecord(br);
139: }
140: // Walk on down for the case of container records
141: if (record instanceof RecordContainer) {
142: handleParentAwareRecords(record);
143: }
144: }
145: }
146: }
147:
148: /**
149: * Use the PersistPtrHolder entries to figure out what is
150: * the "most recent" version of all the core records
151: * (Document, Notes, Slide etc), and save a record of them.
152: * Do this by walking from the oldest PersistPtr to the newest,
153: * overwriting any references found along the way with newer ones
154: */
155: private void findMostRecentCoreRecords() {
156: // To start with, find the most recent in the byte offset domain
157: Hashtable mostRecentByBytes = new Hashtable();
158: for (int i = 0; i < _records.length; i++) {
159: if (_records[i] instanceof PersistPtrHolder) {
160: PersistPtrHolder pph = (PersistPtrHolder) _records[i];
161:
162: // If we've already seen any of the "slide" IDs for this
163: // PersistPtr, remove their old positions
164: int[] ids = pph.getKnownSlideIDs();
165: for (int j = 0; j < ids.length; j++) {
166: Integer id = new Integer(ids[j]);
167: if (mostRecentByBytes.containsKey(id)) {
168: mostRecentByBytes.remove(id);
169: }
170: }
171:
172: // Now, update the byte level locations with their latest values
173: Hashtable this SetOfLocations = pph
174: .getSlideLocationsLookup();
175: for (int j = 0; j < ids.length; j++) {
176: Integer id = new Integer(ids[j]);
177: mostRecentByBytes.put(id, this SetOfLocations
178: .get(id));
179: }
180: }
181: }
182:
183: // We now know how many unique special records we have, so init
184: // the array
185: _mostRecentCoreRecords = new Record[mostRecentByBytes.size()];
186:
187: // We'll also want to be able to turn the slide IDs into a position
188: // in this array
189: _sheetIdToCoreRecordsLookup = new Hashtable();
190: int[] allIDs = new int[_mostRecentCoreRecords.length];
191: Enumeration ids = mostRecentByBytes.keys();
192: for (int i = 0; i < allIDs.length; i++) {
193: Integer id = (Integer) ids.nextElement();
194: allIDs[i] = id.intValue();
195: }
196: Arrays.sort(allIDs);
197: for (int i = 0; i < allIDs.length; i++) {
198: _sheetIdToCoreRecordsLookup.put(new Integer(allIDs[i]),
199: new Integer(i));
200: }
201: // Capture the ID of the highest sheet
202: _highestSheetId = allIDs[(allIDs.length - 1)];
203:
204: // Now convert the byte offsets back into record offsets
205: for (int i = 0; i < _records.length; i++) {
206: if (_records[i] instanceof PositionDependentRecord) {
207: PositionDependentRecord pdr = (PositionDependentRecord) _records[i];
208: Integer recordAt = new Integer(pdr
209: .getLastOnDiskOffset());
210:
211: // Is it one we care about?
212: for (int j = 0; j < allIDs.length; j++) {
213: Integer this ID = new Integer(allIDs[j]);
214: Integer thatRecordAt = (Integer) mostRecentByBytes
215: .get(this ID);
216:
217: if (thatRecordAt.equals(recordAt)) {
218: // Bingo. Now, where do we store it?
219: Integer storeAtI = (Integer) _sheetIdToCoreRecordsLookup
220: .get(this ID);
221: int storeAt = storeAtI.intValue();
222:
223: // Tell it its Sheet ID, if it cares
224: if (pdr instanceof PositionDependentRecordContainer) {
225: PositionDependentRecordContainer pdrc = (PositionDependentRecordContainer) _records[i];
226: pdrc.setSheetId(this ID.intValue());
227: }
228:
229: // Finally, save the record
230: _mostRecentCoreRecords[storeAt] = _records[i];
231: }
232: }
233: }
234: }
235:
236: // Now look for the interesting records in there
237: for (int i = 0; i < _mostRecentCoreRecords.length; i++) {
238: // Check there really is a record at this number
239: if (_mostRecentCoreRecords[i] != null) {
240: // Find the Document, and interesting things in it
241: if (_mostRecentCoreRecords[i].getRecordType() == RecordTypes.Document.typeID) {
242: _documentRecord = (Document) _mostRecentCoreRecords[i];
243: _fonts = _documentRecord.getEnvironment()
244: .getFontCollection();
245: }
246: } else {
247: // No record at this number
248: // Odd, but not normally a problem
249: }
250: }
251: }
252:
253: /**
254: * For a given SlideAtomsSet, return the core record, based on the refID from the
255: * SlidePersistAtom
256: */
257: private Record getCoreRecordForSAS(SlideAtomsSet sas) {
258: SlidePersistAtom spa = sas.getSlidePersistAtom();
259: int refID = spa.getRefID();
260: return getCoreRecordForRefID(refID);
261: }
262:
263: /**
264: * For a given refID (the internal, 0 based numbering scheme), return the
265: * core record
266: * @param refID the refID
267: */
268: private Record getCoreRecordForRefID(int refID) {
269: Integer coreRecordId = (Integer) _sheetIdToCoreRecordsLookup
270: .get(new Integer(refID));
271: if (coreRecordId != null) {
272: Record r = _mostRecentCoreRecords[coreRecordId.intValue()];
273: return r;
274: } else {
275: logger
276: .log(
277: POILogger.ERROR,
278: "We tried to look up a reference to a core record, but there was no core ID for reference ID "
279: + refID);
280: return null;
281: }
282: }
283:
284: /**
285: * Build up model level Slide and Notes objects, from the underlying
286: * records.
287: */
288: private void buildSlidesAndNotes() {
289: // Ensure we really found a Document record earlier
290: // If we didn't, then the file is probably corrupt
291: if (_documentRecord == null) {
292: throw new CorruptPowerPointFileException(
293: "The PowerPoint file didn't contain a Document Record in its PersistPtr blocks. It is probably corrupt.");
294: }
295:
296: // Fetch the SlideListWithTexts in the most up-to-date Document Record
297: //
298: // As far as we understand it:
299: // * The first SlideListWithText will contain a SlideAtomsSet
300: // for each of the master slides
301: // * The second SlideListWithText will contain a SlideAtomsSet
302: // for each of the slides, in their current order
303: // These SlideAtomsSets will normally contain text
304: // * The third SlideListWithText (if present), will contain a
305: // SlideAtomsSet for each Notes
306: // These SlideAtomsSets will not normally contain text
307: //
308: // Having indentified the masters, slides and notes + their orders,
309: // we have to go and find their matching records
310: // We always use the latest versions of these records, and use the
311: // SlideAtom/NotesAtom to match them with the StyleAtomSet
312:
313: SlideListWithText masterSLWT = _documentRecord
314: .getMasterSlideListWithText();
315: SlideListWithText slidesSLWT = _documentRecord
316: .getSlideSlideListWithText();
317: SlideListWithText notesSLWT = _documentRecord
318: .getNotesSlideListWithText();
319:
320: // Find master slides
321: // These can be MainMaster records, but oddly they can also be
322: // Slides or Notes, and possibly even other odd stuff....
323: // About the only thing you can say is that the master details are in
324: // the first SLWT.
325: SlideAtomsSet[] masterSets = new SlideAtomsSet[0];
326: if (masterSLWT != null) {
327: masterSets = masterSLWT.getSlideAtomsSets();
328:
329: ArrayList mmr = new ArrayList();
330: ArrayList tmr = new ArrayList();
331:
332: for (int i = 0; i < masterSets.length; i++) {
333: Record r = getCoreRecordForSAS(masterSets[i]);
334: SlideAtomsSet sas = masterSets[i];
335: int sheetNo = sas.getSlidePersistAtom()
336: .getSlideIdentifier();
337: if (r instanceof org.apache.poi.hslf.record.Slide) {
338: TitleMaster master = new TitleMaster(
339: (org.apache.poi.hslf.record.Slide) r,
340: sheetNo);
341: master.setSlideShow(this );
342: tmr.add(master);
343: } else if (r instanceof org.apache.poi.hslf.record.MainMaster) {
344: SlideMaster master = new SlideMaster(
345: (org.apache.poi.hslf.record.MainMaster) r,
346: sheetNo);
347: master.setSlideShow(this );
348: mmr.add(master);
349: }
350: }
351:
352: _masters = new SlideMaster[mmr.size()];
353: mmr.toArray(_masters);
354:
355: _titleMasters = new TitleMaster[tmr.size()];
356: tmr.toArray(_titleMasters);
357:
358: }
359:
360: // Having sorted out the masters, that leaves the notes and slides
361:
362: // Start by finding the notes records to go with the entries in
363: // notesSLWT
364: org.apache.poi.hslf.record.Notes[] notesRecords;
365: SlideAtomsSet[] notesSets = new SlideAtomsSet[0];
366: Hashtable slideIdToNotes = new Hashtable();
367: if (notesSLWT == null) {
368: // None
369: notesRecords = new org.apache.poi.hslf.record.Notes[0];
370: } else {
371: // Match up the records and the SlideAtomSets
372: notesSets = notesSLWT.getSlideAtomsSets();
373: ArrayList notesRecordsL = new ArrayList();
374: for (int i = 0; i < notesSets.length; i++) {
375: // Get the right core record
376: Record r = getCoreRecordForSAS(notesSets[i]);
377:
378: // Ensure it really is a notes record
379: if (r instanceof org.apache.poi.hslf.record.Notes) {
380: org.apache.poi.hslf.record.Notes notesRecord = (org.apache.poi.hslf.record.Notes) r;
381: notesRecordsL.add(notesRecord);
382:
383: // Record the match between slide id and these notes
384: SlidePersistAtom spa = notesSets[i]
385: .getSlidePersistAtom();
386: Integer slideId = new Integer(spa
387: .getSlideIdentifier());
388: slideIdToNotes.put(slideId, new Integer(i));
389: } else {
390: logger.log(POILogger.ERROR,
391: "A Notes SlideAtomSet at "
392: + i
393: + " said its record was at refID "
394: + notesSets[i]
395: .getSlidePersistAtom()
396: .getRefID()
397: + ", but that was actually a " + r);
398: }
399: }
400: notesRecords = new org.apache.poi.hslf.record.Notes[notesRecordsL
401: .size()];
402: notesRecords = (org.apache.poi.hslf.record.Notes[]) notesRecordsL
403: .toArray(notesRecords);
404: }
405:
406: // Now, do the same thing for our slides
407: org.apache.poi.hslf.record.Slide[] slidesRecords;
408: SlideAtomsSet[] slidesSets = new SlideAtomsSet[0];
409: if (slidesSLWT == null) {
410: // None
411: slidesRecords = new org.apache.poi.hslf.record.Slide[0];
412: } else {
413: // Match up the records and the SlideAtomSets
414: slidesSets = slidesSLWT.getSlideAtomsSets();
415: slidesRecords = new org.apache.poi.hslf.record.Slide[slidesSets.length];
416: for (int i = 0; i < slidesSets.length; i++) {
417: // Get the right core record
418: Record r = getCoreRecordForSAS(slidesSets[i]);
419:
420: // Ensure it really is a slide record
421: if (r instanceof org.apache.poi.hslf.record.Slide) {
422: slidesRecords[i] = (org.apache.poi.hslf.record.Slide) r;
423: } else {
424: logger.log(POILogger.ERROR,
425: "A Slide SlideAtomSet at "
426: + i
427: + " said its record was at refID "
428: + slidesSets[i]
429: .getSlidePersistAtom()
430: .getRefID()
431: + ", but that was actually a " + r);
432: }
433: }
434: }
435:
436: // Finally, generate model objects for everything
437: // Notes first
438: _notes = new Notes[notesRecords.length];
439: for (int i = 0; i < _notes.length; i++) {
440: _notes[i] = new Notes(notesRecords[i]);
441: _notes[i].setSlideShow(this );
442: }
443: // Then slides
444: _slides = new Slide[slidesRecords.length];
445: for (int i = 0; i < _slides.length; i++) {
446: SlideAtomsSet sas = slidesSets[i];
447: int slideIdentifier = sas.getSlidePersistAtom()
448: .getSlideIdentifier();
449:
450: // Do we have a notes for this?
451: Notes notes = null;
452: //Slide.SlideAtom.notesId references the corresponding notes slide. 0 if slide has no notes.
453: int noteId = slidesRecords[i].getSlideAtom().getNotesID();
454: if (noteId != 0) {
455: Integer notesPos = (Integer) slideIdToNotes
456: .get(new Integer(noteId));
457: if (notesPos != null)
458: notes = _notes[notesPos.intValue()];
459: else
460: logger.log(POILogger.ERROR,
461: "Notes not found for noteId=" + noteId);
462: }
463:
464: // Now, build our slide
465: _slides[i] = new Slide(slidesRecords[i], notes, sas,
466: slideIdentifier, (i + 1));
467: _slides[i].setSlideShow(this );
468: }
469: }
470:
471: /**
472: * Writes out the slideshow file the is represented by an instance of
473: * this class
474: * @param out The OutputStream to write to.
475: * @throws IOException If there is an unexpected IOException from the passed
476: * in OutputStream
477: */
478: public void write(OutputStream out) throws IOException {
479: _hslfSlideShow.write(out);
480: }
481:
482: /* ===============================================================
483: * Accessor Code
484: * ===============================================================
485: */
486:
487: /**
488: * Returns an array of the most recent version of all the interesting
489: * records
490: */
491: public Record[] getMostRecentCoreRecords() {
492: return _mostRecentCoreRecords;
493: }
494:
495: /**
496: * Returns an array of all the normal Slides found in the slideshow
497: */
498: public Slide[] getSlides() {
499: return _slides;
500: }
501:
502: /**
503: * Returns an array of all the normal Notes found in the slideshow
504: */
505: public Notes[] getNotes() {
506: return _notes;
507: }
508:
509: /**
510: * Returns an array of all the normal Slide Masters found in the slideshow
511: */
512: public SlideMaster[] getSlidesMasters() {
513: return _masters;
514: }
515:
516: /**
517: * Returns an array of all the normal Title Masters found in the slideshow
518: */
519: public TitleMaster[] getTitleMasters() {
520: return _titleMasters;
521: }
522:
523: /**
524: * Returns the data of all the pictures attached to the SlideShow
525: */
526: public PictureData[] getPictureData() {
527: return _hslfSlideShow.getPictures();
528: }
529:
530: /**
531: * Return the current page size
532: */
533: public Dimension getPageSize() {
534: DocumentAtom docatom = _documentRecord.getDocumentAtom();
535: int pgx = (int) docatom.getSlideSizeX() * Shape.POINT_DPI
536: / Shape.MASTER_DPI;
537: int pgy = (int) docatom.getSlideSizeY() * Shape.POINT_DPI
538: / Shape.MASTER_DPI;
539: return new Dimension(pgx, pgy);
540: }
541:
542: /**
543: * Change the current page size
544: *
545: * @param pgsize page size (in points)
546: */
547: public void setPageSize(Dimension pgsize) {
548: DocumentAtom docatom = _documentRecord.getDocumentAtom();
549: docatom.setSlideSizeX(pgsize.width * Shape.MASTER_DPI
550: / Shape.POINT_DPI);
551: docatom.setSlideSizeY(pgsize.height * Shape.MASTER_DPI
552: / Shape.POINT_DPI);
553: }
554:
555: /**
556: * Helper method for usermodel: Get the font collection
557: */
558: protected FontCollection getFontCollection() {
559: return _fonts;
560: }
561:
562: /**
563: * Helper method for usermodel and model: Get the document record
564: */
565: public Document getDocumentRecord() {
566: return _documentRecord;
567: }
568:
569: /* ===============================================================
570: * Re-ordering Code
571: * ===============================================================
572: */
573:
574: /**
575: * Re-orders a slide, to a new position.
576: * @param oldSlideNumer The old slide number (1 based)
577: * @param newSlideNumber The new slide number (1 based)
578: */
579: public void reorderSlide(int oldSlideNumer, int newSlideNumber) {
580: // Ensure these numbers are valid
581: if (oldSlideNumer < 1 || newSlideNumber < 1) {
582: throw new IllegalArgumentException(
583: "Old and new slide numbers must be greater than 0");
584: }
585: if (oldSlideNumer > _slides.length
586: || newSlideNumber > _slides.length) {
587: throw new IllegalArgumentException(
588: "Old and new slide numbers must not exceed the number of slides ("
589: + _slides.length + ")");
590: }
591:
592: // Shift the SlideAtomsSet
593: SlideListWithText slwt = _documentRecord
594: .getSlideSlideListWithText();
595: slwt.repositionSlideAtomsSet(
596: slwt.getSlideAtomsSets()[(oldSlideNumer - 1)],
597: (newSlideNumber - 1));
598:
599: // Re-order the slides
600: ArrayUtil.arrayMoveWithin(_slides, (oldSlideNumer - 1),
601: (newSlideNumber - 1), 1);
602:
603: // Tell the appropriate slides their new numbers
604: for (int i = 0; i < _slides.length; i++) {
605: _slides[i].setSlideNumber((i + 1));
606: }
607: }
608:
609: /* ===============================================================
610: * Addition Code
611: * ===============================================================
612: */
613:
614: /**
615: * Create a blank <code>Slide</code>.
616: *
617: * @return the created <code>Slide</code>
618: * @throws IOException
619: */
620: public Slide createSlide() throws IOException {
621: SlideListWithText slist = null;
622:
623: // We need to add the records to the SLWT that deals
624: // with Slides.
625: // Add it, if it doesn't exist
626: slist = _documentRecord.getSlideSlideListWithText();
627: if (slist == null) {
628: // Need to add a new one
629: slist = new SlideListWithText();
630: _documentRecord.addSlideListWithText(slist);
631: }
632:
633: // Grab the SlidePersistAtom with the highest Slide Number.
634: // (Will stay as null if no SlidePersistAtom exists yet in
635: // the slide, or only master slide's ones do)
636: SlidePersistAtom prev = null;
637: SlideAtomsSet[] sas = slist.getSlideAtomsSets();
638: for (int j = 0; j < sas.length; j++) {
639: SlidePersistAtom spa = sas[j].getSlidePersistAtom();
640: if (spa.getSlideIdentifier() < 0) {
641: // This is for a master slide
642: // Odd, since we only deal with the Slide SLWT
643: } else {
644: // Must be for a real slide
645: if (prev == null) {
646: prev = spa;
647: }
648: if (prev.getSlideIdentifier() < spa
649: .getSlideIdentifier()) {
650: prev = spa;
651: }
652: }
653: }
654:
655: // Set up a new SlidePersistAtom for this slide
656: SlidePersistAtom sp = new SlidePersistAtom();
657:
658: // Reference is the 1-based index of the slide container in
659: // the PersistPtr root.
660: // It always starts with 3 (1 is Document, 2 is MainMaster, 3 is
661: // the first slide), but quicksaves etc can leave gaps
662: _highestSheetId++;
663: sp.setRefID(_highestSheetId);
664: // First slideId is always 256
665: sp.setSlideIdentifier(prev == null ? 256 : (prev
666: .getSlideIdentifier() + 1));
667:
668: // Add this new SlidePersistAtom to the SlideListWithText
669: slist.addSlidePersistAtom(sp);
670:
671: // Create a new Slide
672: Slide slide = new Slide(sp.getSlideIdentifier(), sp.getRefID(),
673: _slides.length + 1);
674: // Add in to the list of Slides
675: Slide[] s = new Slide[_slides.length + 1];
676: System.arraycopy(_slides, 0, s, 0, _slides.length);
677: s[_slides.length] = slide;
678: _slides = s;
679: logger.log(POILogger.INFO, "Added slide " + _slides.length
680: + " with ref " + sp.getRefID() + " and identifier "
681: + sp.getSlideIdentifier());
682:
683: // Add the core records for this new Slide to the record tree
684: org.apache.poi.hslf.record.Slide slideRecord = slide
685: .getSlideRecord();
686: slideRecord.setSheetId(sp.getRefID());
687: int slideRecordPos = _hslfSlideShow
688: .appendRootLevelRecord(slideRecord);
689: _records = _hslfSlideShow.getRecords();
690:
691: // Add the new Slide into the PersistPtr stuff
692: int offset = 0;
693: int slideOffset = 0;
694: PersistPtrHolder ptr = null;
695: UserEditAtom usr = null;
696: for (int i = 0; i < _records.length; i++) {
697: Record record = _records[i];
698: ByteArrayOutputStream out = new ByteArrayOutputStream();
699: record.writeOut(out);
700:
701: // Grab interesting records as they come past
702: if (_records[i].getRecordType() == RecordTypes.PersistPtrIncrementalBlock.typeID) {
703: ptr = (PersistPtrHolder) _records[i];
704: }
705: if (_records[i].getRecordType() == RecordTypes.UserEditAtom.typeID) {
706: usr = (UserEditAtom) _records[i];
707: }
708:
709: if (i == slideRecordPos) {
710: slideOffset = offset;
711: }
712: offset += out.size();
713: }
714:
715: // Add the new slide into the last PersistPtr
716: // (Also need to tell it where it is)
717: slideRecord.setLastOnDiskOffset(slideOffset);
718: ptr.addSlideLookup(sp.getRefID(), slideOffset);
719: logger.log(POILogger.INFO, "New slide ended up at "
720: + slideOffset);
721:
722: // Last view is now of the slide
723: usr.setLastViewType((short) UserEditAtom.LAST_VIEW_SLIDE_VIEW);
724: usr.setMaxPersistWritten(_highestSheetId);
725:
726: // All done and added
727: slide.setSlideShow(this );
728: return slide;
729: }
730:
731: /**
732: * Adds a picture to this presentation and returns the associated index.
733: *
734: * @param data picture data
735: * @param format the format of the picture. One of constans defined in the <code>Picture</code> class.
736: * @return the index to this picture (1 based).
737: */
738: public int addPicture(byte[] data, int format) throws IOException {
739: byte[] uid = PictureData.getChecksum(data);
740:
741: EscherContainerRecord bstore;
742: int offset = 0;
743:
744: EscherContainerRecord dggContainer = _documentRecord
745: .getPPDrawingGroup().getDggContainer();
746: bstore = (EscherContainerRecord) Shape.getEscherChild(
747: dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
748: if (bstore == null) {
749: bstore = new EscherContainerRecord();
750: bstore.setRecordId(EscherContainerRecord.BSTORE_CONTAINER);
751:
752: List child = dggContainer.getChildRecords();
753: for (int i = 0; i < child.size(); i++) {
754: EscherRecord rec = (EscherRecord) child.get(i);
755: if (rec.getRecordId() == EscherOptRecord.RECORD_ID) {
756: child.add(i, bstore);
757: i++;
758: }
759: }
760: dggContainer.setChildRecords(child);
761: } else {
762: List lst = bstore.getChildRecords();
763: for (int i = 0; i < lst.size(); i++) {
764: EscherBSERecord bse = (EscherBSERecord) lst.get(i);
765: if (Arrays.equals(bse.getUid(), uid)) {
766: return i + 1;
767: }
768: offset += bse.getSize();
769: }
770: }
771:
772: PictureData pict = PictureData.create(format);
773: pict.setData(data);
774: pict.setOffset(offset);
775:
776: EscherBSERecord bse = new EscherBSERecord();
777: bse.setRecordId(EscherBSERecord.RECORD_ID);
778: bse.setOptions((short) (0x0002 | (format << 4)));
779: bse.setSize(pict.getRawData().length + 8);
780: bse.setUid(uid);
781:
782: bse.setBlipTypeMacOS((byte) format);
783: bse.setBlipTypeWin32((byte) format);
784:
785: if (format == Picture.EMF)
786: bse.setBlipTypeMacOS((byte) Picture.PICT);
787: else if (format == Picture.WMF)
788: bse.setBlipTypeMacOS((byte) Picture.PICT);
789: else if (format == Picture.PICT)
790: bse.setBlipTypeWin32((byte) Picture.WMF);
791:
792: bse.setRef(1);
793: bse.setOffset(offset);
794:
795: bstore.addChildRecord(bse);
796: int count = bstore.getChildRecords().size();
797: bstore.setOptions((short) ((count << 4) | 0xF));
798:
799: _hslfSlideShow.addPicture(pict);
800:
801: return count;
802: }
803:
804: /**
805: * Adds a picture to this presentation and returns the associated index.
806: *
807: * @param pict the file containing the image to add
808: * @param format the format of the picture. One of constans defined in the <code>Picture</code> class.
809: * @return the index to this picture (1 based).
810: */
811: public int addPicture(File pict, int format) throws IOException {
812: int length = (int) pict.length();
813: byte[] data = new byte[length];
814: try {
815: FileInputStream is = new FileInputStream(pict);
816: is.read(data);
817: is.close();
818: } catch (IOException e) {
819: throw new HSLFException(e);
820: }
821: return addPicture(data, format);
822: }
823: }
|