Common API Overview
Main Class Analysis
PAGLayer
PAGLayer serves as the rendering layer for PAG, which is a tree-like structure. PAGLayer is essentially the leaf node of this structure. The available rendering layers in PAG consist of PAGImageLayer (image layer), PAGTextLayer (text layer), and PAGSolidLayer (solid layer). It is important to note that only these layers can be edited and modified twice.
PAGLayer mainly provides the following capabilities:
Taking the C++layer interface as an example (PAG's external interface maintains consistency across platforms), you can control the displacement, scaling, and distortion of the layer with setMatrix. The visibility of the layer can be managed with setVisible, and you can obtain the layer's specific time relative to the main rendering timeline using localTimeToGlobal. Additionally, you can set the layer's start time relative to the main timeline with setStartTime. By setting setExcludedFromTimeline, you can control whether the rendering of this layer deviates from the main timeline and is controlled by the caller.
// C++
/**
* A matrix object containing values that alter the scaling, rotation, and translation of the
* layer. Altering it does not change the animation matrix, and it will be concatenated to current
* animation matrix for displaying.
*/
Matrix matrix() const;
void setMatrix(const Matrix& value);
/**
* Whether or not the layer is visible.
*/
bool visible() const;
/**
* Set the visible of the layer.
*/
void setVisible(bool value);
/**
* Converts the time from the PAGLayer's (local) timeline to the PAGSurface (global) timeline. The
* time is in microseconds.
*/
int64_t localTimeToGlobal(int64_t localTime) const;
/**
* Converts the time from the PAGSurface (global) to the PAGLayer's (local) timeline timeline. The
* time is in microseconds.
*/
int64_t globalToLocalTime(int64_t globalTime) const;
/**
* The start time of the layer in microseconds, indicates the start position of the visible range
* in parent composition. It could be negative value.
*/
int64_t startTime() const;
/**
* Set the start time of the layer, in microseconds.
*/
void setStartTime(int64_t time);
/**
* Indicate whether this layer is excluded from parent's timeline. If set to true, this layer's
* current time will not change when parent's current time changes.
*/
bool excludedFromTimeline() const;
/**
* Set the excludedFromTimeline flag of this layer.
*/
void setExcludedFromTimeline(bool value);
PAGImageLayer
PAGImageView is an image layer that enables you to replace the default placeholder image using the replaceImage method. You can also retrieve the data of the default placeholder image through imageBytes. Please note that PAG SDK is primarily focused on animation rendering and does not include features for audio and video editing. The Community Edition of PAG does not support the replacement of placeholder images for videos. However, if you require this feature, you can access the PAG Enterprise Edition.
// C++
/**
* Replace the original image content with the specified PAGImage object.
* Passing in null for the image parameter resets the layer to its default image content.
* The setImage() method only modifies the content of the calling PAGImageLayer.
*
* @param image The PAGImage object to replace with.
*/
void setImage(std::shared_ptr<PAGImage> image);
/**
* The default image data of this layer, which is webp format.
*/
ByteData* imageBytes() const;
The PAGImageLayer feature allows users to create customized video layers by setting their start time and duration. Additionally, it is possible to incorporate external videos into PAG rendering data, making it a useful tool for many common application scenarios.
/**
* Make a PAGImageLayer with with, height and duration(in microseconds).
*/
static std::shared_ptr<PAGImageLayer> Make(int width, int height, int64_t duration);
PAGTextLayer
PAGTextLayer is a helpful tool that allows users to customize their text. It enables modifications to default text information, text color, font type, font size and more.
// C++
/**
* Returns the text layer’s fill color.
*/
Color fillColor() const;
/**
* Set the text layer’s fill color.
*/
void setFillColor(const Color& value);
/**
* Returns the text layer's font.
*/
PAGFont font() const;
/**
* Set the text layer's font.
*/
void setFont(const PAGFont& font);
/**
* Returns the text layer's font size.
*/
float fontSize() const;
/**
* Set the text layer's font size.
*/
void setFontSize(float size);
/**
* Returns the text layer's stroke color.
*/
Color strokeColor() const;
/**
* Set the text layer's stroke color.
*/
void setStrokeColor(const Color& color);
/**
* Returns the text layer's text.
*/
std::string text() const;
/**
* Set the text layer's text.
*/
void setText(const std::string& text);
C++ has made it easier to modify text data by encapsulating the TextDocument class. This class allows users to adjust the typesetting, italicization, and stroke information of text. It corresponds to the PAGText class found on iOS and Android platforms.
/**
* When true, the text layer shows a fill.
*/
bool applyFill = true;
/**
* When true, the text layer shows a stroke.
*/
bool applyStroke = false;
/**
* Readonly, external modifications are not valid.
*/
float baselineShift = 0;
/**
* When true, the text layer is paragraph (bounded) text.
* Readonly, external modifications are not valid.
*/
bool boxText = false;
/**
* Readonly, external modifications are not valid.
*/
Point boxTextPos = Point::Zero();
/**
* For box text, the pixel dimensions for the text bounds.
* Readonly, external modifications are not valid.
*/
Point boxTextSize = Point::Zero();
/**
* Readonly, external modifications are not valid.
*/
float firstBaseLine = 0;
bool fauxBold = false;
bool fauxItalic = false;
/**
* The text layer’s fill color.
*/
Color fillColor = Black;
/**
* A string with the name of the font family.
**/
std::string fontFamily = "";
/**
* A string with the style information — e.g., “bold”, “italic”.
**/
std::string fontStyle = "";
/**
* The text layer’s font size in pixels.
*/
float fontSize = 24;
/**
* The text layer’s stroke color.
*/
Color strokeColor = Black;
/**
* Indicates the rendering order for the fill and stroke of a text layer.
* Readonly, external modifications are not valid.
*/
bool strokeOverFill = true;
/**
* The text layer’s stroke thickness.
*/
float strokeWidth = 1;
/**
* The text layer’s Source Text value.
*/
std::string text = "";
/**
* The paragraph justification for the text layer.
*/
Enum justification = ParagraphJustification::LeftJustify;
/**
* The space between lines, 0 indicates 'auto', which is fontSize * 1.2
*/
float leading = 0;
/**
* The text layer’s spacing between characters.
*/
float tracking = 0;
/**
* The text layer’s background color
*/
Color backgroundColor = White;
PAGSolidLayer
PAGSolidLayer is a solid layer that supports color modification.
// C++
/**
* Returns the layer's solid color.
*/
Color solidColor();
/**
* Set the the layer's solid color.
*/
void setSolidColor(const Color& value);
PAGCompostion
The PAGComponent is a container in the rendering tree that inherits from PAGLayers. It can hold multiple PAGLayers, allowing for easy user creation. Additionally, it supports the addition, deletion and replacement of rendering sequences, and allows users to obtain the corresponding layer-by-layer name.
// C++
/**
* Returns the number of child layers of this composition.
*/
int numChildren() const;
/**
* Returns the child layer that exists at the specified index.
* @param index The index position of the child layer.
* @returns The child layer at the specified index position.
*/
std::shared_ptr<PAGLayer> getLayerAt(int index) const;
/**
* Returns the index position of a child layer.
* @param pagLayer The layer instance to identify.
* @returns The index position of the child layer to identify.
*/
int getLayerIndex(std::shared_ptr<PAGLayer> pagLayer) const;
/**
* Changes the position of an existing child layer in the composition. This affects the layering
* of child layers.
* @param pagLayer The child layer for which you want to change the index number.
* @param index The resulting index number for the child layer.
*/
void setLayerIndex(std::shared_ptr<PAGLayer> pagLayer, int index);
/**
* Add a PAGLayer to current PAGComposition at the top. If you add a layer that already has a
* different PAGComposition object as a parent, the layer is removed from the other PAGComposition
* object.
*/
bool addLayer(std::shared_ptr<PAGLayer> pagLayer);
/**
* Add a PAGLayer to current PAGComposition at the specified index. If you add a layer that
* already has a different PAGComposition object as a parent, the layer is removed from the other
* PAGComposition object.
*/
bool addLayerAt(std::shared_ptr<PAGLayer> pagLayer, int index);
/**
* Check whether current PAGComposition contains the specified pagLayer.
*/
bool contains(std::shared_ptr<PAGLayer> pagLayer) const;
/**
* Remove the specified PAGLayer from current PAGComposition.
*/
std::shared_ptr<PAGLayer> removeLayer(std::shared_ptr<PAGLayer> pagLayer);
/**
* Remove the PAGLayer at specified index from current PAGComposition.
*/
std::shared_ptr<PAGLayer> removeLayerAt(int index);
/**
* Remove all PAGLayers from current PAGComposition.
*/
void removeAllLayers();
/**
* Swap the layers.
*/
void swapLayer(std::shared_ptr<PAGLayer> pagLayer1, std::shared_ptr<PAGLayer> pagLayer2);
/**
* Swap the layers at the specified index.
*/
void swapLayerAt(int index1, int index2);
PAGFile
PAGFile is a subclass of PAGComposition that cannot be created on its own. It can only be obtained by loading a pag file. Compared with PAGComposition, PAGFile offers an additional interface for replacing the content of both the text and image layers. This means that if you need to edit the content of the text or image layer, you can use either the layer's interface or the PAGFile interface.
// C++
/**
* Replace the text data of the specified index. The index ranges from 0 to PAGFile.numTexts - 1.
* Passing in null for the textData parameter will reset it to default text data.
*/
void replaceText(int editableTextIndex, std::shared_ptr<TextDocument> textData);
/**
* Replace file's image content of the specified index with a PAGImage object. The index ranges from
* 0 to PAGFile.numImages - 1. Passing in null for the image parameter will reset it to default
* image content.
*/
void replaceImage(int editableImageIndex, std::shared_ptr<PAGImage> image);
/**
* Replace file's image content of the specified layer name with a PAGImage object.
* Passing in null for the image parameter will reset it to default image content.
*/
void replaceImageByName(const std::string& layerName, std::shared_ptr<PAGImage> image);
PAGSurface
PAGSurface serves as the rendering canvas for PAG. The creation of PAGSurface is possible on iOS platforms through CVPixelBufferRef and size (internally, CVPixelBufferRef is also created), and on Android platforms through Surface, SurfaceTexture, TextureID, size, etc. The chosen creation method depends on the application scenario. PAGSurface offers an interface for obtaining single-frame rendering data and allows for the acquisition of BGRA data, CVPixelBufferRef, and Bitmap.
// OC
/**
* Creates a new PAGSurface from specified CAEAGLLayer. The GPU context will be created internally
* by PAGSurface.
*/
+ (PAGSurface*)FromLayer:(CAEAGLLayer*)layer;
/**
* Creates a new PAGSurface from specified CVPixelBuffer. The GPU context will be created internally
* by PAGSurface.
*/
+ (PAGSurface*)FromCVPixelBuffer:(CVPixelBufferRef)pixelBuffer;
/**
* Creates a new PAGSurface from specified CVPixelBuffer and EAGLContext. Multiple PAGSurfaces with
* the same context share the same GPU caches. The caches are not destroyed when resetting a
* PAGPlayer's surface to another PAGSurface with the same context.
*/
+ (PAGSurface*)FromCVPixelBuffer:(CVPixelBufferRef)pixelBuffer context:(EAGLContext*)eaglContext;
/**
* Creates a offscreen PAGSurface of specified size. PAGSurface internally creates a CVPixelBuffer
* which can be accessed by [PAGSurface getCVPixelBuffer] after the first [PAGPLayer flush].
*/
+ (PAGSurface*)MakeOffscreen:(CGSize)size;
/**
* Returns the internal CVPixelBuffer object associated with this PAGSurface, returns nil if this
* PAGSurface is created by [PAGSurface FromLayer].
*/
- (CVPixelBufferRef)getCVPixelBuffer;
/**
* Returns a CVPixelBuffer object capturing the contents of the PAGSurface. Subsequent rendering of
* the PAGSurface will not be captured.
*/
- (CVPixelBufferRef)makeSnapshot;
/**
* Copies the pixels of the PAGSurface to the specified memory address. The format of the copied
* pixels is in the BGRA color type with the premultiplied alpha type. Returns false if failed.
*/
- (BOOL)copyPixelsTo:(void*)pixels rowBytes:(size_t)rowBytes;
// java
public static PAGSurface MakeOffscreen(int width, int height);
public static PAGSurface FromSurfaceTexture(SurfaceTexture surfaceTexture);
public static PAGSurface FromSurfaceTexture(SurfaceTexture surfaceTexture, EGLContext shareContext);
public static PAGSurface FromSurface(Surface surface);
/**
* Create a PAGSurface from specified OpenGL texture, return null if there is no current OpenGL context or the
* texture is invalid. Note:
* 1. The target of texture must be GL_TEXTURE_2D.
* 2. The texture should not bind to any frameBuffer.
* 3. PAG will use the current (OpenGL) context.
*/
public static PAGSurface FromTexture(int textureID, int width, int height);
/**
* Create a PAGSurface from specified OpenGL texture, return null if there is no current OpenGL context or the
* texture is invalid. Note:
* 1. The target of texture must be GL_TEXTURE_2D.
* 2. The texture should not bind to any frameBuffer.
* 3. PAG will use the current (OpenGL) context.
*/
public static PAGSurface FromTexture(int textureID, int width, int height, boolean flipY);
/**
* Create a PAGSurface from specified OpenGL texture, return null if there is no current OpenGL context or the
* texture is invalid. Note:
* 1. The target of texture must be GL_TEXTURE_2D.
* 2. The texture should not bind to any frameBuffer.
* 3. PAG will use a shared (OpenGL) context with the current.
* 4. The caller can use fence sync objects to synchronise texture content (see
* {@link PAGPlayer#flushAndFenceSync(long[])} and {@link PAGPlayer#waitSync(long)}).
*
* @see PAGPlayer#flushAndFenceSync(long[])
* @see PAGPlayer#waitSync(long)
*/
public static PAGSurface FromTextureForAsyncThread(int textureID, int width, int height) ;
/**
* Create a PAGSurface from specified OpenGL texture, return null if there is no current OpenGL context or the
* texture is invalid. Note:
* 1. The target of texture must be GL_TEXTURE_2D.
* 2. The texture should not bind to any frameBuffer.
* 3. PAG will use a shared (OpenGL) context with the current.
* 4. The caller can use fence sync objects to synchronise texture content (see
* {@link PAGPlayer#flushAndFenceSync(long[])} and {@link PAGPlayer#waitSync(long)}).
*
* @see PAGPlayer#flushAndFenceSync(long[])
* @see PAGPlayer#waitSync(long)
*/
public static PAGSurface FromTextureForAsyncThread(int textureID, int width, int height, boolean flipY);
/**
* Returns a bitmap capturing the contents of the PAGSurface. Subsequent rendering of the
* PAGSurface will not be captured.
*/
public native Bitmap makeSnapshot();
PAGPlayer
PAGPlayer acts as the play control class for PAG, encompassing PAGSurface and PAGComposition. It provides a range of functionalities to enhance the rendering process management. These include controlling the rendering progress using setProgress, completing the rendering of the current frame with flush, retrieving position information of each PAGLayer relative to the PAGSurface rendering canvas through the getBounds interface, and obtaining all layers at a specific position using getLayersUnderPoint.
// C++
/**
* Returns the current PAGComposition for PAGPlayer to render as content.
*/
std::shared_ptr<PAGComposition> getComposition();
/**
* Sets a new PAGComposition for PAGPlayer to render as content.
* Note: If the composition is already added to another PAGPlayer, it will be removed from the
* previous PAGPlayer.
*/
void setComposition(std::shared_ptr<PAGComposition> newComposition);
/**
* Returns the PAGSurface object for PAGPlayer to render onto.
*/
std::shared_ptr<PAGSurface> getSurface();
/**
* Set the PAGSurface object for PAGPlayer to render onto.
*/
void setSurface(std::shared_ptr<PAGSurface> newSurface);
/**
* Returns the current progress of play position, the value is from 0.0 to 1.0.
*/
double getProgress();
/**
* Sets the progress of play position, the value ranges from 0.0 to 1.0. It is applied only when
* the composition is not null.
*/
void setProgress(double percent);
/**
* Apply all pending changes to the target surface immediately. Returns true if the content has
* changed.
*/
bool flush();
/**
* Returns a rectangle that defines the displaying area of the specified layer, which is in the
* coordinate of the PAGSurface.
*/
Rect getBounds(std::shared_ptr<PAGLayer> pagLayer);
/**
* Returns an array of layers that lie under the specified point. The point is in the coordinate
* space of the PAGSurface.
*/
std::vector<std::shared_ptr<PAGLayer>> getLayersUnderPoint(float surfaceX, float surfaceY);
PAGView
PAGView is primarily utilized in UI animation scenarios on various platforms, including Android, iOS, macOS, Web, and WeChat mini programs. PAGView inherits from UIView in iOS, while it inherits from TextView in Android. PAGView supports loading through local paths and PAGComposition, with the play method used for animation play. It incorporates an internal timer and offers an interface for the PAGViewListener to monitor animation status. Internally, PAGView encapsulates PAGPlayer, PAGSurface, and PAGComposition for seamless implementation.
// Taking the iOS platform as an example
@protocol PAGViewListener <NSObject>
@optional
/**
* Notifies the start of the animation.
*/
- (void)onAnimationStart:(PAGView*)pagView;
/**
* Notifies the end of the animation.
*/
- (void)onAnimationEnd:(PAGView*)pagView;
/**
* Notifies the cancellation of the animation.
*/
- (void)onAnimationCancel:(PAGView*)pagView;
/**
* Notifies the repetition of the animation.
*/
- (void)onAnimationRepeat:(PAGView*)pagView;
/**
* Notifies the occurrence of another frame of the animation.
*/
- (void)onAnimationUpdate:(PAGView*)pagView;
@end
/**
* Adds a listener to the set of listeners that are sent events through the life of an animation,
* such as start, repeat, and end.
*/
- (void)addListener:(id<PAGViewListener>)listener;
/**
* Removes a listener from the set listening to this animation.
*/
- (void)removeListener:(id<PAGViewListener>)listener;
/**
* Indicates whether or not this pag view is playing.
*/
- (BOOL)isPlaying;
/**
* Start the animation.
*/
- (void)play;
/**
* Stop the animation.
*/
- (void)stop;
PAGDecoder
PAGDecoder is used to obtain the rendering data of the pag file. It supports creation through PAGComposition. The rendering size is consistent with the size of PAGCompositon. At the same time, the sacle parameter is added to support the user to set the rendering size. The maximum rendering frame rate can be set through the maxFrameRate parameter. At the data reading level, it supports obtaining UIImage, Bitmap and RGBA data.
If PAGComposition is created by path (PAGFile method), and there is no text editing, image replacement, and solid layer color replacement, the data rendered by PAGDecoder supports caching locally, and can be directly loaded into the local cache the next time it runs.
// C++
/**
* Creates a PAGDecoder with a PAGComposition, a frame rate limit, and a scale factor for the
* decoded image size. Please only keep an external reference to the PAGComposition if you need to
* modify it in the feature. Otherwise, the internal composition will not be released
* automatically after the associated disk cache is complete, which may cost more memory than
* necessary. Returns nullptr if the composition is nullptr. Note that the returned PAGDecoder may
* become invalid if the associated PAGComposition is added to a PAGPlayer or another PAGDecoder.
*/
static std::shared_ptr<PAGDecoder> MakeFrom(std::shared_ptr<PAGComposition> composition,
float maxFrameRate = 30.0f, float scale = 1.0f);
/**
* Returns the width of decoded image frames.
*/
int width() const {
return _width;
}
/**
* Returns the height of decoded image frames.
*/
int height() const {
return _height;
}
/**
* Returns the number of frames in the PAGDecoder. Note that the value may change if the
* associated PAGComposition was modified.
*/
int numFrames();
/**
* Returns the frame rate of decoded image frames. The value may change if the associated
* PAGComposition was modified.
*/
float frameRate();
/**
* Returns true if the frame at the given index has changed since the last readFrame() call. The
* caller should skip the corresponding reading call if the frame has not changed.
*/
bool checkFrameChanged(int index);
/**
* Reads pixels of the image frame at the given index into the specified memory address. Returns
* false if failed. Note that caller must ensure that colorType, alphaType, and dstRowBytes stay
* the same throughout every reading call. Otherwise, it may return false.
*/
bool readFrame(int index, void* pixels, size_t rowBytes,
ColorType colorType = ColorType::RGBA_8888,
AlphaType alphaType = AlphaType::Premultiplied);
/**
* Reads pixels of the image frame at the given index into the specified HardwareBuffer. Returns
* false if failed. Reading image frames into HardwareBuffer usually has better performance than
* reading into memory.
*/
bool readFrame(int index, HardwareBufferRef hardwareBuffer);
PAGDiskCache
PAGDiskCache is used to read, set the size of the disk cache and clear cache contents.
// C++
/**
* Defines methods to manage the disk cache capabilities.
*/
class PAG_API PAGDiskCache {
public:
/**
* Returns the size limit of the disk cache in bytes. The default value is 1 GB.
*/
static size_t MaxDiskSize();
/**
* Sets the size limit of the disk cache in bytes, which will triggers the cache cleanup if the
* disk usage exceeds the limit. The opened files are not removed immediately, even if their disk
* usage exceeds the limit, and they will be rechecked after they are closed.
*/
static void SetMaxDiskSize(size_t size);
/**
* Removes all cached files from the disk. All the opened files will be also removed after they
* are closed.
*/
static void RemoveAll();
};
PAGImageView
PAGImageView is primarily used in UI lists and situations where multiple pag files are simultaneously rendered. When implementing these scenarios with PAGView, multiple PAGViews need to be present, each requiring a GPU rendering environment. However, GPU rendering solutions typically come with an initial screen buffer overhead, resulting in increased memory usage. To address this, PAGImageView introduces disk caching functionality. For the rendered content, it will be cached locally. When the data cache of all frames is completed, the rendering environment of the PAG will be destroyed and the rest is the reading of disk data, which realizes the independence of pag file rendering and material. If the relevant content of the pag file has not been edited (such as editing text, replacing placeholder images, etc.), the next load will directly read the cached data without creating a PAG rendering environment. The cache in PAGImageView supports two modes: full disk and full memory. The default mode is full disk, where the memory usage is the smallest and the CPU usage is relatively low. The full memory mode exhibits the lowest CPU usage but requires higher memory usage. This mode is suitable for scenarios that demand high CPU usage with fewer frames in the PAG file.
/**
* If set to true, the PAGImageView loads all image frames into the memory, which will significantly
* increase the rendering performance but may cost lots of additional memory. Use it when you prefer
* rendering speed over memory usage. If set to false, the PAGImageView loads only one image frame
* at a time into the memory. The default value is false.
*/
- (BOOL)cacheAllFramesInMemory;
/**
* Sets the value of the cacheAllFramesInMemory property.
*/
- (void)setCacheAllFramesInMemory:(BOOL)enable;
At the API interface level, other related interfaces of PAGImageView are similar to those of PAGView.
PAGMovie
PAGMovie is a component of the Enterprise Edition that inherits from PAGImage and can directly replace the placeholder image of PAGImageLayer.
// C++
/**
* A movie used to replace the contents of PAGImageLayers in a PAGFile.
*/
class PAG_API PAGMovie : public PAGImage {
public:
/**
* Creates a PAGMovie from the video path, Return null if the file doesn't exist, or it isn't a
* valid video file.
* PAGMovie supports the mov,mp4,m4a,3gp,3g2 and mj2 container formats, and it supports the H264 and H265 encoding formats.
*/
static std::shared_ptr<PAGMovie> MakeFromFile(const std::string& filePath);
/**
* Creates a PAGMovie from the video path, Return null if the file doesn't exist, or it isn't a
* valid video file,or the start time is more than the origin duration of this movie.
* PAGMovie supports the mov,mp4,m4a,3gp,3g2 and mj2 container formats, and it supports the H264 and H265 encoding formats.
*/
static std::shared_ptr<PAGMovie> MakeFromFile(const std::string& filePath, int64_t startTime,
int64_t duration, float speed = 1.0f,
float volume = 1.0f);
/**
* Returns the duration of this movie in microseconds, it applies the speed of PAGMovie.
*/
virtual int64_t duration();
}
PAGAudioReader
PAGAudioReader is a component of the Enterprise Edition, which is used to read audio data according to the progress. The audio data here is a mixture of PAG built-in audio and PAGMovie audio.
// C++
/**
* Creates a PAGAudioReader to read audio frame.
*
* @param sampleRate the sample rate of output audio frame
* @param sampleCount the sample count of output audio frame
* @param channels the channel count of output audio frame
* @param volume the volume of output audio frame which is usually in the range [0 - 1.0].
*/
static std::shared_ptr<PAGAudioReader> Make(int sampleRate = 44100, int sampleCount = 1024,
int channels = 2, float volume = 1.0f);
/**
* Sets a new PAGComposition for PAGAudioReader to play as content.
* Note: If the composition is already added to another PAGAudioReader, it will be removed from
* the previous PAGAudioReader.
*/
void setComposition(std::shared_ptr<PAGComposition> newComposition);
/**
* Seeks to the specified target time.
*/
void seek(int64_t toTime);
/**
* Read the next audio frame.
* output format: PCM Signed 16
* if channels == 1, channel layout is MONO
* if channels == 2, channel layout is STEREO
*/
std::shared_ptr<PAGAudioSample> readNextSample();
/**
* Returns false if current composition has audio output, e.g. The PAG File has audio bytes or
* An movie have replaced the contents of PAGImageLayers in a PAGFile
*/
bool isEmpty();
PAGMovieExporter
PAGMovieExporter is an Enterprise Edition component used to export rendering results into video, including not only rendered images but also audio data.
// C++
/**
* Create a movie Exporter with the specified composition and output movie config.
*/
static std::shared_ptr<PAGMovieExporter> Make(
const std::shared_ptr<PAGComposition>& composition, const PAGExportConfig& config,
std::shared_ptr<PAGMovieExporter::Callback>& callback);
/**
* Start exporting movie asynchronously
*/
void start() = 0;
/**
* Cancel exporting movie
*/
void cancel() = 0;
};
}
Interpretation of Common Methods
PAG Runtime Editing
The runtime editing of PAG is mainly divided into two categories:
1) Modify the text information in the text layer, replace the placeholder image in the image layer, and modify the color in the solid layer
// C++
std::shared_ptr<pag::PAGFile> ReplaceImageOrText() {
auto pagFile = pag::PAGFile::Load("../../assets/test2.pag");
if (pagFile == nullptr) {
return nullptr;
}
for (int i = 0; i < pagFile->numImages(); i++) {
auto pagImage = pag::PAGImage::FromPath("../../assets/scene.png");
pagFile->replaceImage(i, pagImage);
}
for (int i = 0; i < pagFile->numTexts(); i++) {
auto textDocumentHandle = pagFile->getTextData(i);
textDocumentHandle->text = "hahaha👌";
pagFile->replaceText(i, textDocumentHandle);
}
return pagFile;
}
2) Rendering tree editing Rendering tree editing refers to the free combination of multiple layers and pag files by using the relevant interface of PAGComposition. For specific usage, please refer to the following codes:
// Take the OC version as an example
- (PAGComposition *)makeComposition {
PAGComposition* compostion = [PAGComposition Make:self.view.bounds.size];
float itemWidth = self.view.bounds.size.width / 5;
float itemHeight = 100;
for (int i = 0; i < 20; i++) {
PAGFile* pagFile = [self getPAGFile:i / 5 clume:i % 5 name:[NSString stringWithFormat:@"%d", i] itemWidth:itemWidth itemHeight:itemHeight];
[compostion addLayer:pagFile];
}
return compostion;
}
- (PAGFile*)getPAGFile:(int)row clume:(int)colume name:(NSString*)name itemWidth:(float)itemWidth itemHeight:(float)itemHeight {
PAGFile* pagFile = [PAGFile Load:[[NSBundle mainBundle] pathForResource:name ofType:@"pag"]];
if (pagFile) {
float scaleX = itemWidth * 1.0f / [pagFile width];
CGAffineTransform transform = CGAffineTransformMakeScale(scaleX, scaleX);
CGAffineTransform tranflate = CGAffineTransformMakeTranslation(itemWidth * colume, row * itemHeight + 150);
transform = CGAffineTransformConcat(transform, tranflate);
[pagFile setMatrix:transform];
[pagFile setStartTime:0];
[pagFile setDuration:10000000];
}
return pagFile;
}
PAG UI and List Scenario Usage
When a page contains multiple pag files and multiple PAGViews are used, as each PAGView requires an independent rendering environment, the memory and CPU usage will be relatively high. To mitigate this, two recommended processing methods are available:
1)You can add multiple PAG files to the same PAGComposition by using the combination mode of PAG. This approach reduces the need for multiple rendering environments, resulting in lower memory and CPU usage. Detailed information on how to achieve this can be found in the "Editing at Runtime" section. For a practical demonstration, please refer to the demo project provided with PAG:
Android:https://github.com/libpag/pag-android
iOS: https://github.com/libpag/pag-ios
2)In specific UI list scenarios, where multiple views need to coexist, adding the pag file to a PAGComposition might not be feasible. In such cases, the PAGImageView can serve as a viable alternative. For more detailed guidance, please refer to the section on Use PAGImageView.
PAG Font Registration
In addition to modifying the text information of the text layer, PAG also supports modifying the font. These are the specific methods:
(1)Obtain font related information through PAGFont and assign values to PAGText. The interface used is as follows: Obtain font information
// C++
/**
* Registers a font required by the text layers in pag files, so that they can be rendered as
* designed.
*/
static PAGFont RegisterFont(const std::string& fontPath, int ttcIndex,
const std::string& fontFamily = "",
const std::string& fontStyle = "");
/**
* Registers a font required by the text layers in pag files, so that they can be rendered as
* designed.
*/
static PAGFont RegisterFont(const void* data, size_t length, int ttcIndex,
const std::string& fontFamily = "",
const std::string& fontStyle = "");
PAGFont(std::string fontFamily, std::string fontStyle)
: fontFamily(std::move(fontFamily)), fontStyle(std::move(fontStyle)) {
}
/**
* A string with the name of the font family.
**/
const std::string fontFamily;
/**
* A string with the style information — e.g., “bold”, “italic”.
**/
const std::string fontStyle;
(2) Assign values to PAGText through fontFamlily and fontStyle, which is then filled into PAGTextLayer.
// C++
for (int i = 0; i < pagFile->numTexts(); i++) {
auto textDocumentHandle = pagFile->getTextData(i);
textDocumentHandle->text = "hahaha👌";
// Use special font
auto pagFont = pag::PAGFont::RegisterFont("../../resources/font/NotoSansSC-Regular.otf", 0);
textDocumentHandle->fontFamily = pagFont.fontFamily;
textDocumentHandle->fontStyle = pagFont.fontStyle;
pagFile->replaceText(i, textDocumentHandle);
}
Internally, PAG (available for Android, iOS, macOS, and Windows platforms) includes a default font list (it also permits external configuration of the font fallback list, and the external setting will supersede the default setting). If a specific font is used but not registered or doesn't include the required characters, PAG will fall back to its default font list. However, the business side may have concerns about using such fonts due to potential uncertainties.
// C++
/**
* Resets the fallback font names. It should be called only once when the application is being
* initialized.
*/
static void SetFallbackFontNames(const std::vector<std::string>& fontNames);
/**
* Resets the fallback font paths. It should be called only once when the application is being
* initialized.
*/
static void SetFallbackFontPaths(const std::vector<std::string>& fontPaths,
const std::vector<int>& ttcIndices);
PAG Video Editing Scenarios
In the video editing scenarios, instead of PAGView, PAGPlayer, PAGSurface and PAGComposition are used.
PAGSurface can be created using either CVPixelBufferRef or texture, seamlessly integrating with video post-editing. Furthermore, PAGImage supports creation through CVPixelBufferRef or texture, allowing control of play progress via PAGPlayer and filling video content into the placeholder image of the image layer.
// OC
/**
* Creates a PAGImage object from the specified CVPixelBuffer, return null if the CVPixelBuffer is
* invalid.
*/
+ (PAGImage*)FromPixelBuffer:(CVPixelBufferRef)pixelBuffer;
// java
public static PAGImage FromTexture(int textureID, int textureTarget, int width, int height);
public static PAGImage FromTexture(int textureID, int textureTarget, int width, int height, boolean flipY);
If you need to export video, you can use PAG Enterprise Edition.
PAG Software Decoder Injection
Why is software decoder injection necessary? The PAG export method supports BMP composition export. In the pag file, each BMP composition is equivalent to a video that needs to be decoded. Although the PAG SDK uses hardware decoding by default, there are two issues with this approach:
1)The number of instantaneous hardware decoders on mobile devices is limited, and creating an infinite number of decoders is not possible. If the number of created hardware decoders exceeds the limit, decoding failures may occur, especially in video editing scenarios
2)Due to model compatibility and fragmented verification, not all models can be successfully decoded by hardware on the Android platform. Therefore, software decoding is necessary on Android to ensure compatibility
The provided prebuilt library does not have a software decoder by default on the iOS platform due to compatibility limitations. However, Android offers two packages: the common package includes a built-in software decoder, while the noffavc package does not. Specifically, how to inject a software decoder: you can choose the complete prebuilt library for the Android platform, and introduce ffavc for the iOS platform.
pod 'ffavc'
Complete the registration of the software decoder by the following methods:
// OC
-(void)registerSoftwareDecoder {
// Registering software decoder factory pointer.
auto factory = ffavc::DecoderFactory::GetHandle();
[PAGVideoDecoder RegisterSoftwareDecoderFactory:(void*)factory];
}
If the user has a built-in software decoder library in their own APP, they can incorporate the software decoder through external injection. The PAG official website provides the following interface for software decoder injection, which needs to be implemented by the business side using their own decoders. The video encoding format in the PAG BMP composition is h264. https://github.com/libpag/ffavc/blob/main/vendor/libpag/include/pag/decoder.h
For specific implementation method, you can refer to: https://github.com/libpag/ffavc/blob/main/src/decoder/FFAVCDecoder.cpp
By following the aforementioned method, you can independently inject the software decoder.
PAG Server Rendering
Unlike Lottie and SVGA, PAG offers server rendering capabilities. While PAG's rendering relies on the OpenGL environment, the server can still utilize the CPU server. At the implementation level, PAG establishes an OpenGL environment on the CPU server using swiftshader. This enables normal rendering of the pag file within the CPU environment. The specific use on the server side is as follows. The obtained data is in BGRA format and can be utilized for video encoding purposes.
// C++
auto pagFile = pag::PAGFile::Load("../../assets/test2.pag");
auto pagSurface = pag::PAGSurface::MakeOffscreen(pagFile->width(), pagFile->height());
if (pagSurface == nullptr) {
printf("---pagSurface is nullptr!!!\n");
return -1;
}
auto pagPlayer = new pag::PAGPlayer();
pagPlayer->setSurface(pagSurface);
pagPlayer->setComposition(pagFile);
auto totalFrames = TimeToFrame(pagFile->duration(), pagFile->frameRate());
auto currentFrame = 0;
int bytesLength = pagFile->width() * pagFile->height() * 4;
while (currentFrame <= totalFrames) {
pagPlayer->setProgress(currentFrame * 1.0 / totalFrames);
auto status = pagPlayer->flush();
// PAG rendering data reading
auto data = new uint8_t[bytesLength];
pagSurface->readPixels(pag::ColorType::BGRA_8888, pag::AlphaType::Premultiplied, data,
pagFile->width() * 4);
delete[] data;
currentFrame++;
}
delete pagPlayer;