shared/java/ImageInfo.java (116 lines of code) (raw):
package org.jetbrains.skija;
import lombok.Data;
import lombok.*;
import org.jetbrains.annotations.*;
import org.jetbrains.skija.impl.*;
/**
* <p>Describes pixel dimensions and encoding. Bitmap, Image, Pixmap, and Surface
* can be created from ImageInfo. ImageInfo can be retrieved from Bitmap and
* Pixmap, but not from Image and Surface. For example, Image and Surface
* implementations may defer pixel depth, so may not completely specify ImageInfo.</p>
*
* <p>ImageInfo contains dimensions, the pixel integral width and height. It encodes
* how pixel bits describe alpha, transparency; color components red, blue,
* and green; and ColorSpace, the range and linearity of colors.</p>
*/
@AllArgsConstructor @Data @With
public class ImageInfo {
public final ColorInfo _colorInfo;
public final int _width;
public final int _height;
public static final ImageInfo DEFAULT = new ImageInfo(ColorInfo.DEFAULT, 0, 0);
public ImageInfo(int width, int height, @NotNull ColorType colorType, @NotNull ColorAlphaType alphaType) {
this(new ColorInfo(colorType, alphaType, null), width, height);
}
public ImageInfo(int width, int height, @NotNull ColorType colorType, @NotNull ColorAlphaType alphaType, @Nullable ColorSpace colorSpace) {
this(new ColorInfo(colorType, alphaType, colorSpace), width, height);
}
@ApiStatus.Internal
public ImageInfo(int width, int height, int colorType, int alphaType, long colorSpace) {
this(width, height, ColorType._values[colorType], ColorAlphaType._values[alphaType], colorSpace == 0 ? null : new ColorSpace(colorSpace));
}
/**
* @return ImageInfo with {@link ColorType#N32}
*/
@NotNull @Contract("_, _, _ -> new")
public static ImageInfo makeN32(int width, int height, @NotNull ColorAlphaType alphaType) {
return new ImageInfo(new ColorInfo(ColorType.N32, alphaType, null), width, height);
}
/**
* @return ImageInfo with {@link ColorType#N32}
*/
@NotNull @Contract("_, _, _, _ -> new")
public static ImageInfo makeN32(int width, int height, @NotNull ColorAlphaType alphaType, @Nullable ColorSpace colorSpace) {
return new ImageInfo(new ColorInfo(ColorType.N32, alphaType, colorSpace), width, height);
}
/**
* @return ImageInfo with {@link ColorType#N32} and {@link ColorSpace#getSRGB()}
*
* @see <a href="https://fiddle.skia.org/c/@ImageInfo_MakeS32">https://fiddle.skia.org/c/@ImageInfo_MakeS32</a>
*/
@NotNull @Contract("_, _, _ -> new")
public static ImageInfo makeS32(int width, int height, @NotNull ColorAlphaType alphaType) {
return new ImageInfo(new ColorInfo(ColorType.N32, alphaType, ColorSpace.getSRGB()), width, height);
}
/**
* @return ImageInfo with {@link ColorType#N32} and {@link ColorAlphaType#PREMUL}
*/
@NotNull @Contract("_, _ -> new")
public static ImageInfo makeN32Premul(int width, int height) {
return new ImageInfo(new ColorInfo(ColorType.N32, ColorAlphaType.PREMUL, null), width, height);
}
/**
* @return ImageInfo with {@link ColorType#N32} and {@link ColorAlphaType#PREMUL}
*/
@NotNull @Contract("_, _, _ -> new")
public static ImageInfo makeN32Premul(int width, int height, @Nullable ColorSpace colorSpace) {
return new ImageInfo(new ColorInfo(ColorType.N32, ColorAlphaType.PREMUL, colorSpace), width, height);
}
/**
* @return ImageInfo with {@link ColorType#ALPHA_8} and {@link ColorAlphaType#PREMUL}
*/
@NotNull @Contract("_, _ -> new")
public static ImageInfo makeA8(int width, int height) {
return new ImageInfo(new ColorInfo(ColorType.ALPHA_8, ColorAlphaType.PREMUL, null), width, height);
}
/**
* @return ImageInfo with {@link ColorType#UNKNOWN} and {@link ColorAlphaType#UNKNOWN}
*/
@NotNull @Contract("_, _ -> new")
public static ImageInfo makeUnknown(int width, int height) {
return new ImageInfo(new ColorInfo(ColorType.UNKNOWN, ColorAlphaType.UNKNOWN, null), width, height);
}
@NotNull
public ColorType getColorType() {
return _colorInfo.getColorType();
}
@NotNull
public ImageInfo withColorType(@NotNull ColorType colorType) {
return withColorInfo(_colorInfo.withColorType(colorType));
}
@NotNull
public ColorAlphaType getColorAlphaType() {
return _colorInfo.getAlphaType();
}
@NotNull
public ImageInfo withColorAlphaType(@NotNull ColorAlphaType alphaType) {
return withColorInfo(_colorInfo.withAlphaType(alphaType));
}
@Nullable
public ColorSpace getColorSpace() {
return _colorInfo.getColorSpace();
}
@NotNull
public ImageInfo withColorSpace(@NotNull ColorSpace colorSpace) {
return withColorInfo(_colorInfo.withColorSpace(colorSpace));
}
/**
* @return true if either dimension is zero or smaller
*/
public boolean isEmpty() {
return _width <= 0 || _height <= 0;
}
/**
* <p>Returns true if ColorAlphaType is set to hint that all pixels are opaque; their
* alpha value is implicitly or explicitly 1.0. If true, and all pixels are
* not opaque, Skia may draw incorrectly.</p>
*
* <p>Does not check if ColorType allows alpha, or if any pixel value has
* transparency.</p>
*
* @return true if alphaType is {@link ColorAlphaType#OPAQUE}
*/
public boolean isOpaque() {
return _colorInfo.isOpaque();
}
/**
* @return integral rectangle from (0, 0) to (getWidth(), getHeight())
*/
@NotNull
public IRect getBounds() {
return IRect.makeXYWH(0, 0, _width, _height);
}
/**
* @return true if associated ColorSpace is not null, and ColorSpace gamma
* is approximately the same as sRGB.
*/
public boolean isGammaCloseToSRGB() {
return _colorInfo.isGammaCloseToSRGB();
}
@NotNull
public ImageInfo withWidthHeight(int width, int height) {
return new ImageInfo(_colorInfo, width, height);
}
/**
* Returns number of bytes per pixel required by ColorType.
* Returns zero if {@link #getColorType()} is {@link ColorType#UNKNOWN}.
*
* @return bytes in pixel
*/
public int getBytesPerPixel() {
return _colorInfo.getBytesPerPixel();
}
/**
* Returns bit shift converting row bytes to row pixels.
* Returns zero for {@link ColorType#UNKNOWN}.
*
* @return one of: 0, 1, 2, 3, 4; left shift to convert pixels to bytes
*/
public int getShiftPerPixel() {
return _colorInfo.getShiftPerPixel();
}
/**
* Returns minimum bytes per row, computed from pixel getWidth() and ColorType, which
* specifies getBytesPerPixel(). Bitmap maximum value for row bytes must fit
* in 31 bits.
*/
public long getMinRowBytes() {
return _width * getBytesPerPixel();
}
/**
* <p>Returns byte offset of pixel from pixel base address.</p>
*
* <p>Asserts in debug build if x or y is outside of bounds. Does not assert if
* rowBytes is smaller than {@link #getMinRowBytes()}, even though result may be incorrect.</p>
*
* @param x column index, zero or greater, and less than getWidth()
* @param y row index, zero or greater, and less than getHeight()
* @param rowBytes size of pixel row or larger
* @return offset within pixel array
*
* @see <a href="https://fiddle.skia.org/c/@ImageInfo_computeOffset">https://fiddle.skia.org/c/@ImageInfo_computeOffset</a>
*/
public long computeOffset(int x, int y, long rowBytes) {
return _colorInfo._colorType.computeOffset(x, y, rowBytes);
}
/**
* <p>Returns storage required by pixel array, given ImageInfo dimensions, ColorType,
* and rowBytes. rowBytes is assumed to be at least as large as {@link #getMinRowBytes()}.</p>
*
* <p>Returns zero if height is zero.</p>
*
* @param rowBytes size of pixel row or larger
* @return memory required by pixel buffer
*
* @see <a href="https://fiddle.skia.org/c/@ImageInfo_computeByteSize">https://fiddle.skia.org/c/@ImageInfo_computeByteSize</a>
*/
public long computeByteSize(long rowBytes) {
if (0 == _height) return 0;
return (_height - 1) * rowBytes + _width * getBytesPerPixel();
}
/**
* <p>Returns storage required by pixel array, given ImageInfo dimensions, and
* ColorType. Uses {@link #getMinRowBytes()} to compute bytes for pixel row.</p>
*
* Returns zero if height is zero.
*
* @return least memory required by pixel buffer
*/
public long computeMinByteSize() {
return computeByteSize(getMinRowBytes());
}
/**
* Returns true if rowBytes is valid for this ImageInfo.
*
* @param rowBytes size of pixel row including padding
* @return true if rowBytes is large enough to contain pixel row and is properly aligned
*/
public boolean isRowBytesValid(long rowBytes) {
if (rowBytes < getMinRowBytes())
return false;
int shift = getShiftPerPixel();
return rowBytes >> shift << shift == rowBytes;
}
}