/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright @ 2015 Atlassian Pty Ltd
*
* 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 net.java.sip.communicator.impl.osdependent.windows;
import java.awt.image.*;
import java.nio.*;
import com.sun.jna.*;
import com.sun.jna.platform.win32.*;
import com.sun.jna.platform.win32.WinDef.*;
/**
* Image conversion utilities.
*
* Parts of this code are based on AppIcon.java from IntelliJ community.
* Licensed under Apache 2.0, Copyright 2000-2016 JetBrains s.r.o.
*/
public class ImageConverter
{
/**
* Converts the <tt>BufferedImage</tt> to an ICONDIR structure.
* @param src The source image to convert
* @return an ICONDIR structure with the data of the passed source image
*/
public static byte[] writeTransparentIcoImage(BufferedImage src)
{
int bitCount = 32;
int scanline_size = (bitCount * src.getWidth() + 7) / 8;
if ((scanline_size % 4) != 0)
scanline_size += 4 - (scanline_size % 4); // pad scanline to 4 byte
// size.
int t_scanline_size = (src.getWidth() + 7) / 8;
if ((t_scanline_size % 4) != 0)
t_scanline_size += 4 - (t_scanline_size % 4); // pad scanline to 4
// byte size.
int imageSize = 40 + src.getHeight() * scanline_size
+ src.getHeight() * t_scanline_size;
// sizeof(ICONDIR)
// + sizeof(ICONDIRENTRY)
// + (sizeof(BITMAPINFOHEADER)+data)
ByteBuffer bos = ByteBuffer.allocate(6 + 16 + imageSize);
bos.order(ByteOrder.LITTLE_ENDIAN);
// ICONDIR
bos.putShort((short) 0); // reserved
bos.putShort((short) 1); // 1=ICO, 2=CUR
bos.putShort((short) 1); // count
// ICONDIRENTRY
int iconDirEntryWidth = src.getWidth();
int iconDirEntryHeight = src.getHeight();
if (iconDirEntryWidth > 255 || iconDirEntryHeight > 255)
{
iconDirEntryWidth = 0;
iconDirEntryHeight = 0;
}
bos.put((byte) iconDirEntryWidth);
bos.put((byte) iconDirEntryHeight);
bos.put((byte) 0);
bos.put((byte) 0); // reserved
bos.putShort((short) 1); // color planes
bos.putShort((short) bitCount);
bos.putInt(imageSize);
bos.putInt(22); // image offset
// BITMAPINFOHEADER
bos.putInt(40); // size
bos.putInt(src.getWidth());
bos.putInt(2 * src.getHeight());
bos.putShort((short) 1); // planes
bos.putShort((short) bitCount);
bos.putInt(0); // compression
bos.putInt(0); // image size
bos.putInt(0); // x pixels per meter
bos.putInt(0); // y pixels per meter
bos.putInt(0); // colors used, 0 = (1 << bitCount) (ignored)
bos.putInt(0); // colors important
int bit_cache = 0;
int bits_in_cache = 0;
int row_padding = scanline_size - (bitCount * src.getWidth() + 7) / 8;
for (int y = src.getHeight() - 1; y >= 0; y--)
{
for (int x = 0; x < src.getWidth(); x++)
{
int argb = src.getRGB(x, y);
bos.put((byte) (0xff & argb));
bos.put((byte) (0xff & (argb >> 8)));
bos.put((byte) (0xff & (argb >> 16)));
bos.put((byte) (0xff & (argb >> 24)));
}
for (int x = 0; x < row_padding; x++)
bos.put((byte) 0);
}
int t_row_padding = t_scanline_size - (src.getWidth() + 7) / 8;
for (int y = src.getHeight() - 1; y >= 0; y--)
{
for (int x = 0; x < src.getWidth(); x++)
{
int argb = src.getRGB(x, y);
int alpha = 0xff & (argb >> 24);
bit_cache <<= 1;
if (alpha == 0)
bit_cache |= 1;
bits_in_cache++;
if (bits_in_cache >= 8)
{
bos.put((byte) (0xff & bit_cache));
bit_cache = 0;
bits_in_cache = 0;
}
}
if (bits_in_cache > 0)
{
bit_cache <<= (8 - bits_in_cache);
bos.put((byte) (0xff & bit_cache));
bit_cache = 0;
bits_in_cache = 0;
}
for (int x = 0; x < t_row_padding; x++)
bos.put((byte) 0);
}
byte[] result = new byte[bos.position()];
System.arraycopy(bos.array(), 0, result, 0, bos.position());
return result;
}
/**
* Converts an ICONDIR ico to an HICON handle
* @param ico the image data
* @return A Windows HICON handle
*/
public static HICON createIcon(byte[] ico)
{
Memory buffer = new Memory(ico.length);
buffer.write(0, ico, 0, ico.length);
int nSize = 100;
int offset = User32Ex.INSTANCE.LookupIconIdFromDirectoryEx(buffer, true,
nSize, nSize, 0);
if (offset != 0)
{
return User32Ex.INSTANCE.CreateIconFromResourceEx(
buffer.share(offset), new WinDef.DWORD(0), true,
new WinDef.DWORD(0x00030000), nSize, nSize, 0);
}
return null;
}
}