/*
* Copyright © 2009-2011 Rebecca G. Bettencourt / Kreative Software
* <p>
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* <a href="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</a>
* <p>
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
* <p>
* Alternatively, the contents of this file may be used under the terms
* of the GNU Lesser General Public License (the "LGPL License"), in which
* case the provisions of LGPL License are applicable instead of those
* above. If you wish to allow use of your version of this file only
* under the terms of the LGPL License and not to allow others to use
* your version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the LGPL License. If you do not delete
* the provisions above, a recipient may use your version of this file
* under either the MPL or the LGPL License.
* @since PowerPaint 1.0
* @author Rebecca G. Bettencourt, Kreative Software
*/
package com.kreative.paint.format;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import com.kreative.paint.Canvas;
import com.kreative.paint.form.Form;
import com.kreative.paint.io.Monitor;
public class MacPaintFormat implements Format {
public String getName() { return "MacPaint"; }
public String getExpandedName() { return "MacPaint"; }
public String getExtension() { return "mpnt"; }
public int getMacFileType() { return 0x504E5447; }
public int getMacResourceType() { return 0x504E5447; }
public long getDFFType() { return 0x496D67204D504E54L; }
public MediaType getMediaType() { return MediaType.IMAGE; }
public GraphicType getGraphicType() { return GraphicType.BITMAP; }
public SizeType getSizeType() { return SizeType.FIXED; }
public ColorType getColorType() { return ColorType.BLACK_AND_WHITE; }
public AlphaType getAlphaType() { return AlphaType.OPAQUE; }
public LayerType getLayerType() { return LayerType.FLAT; }
public boolean onlyUponRequest() { return false; }
public int usesMagic() { return 0; }
public boolean acceptsMagic(byte[] start, long length) { return false; }
public boolean acceptsExtension(String ext) { return ext.equalsIgnoreCase("mac") || ext.equalsIgnoreCase("pnt") || ext.equalsIgnoreCase("mpnt") || ext.equalsIgnoreCase("mpt"); }
public boolean acceptsMacFileType(int type) { return type == 0x504E5447; }
public boolean acceptsMacResourceType(int type) { return type == 0x504E5447; }
public boolean acceptsDFFType(long type) { return type == 0x496D67204D504E54L; }
public boolean supportsRead() { return true; }
public boolean usesReadOptionForm() { return false; }
public Form getReadOptionForm() { return null; }
public Canvas read(DataInputStream in, Monitor m) throws IOException {
int p;
in.readFully(new byte[512]);
byte[] data = new byte[51840];
p = 0;
while (p < data.length) {
int v = in.readByte();
if (v < 0) {
int count = -v+1;
byte d = in.readByte();
while (count-- > 0 && p < data.length) {
data[p++] = d;
}
} else {
int count = v+1;
while (count-- > 0 && p < data.length) {
data[p++] = in.readByte();
}
}
}
int[] pixels = new int[414720];
p = 0;
for (byte b : data) {
pixels[p++] = ((b & 0x80) != 0) ? 0xFF000000 : 0xFFFFFFFF;
pixels[p++] = ((b & 0x40) != 0) ? 0xFF000000 : 0xFFFFFFFF;
pixels[p++] = ((b & 0x20) != 0) ? 0xFF000000 : 0xFFFFFFFF;
pixels[p++] = ((b & 0x10) != 0) ? 0xFF000000 : 0xFFFFFFFF;
pixels[p++] = ((b & 0x08) != 0) ? 0xFF000000 : 0xFFFFFFFF;
pixels[p++] = ((b & 0x04) != 0) ? 0xFF000000 : 0xFFFFFFFF;
pixels[p++] = ((b & 0x02) != 0) ? 0xFF000000 : 0xFFFFFFFF;
pixels[p++] = ((b & 0x01) != 0) ? 0xFF000000 : 0xFFFFFFFF;
}
Canvas c = new Canvas(576, 720);
c.get(0).setRGB(0, 0, 576, 720, pixels, 0, 576);
return c;
}
public boolean supportsWrite() { return true; }
public boolean usesWriteOptionForm() { return false; }
public Form getWriteOptionForm() { return null; }
public int approximateFileSize(Canvas c) {
return 32768;
}
public void write(Canvas c, DataOutputStream out, Monitor m) throws IOException {
BufferedImage bi = new BufferedImage(576, 720, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
c.paint(g);
g.dispose();
int[] pixels = new int[414720];
bi.getRGB(0, 0, 576, 720, pixels, 0, 576);
out.write(new byte[512]);
byte[] row = new byte[72];
byte[] runs = new byte[144];
byte[] runs2 = new byte[144];
for (int y = 0, py = 0; y < 720 && py < 414720; y++, py += 576) {
for (int x = 0, px = py, rx = 0; x < 576 && px < 414720 && rx < 72; x += 8, px += 8, rx++) {
row[rx] = 0;
for (int p = 0, pp = px; p < 8 && pp < 414720; p++, pp++) {
row[rx] <<= 1;
if (isOpaque(pixels[pp]) && isBlack(pixels[pp])) row[rx] |= 1;
}
}
int rp = 0;
for (byte b : row) {
if (rp >= 2 && runs[rp-1] == b) {
runs[rp-2]++;
} else {
runs[rp++] = 1;
runs[rp++] = b;
}
}
int rp2 = 0;
int rpc = 0;
for (int i = 0; i < rp; i += 2) {
int cnt = runs[i];
byte b = runs[i+1];
if (cnt > 1) {
runs2[rp2++] = (byte)(-cnt+1);
runs2[rp2++] = b;
rpc = rp2;
} else {
if (rpc == rp2) {
runs2[rp2++] = 0;
runs2[rp2++] = b;
} else {
runs2[rpc]++;
runs2[rp2++] = b;
}
}
}
out.write(runs2, 0, rp2);
}
}
private static boolean isBlack(int pixel) {
int r = ((pixel >>> 16) & 0xFF);
int g = ((pixel >>> 8) & 0xFF);
int b = ((pixel >>> 0) & 0xFF);
int k = (30*r + 59*g + 11*b) / 100;
return (k < 0x80);
}
private static boolean isOpaque(int pixel) {
int a = ((pixel >>> 24) & 0xFF);
return (a >= 0x80);
}
}