(() => GetFormat ("PNG"));
+
+ public override ImageMetaData ReadMetaData (Stream stream)
+ {
+ var header = ResourceHeader.Read (stream);
+ if (null == header)
+ return null;
+ return new DwqMetaData
+ {
+ Width = LittleEndian.ToUInt32 (header.Bytes, 0x24),
+ Height = LittleEndian.ToUInt32 (header.Bytes, 0x28),
+ BPP = 32,
+ BaseType = Encoding.ASCII.GetString (header.Bytes, 0, 0x10).TrimEnd(),
+ PackedSize = LittleEndian.ToInt32 (header.Bytes, 0x20),
+ PackType = header.PackType,
+ AType = header.AType,
+ };
+ }
+
+ public override ImageData Read (Stream stream, ImageMetaData info)
+ {
+ var meta = info as DwqMetaData;
+ if (null == meta)
+ throw new ArgumentException ("DwqFormat.Read should be supplied with DwqMetaData", "info");
+
+ BitmapSource bitmap = null;
+ switch (meta.PackType)
+ {
+ case 5: // JPEG
+ using (var jpeg = new StreamRegion (stream, 0x40, stream.Length-0x40, true))
+ return JpegFormat.Value.Read (jpeg, info);
+
+ case 8: // PNG
+ using (var png = new StreamRegion (stream, 0x40, stream.Length-0x40, true))
+ return PngFormat.Value.Read (png, info);
+
+ case 0: // BMP
+ using (var bmp = new StreamRegion (stream, 0x40, stream.Length-0x40, true))
+ {
+ var decoder = new BmpBitmapDecoder (bmp, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
+ // non-conforming BMP, flip image vertically
+ bitmap = new TransformedBitmap (decoder.Frames[0], new ScaleTransform { ScaleY = -1 });
+ return new ImageData (bitmap, info);
+ }
+
+ case 7: // JPEG+MASK
+ using (var jpeg = new StreamRegion (stream, 0x40, meta.PackedSize, true))
+ {
+ var decoder = new JpegBitmapDecoder (jpeg, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
+ bitmap = decoder.Frames[0];
+ }
+ break;
+
+ case 3: // PACKBMP+MASK
+ using (var bmp = new StreamRegion (stream, 0x40, meta.PackedSize, true))
+ {
+ var reader = new DwqBmpReader (bmp, meta);
+ reader.Unpack();
+ bitmap = BitmapSource.Create ((int)info.Width, (int)info.Height,
+ ImageData.DefaultDpiX, ImageData.DefaultDpiY,
+ reader.Format, reader.Palette, reader.Data, reader.Stride);
+ }
+ break;
+ }
+ if (null == bitmap)
+ throw new NotImplementedException();
+ if (meta.AType)
+ {
+ int mask_offset = 0x40+meta.PackedSize;
+ using (var mask = new StreamRegion (stream, mask_offset, stream.Length-mask_offset, true))
+ {
+ var reader = new DwqBmpReader (mask, meta);
+ if (8 == reader.Format.BitsPerPixel) // mask should be represented as 8bpp bitmap
+ {
+ reader.Unpack();
+ var alpha = reader.Data;
+ var palette = reader.Palette.Colors;
+ for (int i = 0; i < alpha.Length; ++i)
+ {
+ var color = palette[alpha[i]];
+ int A = (color.R + color.G + color.B) / 3;
+ alpha[i] = (byte)A;
+ }
+ bitmap = ApplyAlphaChannel (bitmap, reader.Data);
+ }
+ }
+ }
+ bitmap.Freeze();
+ return new ImageData (bitmap, meta);
+ }
+
+ public override void Write (Stream file, ImageData image)
+ {
+ throw new NotImplementedException ("DwqFormat.Write not implemented");
+ }
+
+ private BitmapSource ApplyAlphaChannel (BitmapSource bitmap, byte[] alpha)
+ {
+ if (bitmap.Format.BitsPerPixel != 32)
+ bitmap = new FormatConvertedBitmap (bitmap, PixelFormats.Bgr32, null, 0);
+
+ int stride = bitmap.PixelWidth * 4;
+ byte[] pixels = new byte[stride * bitmap.PixelHeight];
+ int asrc = 0;
+ bitmap.CopyPixels (pixels, stride, 0);
+ for (int dst = 3; dst < pixels.Length; dst += 4)
+ {
+ pixels[dst] = alpha[asrc++];
+ }
+ return BitmapSource.Create (bitmap.PixelWidth, bitmap.PixelHeight,
+ ImageData.DefaultDpiX, ImageData.DefaultDpiY,
+ PixelFormats.Bgra32, null, pixels, stride);
+ }
+ }
+
+ internal class DwqBmpReader
+ {
+ Stream m_input;
+ byte[] m_pixels;
+ int m_width;
+ int m_height;
+
+ public byte[] Data { get { return m_pixels; } }
+ public int Stride { get; private set; }
+ public PixelFormat Format { get; private set; }
+ public BitmapPalette Palette { get; private set; }
+
+ public DwqBmpReader (Stream input, DwqMetaData info)
+ {
+ m_input = input;
+ m_width = (int)info.Width;
+ m_height = (int)info.Height;
+ var header = new byte[0x36];
+ if (header.Length != m_input.Read (header, 0, header.Length))
+ throw new InvalidFormatException();
+ int w = LittleEndian.ToInt32 (header, 0x12);
+ int h = LittleEndian.ToInt32 (header, 0x16);
+ if (w != m_width || h != m_height)
+ throw new InvalidFormatException();
+
+ int bpp = LittleEndian.ToUInt16 (header, 0x1C);
+ switch (bpp)
+ {
+ case 8: Format = PixelFormats.Indexed8; Stride = m_width; break;
+ case 16: Format = PixelFormats.Bgr565; Stride = m_width*2; break;
+ case 24: Format = PixelFormats.Bgr24; Stride = m_width*3; break;
+ case 32: Format = PixelFormats.Bgr32; Stride = m_width*4; break;
+ default: throw new InvalidFormatException();
+ }
+ if (8 == bpp)
+ {
+ int colors = Math.Min (LittleEndian.ToInt32 (header, 0x2E), 0x100);
+ ReadPalette (colors);
+ }
+ uint data_position = LittleEndian.ToUInt32 (header, 0xA);
+ m_input.Position = data_position;
+ m_pixels = new byte[Stride*m_height];
+ }
+
+ private void ReadPalette (int colors)
+ {
+ int palette_size = colors * 4;
+ var palette_data = new byte[palette_size];
+ if (palette_size != m_input.Read (palette_data, 0, palette_size))
+ throw new InvalidFormatException();
+ var palette = new Color[colors];
+ for (int i = 0; i < palette.Length; ++i)
+ {
+ byte r = palette_data[i*4];
+ byte g = palette_data[i*4+1];
+ byte b = palette_data[i*4+2];
+ palette[i] = Color.FromRgb (r, g, b);
+ }
+ Palette = new BitmapPalette (palette);
+ }
+
+ public void Unpack () // sub_408990
+ {
+ var prev_line = new byte[Stride];
+ int dst = 0;
+ for (int y = 0; y < m_height; ++y)
+ {
+ for (int x = 0; x < Stride; )
+ {
+ int b = m_input.ReadByte();
+ if (0 != b)
+ {
+ if (-1 == b)
+ throw new EndOfStreamException();
+ m_pixels[dst + x++] = (byte)b;
+ }
+ else
+ {
+ int count = m_input.ReadByte();
+ if (-1 == count)
+ throw new EndOfStreamException();
+ for (int i = 0; i < count; ++i)
+ m_pixels[dst + x++] = 0;
+ }
+ }
+ for (int i = 0; i < Stride; ++i)
+ {
+ m_pixels[dst] ^= prev_line[i];
+ prev_line[i] = m_pixels[dst++];
+ }
+ }
+ }
+ }
+}
diff --git a/ArcFormats/Properties/AssemblyInfo.cs b/ArcFormats/Properties/AssemblyInfo.cs
index a7bfbed3..3c117ea7 100644
--- a/ArcFormats/Properties/AssemblyInfo.cs
+++ b/ArcFormats/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion ("1.1.8.87")]
-[assembly: AssemblyFileVersion ("1.1.8.87")]
+[assembly: AssemblyVersion ("1.1.8.88")]
+[assembly: AssemblyFileVersion ("1.1.8.88")]
diff --git a/supported.html b/supported.html
index d5f76c45..1b0e1624 100644
--- a/supported.html
+++ b/supported.html
@@ -37,7 +37,7 @@ Shoujo Settai
*.bin | ACPXPK01 | No | Unison Shift | Wasurenagusa ~Forget-me-Not~ |
*.gsp | - | No | Black Rainbow | Saimin Gakuen |
*.bmz | ZLC3 | Yes |
-*.int | KIF | Yes[1] | CatSystem2 |
+ |
*.int | KIF | Yes | CatSystem2 |
Grisaia no Kajitsu
Makai Tenshi Djibril -Episode 4-
Shukufuku no Campanella
@@ -216,6 +216,7 @@ Mainichi Shabutte Ii Desu ka?
|
*.dat | SPack | No | Goku-Fero | Inchuu Reiki Elenova |
*.fpk | - | No | Candy Soft | Jii -Nozoki no Houshuu- |
*.noa *.dat | Entis\x1a | No | Entis GLS |
+Alea Akaki Tsuki o Haruka ni Nozomi
Konneko
Yatohime Zankikou
|
@@ -286,6 +287,11 @@ Mamagoto
*.iaf | - | No |
*.bin+*.pak | hed | No | elf | Adult Video King |
*.hip *.hiz
| hip hiz | No |
+*.gpk+*.gtb *.vpk+*.vtb | - | No | Black Cyc |
+Yami no Koe Zero
+ |
+*.dwq | BMP JPEG PNG JPEG+MASK PACKBMP+MASK
| No |
+*.vaw *.wgq | IF PACKTYPE== OGG | No |
Non-encrypted only