/* * Copyright 2011 Uwe Krueger. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mandelsoft.mand; import com.mandelsoft.io.FileAbstractFile; import com.mandelsoft.io.AbstractFile; import com.mandelsoft.mand.tools.Command; import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import javax.imageio.ImageIO; import com.mandelsoft.mand.cm.Colormap; import com.mandelsoft.mand.mapping.IdentityMapper; import com.mandelsoft.mand.mapping.Mapper; import com.mandelsoft.mand.mapping.Mapping; import com.mandelsoft.mand.cm.ColormapModel; import com.mandelsoft.mand.cm.ColormapModel.ResizeMode; import com.mandelsoft.mand.scan.MandelFolder; import com.mandelsoft.mand.util.MandUtils; /** * * @author Uwe Krueger */ public class MandelData extends Command implements MandelConstants { public interface Part { boolean needsVersionUpdate(); } private AbstractFile file; private MandelInfo info; private Colormap colormap; private Mapping mapping; private Mapper mapper; private MandelRaster raster; private BufferedImage image; private boolean incomplete; // incomplete raster private boolean modified; private boolean partial; private boolean temporary; private int origtype; private MandelData origdata; public MandelData(Colormap cm) { this.colormap=cm; } public MandelData(MandelInfo info) { this.info=info; } public MandelData(MandelInfo info, MandelHeader h, AbstractFile f) { this.info=info; if (h.getType()!=MandelData.C_INFO) { origtype=h.getType(); partial=true; } this.setFile(f); } public MandelData(MandelData data) { this(data.getInfo()); if (data.getColormap()!=null) this.colormap=new Colormap(data.getColormap()); this.mapping=data.getMapping(); this.mapper=data.getMapper(); this.raster=data.getRaster(); this.file=data.file; this.temporary=true; this.origdata=data; } public MandelData(File f) throws IOException { this(false,f); } public MandelData(File f, boolean verbose) throws IOException { this(false,f,verbose); } public MandelData(boolean infoonly, File f) throws IOException { this(infoonly,f,true); } public MandelData(boolean infoonly, File f, boolean verbose) throws IOException { this(infoonly, new FileAbstractFile(f), verbose); } public MandelData(AbstractFile f) throws IOException { this(false,f); } public MandelData(AbstractFile f, boolean verbose) throws IOException { this(false,f,verbose); } public MandelData(boolean infoonly, AbstractFile f) throws IOException { this(infoonly,f,true); } public MandelData(boolean infoonly, AbstractFile f, boolean verbose) throws IOException { read(infoonly,f,verbose); this.file=f; } public MandelData(AbstractFile f, int requested) throws IOException { this(f,requested,true); } public MandelData(AbstractFile f, int requested, boolean verbose) throws IOException { read(f,requested,verbose); this.file=f; } public MandelData(InputStream is) throws IOException { this(false,is); } public MandelData(InputStream is, boolean verbose) throws IOException { this(false,is,verbose); } public MandelData(boolean infoonly, InputStream is) throws IOException { this(infoonly,is,true); } public MandelData(boolean infoonly, InputStream is, boolean verbose) throws IOException { DataInputStream dis=getDataInputStream(is); try { read(infoonly,dis,verbose); } finally { dis.close(); } } public MandelData(InputStream is, int requested) throws IOException { this(is,requested,true); } public MandelData(InputStream is, int requested, boolean verbose) throws IOException { DataInputStream dis=getDataInputStream(is); try { read(dis,requested,verbose); } finally { dis.close(); } } public boolean needsVersionUpdate() { return (info==null?false:info.needsVersionUpdate()) || (colormap==null?false:colormap.needsVersionUpdate()) || (mapping==null?false:mapping.needsVersionUpdate()) || (mapper==null?false:mapper.needsVersionUpdate()) || (raster==null?false:raster.needsVersionUpdate()) ; } public boolean isTemporary() { return temporary; } public void setTemporary(boolean temporary) { this.temporary=temporary; } public boolean isIncomplete() { return incomplete; } public void setIncomplete(boolean incomplete) { this.incomplete=incomplete; } public MandelData getOriginalData() { return origdata; } public boolean isModified() { return modified; } public void setModified(boolean modified) { this.modified=modified; } public boolean isPartial() { return partial; } public int getType() { return (info!=null?C_INFO:0)| (raster!=null?C_RASTER:0)| (colormap!=null?C_COLMAP:0)| (mapping!=null?C_MAPPING:0)| (mapper!=null?C_MAPPER:0)| (image!=null?C_IMAGE:0)| (incomplete?C_INCOMPLETE:0); } public MandelHeader getHeader() { return new MandelHeader(getType()); } public MandelHeader getOrigHeader() { if (origdata!=null) return origdata.getOrigHeader(); if (isPartial()) return new MandelHeader(origtype); return getHeader(); } public MandelData getOrigData() { return origdata; } public String getTypeDesc() { return getHeader().getTypeDesc(); } public AbstractFile getFile() { return file; } public MandelInfo getInfo() { return info; } public Colormap getColormap() { return colormap; } public Mapping getMapping() { return mapping; } public Mapper getMapper() { return mapper; } public MandelRaster getRaster() { return raster; } public void setFile(AbstractFile f) { this.file=f; } public void setColormap(ResizeMode mode, Colormap colormap) { if (this.colormap==colormap) return; if (mapping!=null && colormap!=null && mapping.getTargetSize()!=colormap.getSize()) { if (mapper==null) { if (mapping.getTargetSize()>colormap.getSize()) { throw new MandelException("size does not match: "+ colormap.getSize()+"!="+mapping.getTargetSize()); } else { System.out.println("keep smaller mapping "+mapping.getTargetSize()+ "<"+colormap.getSize()); } } else { // create new mapping System.out.println("create new matching mapping "+ colormap.getSize()+"<-"+mapping.getTargetSize()); updateMapping(mode, colormap.getSize(), colormap, "size does not match and no new mapping creatable: "+ colormap.getSize()+"!="+mapping.getTargetSize()); } } // else { this.colormap=colormap; // if (colormap!=null && colormap.getSize()>=info.getTargetSize() && // mapping==null) { // System.out.println("create identity mapping"); // setMapping(new IdentityMapper().createMapping(raster, colormap.getSize())); // } setModified(true); // } } public Colormap resizeColormap(ResizeMode mode, int size) { if (colormap==null) return null; if (colormap.getSize()==size) return colormap; if (mapping==null) mapping=_createMapping(colormap.getSize()); if (mapping==null) return null; updateMapping(mode,size,colormap,"cannot resize colormap"); return colormap; } private void updateMapping(ResizeMode mode) { if (colormap!=null) updateMapping(mode, colormap.getSize(), colormap,"mapping update failed"); } private Mapping _createMapping(int size) { System.out.println("create mapping for size "+size); //new Throwable().printStackTrace(System.out); return mapper.createMapping(raster,size); } private void updateMapping(ResizeMode mode, int size, Colormap colormap, String errmsg) { // create new mapping Mapping nm=_createMapping(size); if (nm==null) { throw new MandelException(errmsg); } System.out.println("got mapping "+nm.getTargetSize()); Mapping old=mapping; mapping=nm; if (size!=nm.getTargetSize()) { size=nm.getTargetSize(); System.out.println("mapping requests different colormap size: "+size); } if (mapping.getTargetSize()!=colormap.getSize()) { // ColormapDialog d=new ColormapDialog(null,"new",colormap,false); // d.setVisible(true); ColormapModel m=new ColormapModel(colormap); m.setResizeMode(mode); if (old==null || old.getTargetSize()!=colormap.getSize()) { System.out.println("proportional resize raster colormap to "+size); m.resize(size); } else { System.out.println("resize raster colormap to "+size); m.resize(size, old, mapping); } colormap=m.getColormap(); System.out.println("raster colormap resized"); } setColormap(mode,colormap); setModified(true); } public void setMapping(Mapping mapping) { if (colormap!=null && mapping!=null && mapping.getTargetSize()>colormap.getSize()) { throw new MandelException("target size: "+ mapping.getTargetSize()+">"+colormap.getSize()); } if (info!=null && mapping!=null) { if (mapping.getMinIt()>info.getMinIt()) { String msg="min iteration value does not match: "+ mapping.getMinIt()+">"+info.getMinIt(); System.out.println("*** "+msg); if (false) { throw new MandelException(msg); } } if (mapping.getMaxIt()!=info.getMaxIt()) { String msg="max iteration value does not match: "+ mapping.getMaxIt()+"!="+info.getMaxIt(); System.out.println("*** "+msg); if (false) { throw new MandelException(msg); } } } this.mapping=mapping; setModified(true); } public void setMapper(ResizeMode mode, Mapper m) { this.mapper=m; if (m!=null) updateMapping(mode); setModified(true); } public void createMapping(ResizeMode mode) { if (mapper==null) throw new MandelException("cannot create mapping: no mapper set"); if (raster==null) throw new MandelException("cannot create mapping: no raster set"); if (colormap==null) throw new MandelException("cannot create mapping: no colormap set"); updateMapping(mode); } public void setRaster(MandelRaster raster) { if (raster!=null) { if (info.getRX()!=raster.getRX()) { throw new MandelException("raster size does not match "+ raster.getRX()+" != "+info.getRX()); } if (info.getRY()!=raster.getRY()) { throw new MandelException("raster size does not match "+ raster.getRY()+" != "+info.getRY()); } } this.raster=raster; setModified(true); } public MandelRaster createRaster() { if (raster==null) { raster=new MandelRaster(info.getRX(),info.getRY()); setModified(true); } return raster; } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image=image; setModified(true); } /////////////////////////////////////////////////////////////// // io /////////////////////////////////////////////////////////////// public void write(DataOutputStream dos) throws IOException { write(dos,true); } public void write(DataOutputStream dos, boolean verbose) throws IOException { int flags=getType(); if (verbose) System.out.println("writing mandel ("+flags+")..."); dos.writeInt(MAGIC); dos.writeInt(flags); if (info!=null) info.write(dos); if (colormap!=null) colormap.write(dos); if (mapping!=null) mapping.write(dos); if (raster!=null) raster.write(dos); if (mapper!=null) Mapper.IO.write(mapper, dos); if (image!=null) { System.out.println(" writing image..."); ImageIO.write(image, "png", dos); } } public void write(File f) throws IOException { write(f,true); } public void write(File f, boolean verbose) throws IOException { File backup=null; if (f.exists() && !f.isDirectory()) { // first save creation times in not yet set (for old format versions) MandelHeader h=getHeader(); if (h.isRaster()) { if (info.getRasterCreationTime()==0) { info.setRasterCreationTime(f.lastModified()); } } else { if (h.isImage()) { if (info.getImageCreationTime()==0) { info.setImageCreationTime(f.lastModified()); } } } // create backup old old file version backup=new File(f.getParentFile(), f.getName()+"~"); f.renameTo(backup); } try { DataOutputStream dos=new DataOutputStream( new BufferedOutputStream( new FileOutputStream(f))); try { write(dos, verbose); if (backup!=null) { backup.delete(); backup=null; } } finally { dos.close(); } } finally { if (backup!=null) { f.delete(); backup.renameTo(f); } else { MandelFolder.Util.add(f); } } } public void read(DataInputStream dis) throws IOException { read(dis,true); } public void read(DataInputStream dis, boolean verbose) throws IOException { read(false,dis,verbose); } public void read(boolean infoonly, DataInputStream dis) throws IOException { read(infoonly,dis,true); } public void read(boolean infoonly, DataInputStream dis, boolean verbose) throws IOException { read(dis,infoonly?C_INFO:C_ALL, verbose); } public void read(DataInputStream dis, int requested) throws IOException { read(dis,requested,true); } public void read(DataInputStream dis, int requested, boolean verbose) throws IOException { if (verbose) System.out.println("reading mandel "+requested+"..."); int magic=dis.readInt(); if (magic!=MAGIC) throw new IOException("illegal format "+magic+"!="+MAGIC); int flags=origtype=dis.readInt(); //if (verbose) System.out.println(" found "+flags); partial=((flags&~M_META)&~requested)!=0; incomplete=(flags&C_INCOMPLETE)!=0; if (requested!=0 && (flags&C_INFO)!=0) { info=new MandelInfo(); info.read(dis,verbose); requested&=~C_INFO; } else info=null; if (requested!=0 && (flags&C_COLMAP)!=0) { colormap=new Colormap(dis,verbose); requested&=~C_COLMAP; } else colormap=null; if (requested!=0 && (flags&C_MAPPING)!=0) { mapping=new Mapping(); mapping.read(dis,verbose); requested&=~C_MAPPING; } else mapping=null; if (requested!=0 && (flags&C_RASTER)!=0) { raster=new MandelRaster(); raster.read(dis,verbose); requested&=~C_RASTER; } else raster=null; if (requested!=0 && (flags&C_MAPPER)!=0) { mapper=Mapper.IO.read(dis,verbose); requested&=~C_MAPPER; } else mapper=null; if (requested!=0 && (flags&C_IMAGE)!=0) { if (verbose) System.out.println(" reading image..."); image=ImageIO.read(dis); requested&=~C_IMAGE; } else image=null; // handle updates if (info!=null && info.needsVersionUpdate()) info.updateData(this); } public void read(AbstractFile f) throws IOException { read(false,f); } public void read(AbstractFile f, boolean verbose) throws IOException { read(false,f,verbose); } public void read(AbstractFile f, int requested) throws IOException { read(f,requested,true); } public void read(AbstractFile f, int requested, boolean verbose) throws IOException { DataInputStream dis=getDataInputStream(f.getInputStream()); try { read(dis,requested,verbose); } finally { dis.close(); } } public void read(boolean infoonly, AbstractFile f) throws IOException { read(infoonly,f,true); } public void read(boolean infoonly, AbstractFile f, boolean verbose) throws IOException { if (verbose) System.out.println("reading "+f); DataInputStream dis=getDataInputStream(f.getInputStream()); try { read(infoonly,dis,verbose); } finally { dis.close(); } } public void write() throws IOException { if (getFile()==null) throw new IOException("no file set"); if (isPartial()) throw new IOException("partial data"); if (isTemporary()) throw new IOException("temporary data"); if (!getFile().isFile()) throw new IOException("no file"); write(getFile().getFile()); setModified(false); } public void reset() throws IOException { if (getFile()==null) throw new IOException("no file set"); read(getFile()); setModified(false); } /////////////////////////////////////////////////////////////// // static utilities /////////////////////////////////////////////////////////////// static public void createRoot(File f) throws IOException { System.out.println("Creating root data..."); MandelData md=new MandelData(MandUtils.createRoot()); md.write(f); } static private DataInputStream getDataInputStream(InputStream is) { if (is instanceof DataInputStream) return (DataInputStream)is; if (is instanceof BufferedInputStream) return new DataInputStream(is); return new DataInputStream(new BufferedInputStream(is)); } /////////////////////////////////////////////////////////////// // main /////////////////////////////////////////////////////////////// static void print(File f) { try { MandelData md=new MandelData(new FileAbstractFile(f)); System.out.println(md.getTypeDesc()+": "+f); MandelInfo mi=md.getInfo(); System.out.println("xm = "+mi.getXM()); System.out.println("ym = "+mi.getYM()); System.out.println("dx = "+mi.getDX()); System.out.println("dy = "+mi.getDY()); System.out.println("limit = "+mi.getLimitIt()); System.out.println("rx = "+mi.getRX()); System.out.println("ry = "+mi.getRY()); if (mi.getMaxIt()>0) { System.out.println("max it= "+mi.getMaxIt()); System.out.println("min it= "+mi.getMinIt()); System.out.println("num it= "+mi.getNumIt()); System.out.println("time = "+mi.getTime()); } } catch (IOException io) { io.printStackTrace(System.err); Error("cannot read "+f+": "+io); } } static void print(String s) { File f=new File(s); print(f); } static public void main(String[] args) { int c=0; while (args.length>c && args[c].charAt(0)=='-') { for (int i=1; i<args[c].length(); i++) { char opt; switch (opt=args[c].charAt(i)) { case 'r': try { createRoot(new File("0.md")); } catch (IOException io) { Error("cannot create root: "+io); } break; default: Error("illegal option '"+opt+"'"); } } c++; } while (args.length>c) { print(args[c++]); } } }