QPixmap MediaPreviewWidget::currentImage() const { if (_document) { if (_document->sticker()) { if (_cacheStatus != CacheLoaded) { _document->checkSticker(); if (_document->sticker()->img->isNull()) { if (_cacheStatus != CacheThumbLoaded && _document->thumb->loaded()) { QSize s = currentDimensions(); _cache = _document->thumb->pixBlurred(s.width(), s.height()); _cacheStatus = CacheThumbLoaded; } } else { QSize s = currentDimensions(); _cache = _document->sticker()->img->pix(s.width(), s.height()); _cacheStatus = CacheLoaded; } } } else { _document->automaticLoad(nullptr); if (_document->loaded()) { if (!_gif && _gif != BadClipReader) { MediaPreviewWidget *that = const_cast<MediaPreviewWidget*>(this); that->_gif = new ClipReader(_document->location(), _document->data(), func(that, &MediaPreviewWidget::clipCallback)); if (gif()) _gif->setAutoplay(); } } if (gif() && _gif->started()) { QSize s = currentDimensions(); return _gif->current(s.width(), s.height(), s.width(), s.height(), getms()); } if (_cacheStatus != CacheThumbLoaded && _document->thumb->loaded()) { QSize s = currentDimensions(); _cache = _document->thumb->pixBlurred(s.width(), s.height()); _cacheStatus = CacheThumbLoaded; } } } else if (_photo) { if (_cacheStatus != CacheLoaded) { if (_photo->full->loaded()) { QSize s = currentDimensions(); LOG(("DIMENSIONS: %1 %2").arg(s.width()).arg(s.height())); _cache = _photo->full->pix(s.width(), s.height()); _cacheStatus = CacheLoaded; } else { if (_cacheStatus != CacheThumbLoaded && _photo->thumb->loaded()) { QSize s = currentDimensions(); LOG(("DIMENSIONS: %1 %2").arg(s.width()).arg(s.height())); _cache = _photo->thumb->pixBlurred(s.width(), s.height()); _cacheStatus = CacheThumbLoaded; } _photo->thumb->load(); _photo->full->load(); } } } return _cache; }
bool ParupaintPanvasInputOutput::loadGIF(ParupaintPanvas * panvas, const QString & filename, QString & errorStr) { Q_ASSERT(panvas); QMovie gif(filename); if(!gif.isValid()) return (errorStr = "Couldn't load GIF.").isEmpty(); gif.jumpToFrame(0); panvas->setBackgroundColor(Qt::transparent); panvas->clearCanvas(); panvas->resize(gif.frameRect().size()); panvas->newCanvas(1, 0); do { const QImage & gif_image = gif.currentImage().convertToFormat(QImage::Format_ARGB32); ParupaintFrame * gif_frame = new ParupaintFrame(gif_image); panvas->layerAt(0)->appendFrame(gif_frame); gif.jumpToNextFrame(); } while(gif.currentFrameNumber() != 0); return true; }
/* * Read enough of the stream to initialize the SkGifCodec. * Returns a bool representing success or failure. * * @param codecOut * If it returned true, and codecOut was not nullptr, * codecOut will be set to a new SkGifCodec. * * @param gifOut * If it returned true, and codecOut was nullptr, * gifOut must be non-nullptr and gifOut will be set to a new * GifFileType pointer. * * @param stream * Deleted on failure. * codecOut will take ownership of it in the case where we created a codec. * Ownership is unchanged when we returned a gifOut. * */ bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** gifOut) { SkAutoTDelete<SkStream> streamDeleter(stream); // Read gif header, logical screen descriptor, and global color table SkAutoTCallVProc<GifFileType, CloseGif> gif(open_gif(stream)); if (nullptr == gif) { gif_error("DGifOpen failed.\n"); return false; } // Read through gif extensions to get to the image data. Set the // transparent index based on the extension data. uint32_t transIndex; SkCodec::Result result = ReadUpToFirstImage(gif, &transIndex); if (kSuccess != result){ return false; } // Read the image descriptor if (GIF_ERROR == DGifGetImageDesc(gif)) { return false; } // If reading the image descriptor is successful, the image count will be // incremented. SkASSERT(gif->ImageCount >= 1); if (nullptr != codecOut) { SkISize size; SkIRect frameRect; if (!GetDimensions(gif, &size, &frameRect)) { gif_error("Invalid gif size.\n"); return false; } bool frameIsSubset = (size != frameRect.size()); // Determine the encoded alpha type. The transIndex might be valid if it less // than 256. We are not certain that the index is valid until we process the color // table, since some gifs have color tables with less than 256 colors. If // there might be a valid transparent index, we must indicate that the image has // alpha. // In the case where we must support alpha, we indicate kBinary, since every // pixel will either be fully opaque or fully transparent. SkEncodedInfo::Alpha alpha = (transIndex < 256) ? SkEncodedInfo::kBinary_Alpha : SkEncodedInfo::kOpaque_Alpha; // Return the codec // Use kPalette since Gifs are encoded with a color table. // Use 8-bits per component, since this is the output we get from giflib. // FIXME: Gifs can actually be encoded with 4-bits per pixel. Can we support this? SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8); *codecOut = new SkGifCodec(size.width(), size.height(), info, streamDeleter.release(), gif.release(), transIndex, frameRect, frameIsSubset); } else { SkASSERT(nullptr != gifOut); streamDeleter.release(); *gifOut = gif.release(); } return true; }
void StickerPreviewWidget::showPreview(DocumentData *sticker) { if (sticker && !sticker->isAnimation() && !sticker->sticker()) sticker = 0; if (sticker) { _cache = QPixmap(); if (isHidden() || _a_shown.animating()) { if (isHidden()) show(); a_shown.start(1); _a_shown.start(); } else { update(); } } else if (isHidden()) { return; } else { if (_gif) _cache = currentImage(); a_shown.start(0); _a_shown.start(); } _doc = sticker; if (_gif) { if (gif()) { delete _gif; } _gif = 0; } _cacheStatus = CacheNotLoaded; }
FrameSegment::FrameSegment(const QString &gifFileName){ Q_ASSERT(gifFileName.endsWith("gif")); QMovie gif(gifFileName); if(!gif.isValid()){ return; } gif.start(); gif.setPaused(true); for(int i=0,size=gif.frameCount();i<size;++i){ QImage frame=gif.currentImage(); Q_ASSERT(!frame.isNull()); frames_.append(Frame(frame,gif.nextFrameDelay())); gif.jumpToNextFrame(); } gif.stop(); }
int cellGifDecDecodeData(u32 mainHandle, u32 subHandle, mem8_ptr_t data, const mem_ptr_t<CellGifDecDataCtrlParam> dataCtrlParam, mem_ptr_t<CellGifDecDataOutInfo> dataOutInfo) { if (!data.IsGood() || !dataCtrlParam.IsGood() || !dataOutInfo.IsGood()) return CELL_GIFDEC_ERROR_ARG; dataOutInfo->status = CELL_GIFDEC_DEC_STATUS_STOP; CellGifDecSubHandle* subHandle_data; if(!cellGifDec->CheckId(subHandle, subHandle_data)) return CELL_GIFDEC_ERROR_FATAL; const u32& fd = subHandle_data->fd; const u64& fileSize = subHandle_data->fileSize; const CellGifDecOutParam& current_outParam = subHandle_data->outParam; //Copy the GIF file to a buffer MemoryAllocator<unsigned char> gif(fileSize); MemoryAllocator<u64> pos, nread; cellFsLseek(fd, 0, CELL_SEEK_SET, pos); cellFsRead(fd, gif.GetAddr(), gif.GetSize(), nread); //Decode GIF file. (TODO: Is there any faster alternative? Can we do it without external libraries?) int width, height, actual_components; std::shared_ptr<unsigned char> image(stbi_load_from_memory(gif, fileSize, &width, &height, &actual_components, 4)); if (!image) return CELL_GIFDEC_ERROR_STREAM_FORMAT; uint image_size = width * height * 4; switch((u32)current_outParam.outputColorSpace) { case CELL_GIFDEC_RGBA: if (!Memory.CopyFromReal(data.GetAddr(), image.get(), image_size)) { cellGifDec->Error("cellGifDecDecodeData() failed (dataa_addr=0x%x)", data.GetAddr()); return CELL_EFAULT; } break; case CELL_GIFDEC_ARGB: for(uint i = 0; i < image_size; i+=4) { data += image.get()[i+3]; data += image.get()[i+0]; data += image.get()[i+1]; data += image.get()[i+2]; } break; default: return CELL_GIFDEC_ERROR_ARG; } dataOutInfo->status = CELL_GIFDEC_DEC_STATUS_FINISH; dataOutInfo->recordType = CELL_GIFDEC_RECORD_TYPE_IMAGE_DESC; return CELL_OK; }
void MediaPreviewWidget::resetGifAndCache() { if (_gif) { if (gif()) { delete _gif; } _gif = nullptr; } _cacheStatus = CacheNotLoaded; _cachedSize = QSize(); }
QPixmap StickerPreviewWidget::currentImage() const { if (_doc) { if (_doc->sticker()) { if (_cacheStatus != CacheLoaded) { _doc->checkSticker(); if (_doc->sticker()->img->isNull()) { if (_cacheStatus != CacheThumbLoaded && _doc->thumb->loaded()) { QSize s = currentDimensions(); _cache = _doc->thumb->pixBlurred(s.width(), s.height()); _cacheStatus = CacheThumbLoaded; } } else { QSize s = currentDimensions(); _cache = _doc->sticker()->img->pix(s.width(), s.height()); _cacheStatus = CacheLoaded; } } } else { _doc->automaticLoad(0); if (_doc->loaded()) { if (!_gif && _gif != BadClipReader) { StickerPreviewWidget *that = const_cast<StickerPreviewWidget*>(this); that->_gif = new ClipReader(_doc->location(), _doc->data(), func(that, &StickerPreviewWidget::clipCallback)); if (gif()) _gif->setAutoplay(); } } if (gif() && _gif->started()) { QSize s = currentDimensions(); return _gif->current(s.width(), s.height(), s.width(), s.height(), getms()); } if (_cacheStatus != CacheThumbLoaded && _doc->thumb->loaded()) { QSize s = currentDimensions(); _cache = _doc->thumb->pixBlurred(s.width(), s.height()); _cacheStatus = CacheThumbLoaded; } } } return _cache; }
void StickerPreviewWidget::clipCallback(ClipReaderNotification notification) { switch (notification) { case ClipReaderReinit: { if (gif() && _gif->state() == ClipError) { delete _gif; _gif = BadClipReader; } if (gif() && _gif->ready() && !_gif->started()) { QSize s = currentDimensions(); _gif->start(s.width(), s.height(), s.width(), s.height(), false); } update(); } break; case ClipReaderRepaint: { if (gif() && !_gif->currentDisplayed()) { update(); } } break; } }
QSize StickerPreviewWidget::currentDimensions() const { if (!_doc) return QSize(_cache.width() / cIntRetinaFactor(), _cache.height() / cIntRetinaFactor()); QSize result(qMax(convertScale(_doc->dimensions.width()), 1), qMax(convertScale(_doc->dimensions.height()), 1)); if (gif() && _gif->ready()) { result = QSize(qMax(convertScale(_gif->width()), 1), qMax(convertScale(_gif->height()), 1)); } if (result.width() > st::maxStickerSize) { result.setHeight(qMax(qRound((st::maxStickerSize * result.height()) / result.width()), 1)); result.setWidth(st::maxStickerSize); } if (result.height() > st::maxStickerSize) { result.setWidth(qMax(qRound((st::maxStickerSize * result.width()) / result.height()), 1)); result.setHeight(st::maxStickerSize); } return result; }
QSize MediaPreviewWidget::currentDimensions() const { if (!_cachedSize.isEmpty()) { return _cachedSize; } if (!_document && !_photo) { _cachedSize = QSize(_cache.width() / cIntRetinaFactor(), _cache.height() / cIntRetinaFactor()); return _cachedSize; } QSize result, box; if (_photo) { result = QSize(_photo->full->width(), _photo->full->height()); box = QSize(width() - 2 * st::boxVerticalMargin, height() - 2 * st::boxVerticalMargin); } else { result = _document->dimensions; if (gif() && _gif->ready()) { result = QSize(_gif->width(), _gif->height()); } if (_document->sticker()) { box = QSize(st::maxStickerSize, st::maxStickerSize); } else { box = QSize(2 * st::maxStickerSize, 2 * st::maxStickerSize); } } result = QSize(qMax(convertScale(result.width()), 1), qMax(convertScale(result.height()), 1)); if (result.width() > box.width()) { result.setHeight(qMax((box.width() * result.height()) / result.width(), 1)); result.setWidth(box.width()); } if (result.height() > box.height()) { result.setWidth(qMax((box.height() * result.width()) / result.height(), 1)); result.setHeight(box.height()); } if (_photo) { _cachedSize = result; } return result; }
/* * Read enough of the stream to initialize the SkGifCodec. * Returns a bool representing success or failure. * * @param codecOut * If it returned true, and codecOut was not nullptr, * codecOut will be set to a new SkGifCodec. * * @param gifOut * If it returned true, and codecOut was nullptr, * gifOut must be non-nullptr and gifOut will be set to a new * GifFileType pointer. * * @param stream * Deleted on failure. * codecOut will take ownership of it in the case where we created a codec. * Ownership is unchanged when we returned a gifOut. * */ bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** gifOut) { SkAutoTDelete<SkStream> streamDeleter(stream); // Read gif header, logical screen descriptor, and global color table SkAutoTCallVProc<GifFileType, CloseGif> gif(open_gif(stream)); if (nullptr == gif) { gif_error("DGifOpen failed.\n"); return false; } // Read through gif extensions to get to the image data. Set the // transparent index based on the extension data. uint32_t transIndex; SkCodec::Result result = ReadUpToFirstImage(gif, &transIndex); if (kSuccess != result){ return false; } // Read the image descriptor if (GIF_ERROR == DGifGetImageDesc(gif)) { return false; } // If reading the image descriptor is successful, the image count will be // incremented. SkASSERT(gif->ImageCount >= 1); if (nullptr != codecOut) { SkISize size; SkIRect frameRect; if (!GetDimensions(gif, &size, &frameRect)) { gif_error("Invalid gif size.\n"); return false; } bool frameIsSubset = (size != frameRect.size()); // Determine the recommended alpha type. The transIndex might be valid if it less // than 256. We are not certain that the index is valid until we process the color // table, since some gifs have color tables with less than 256 colors. If // there might be a valid transparent index, we must indicate that the image has // alpha. // In the case where we must support alpha, we have the option to set the // suggested alpha type to kPremul or kUnpremul. Both are valid since the alpha // component will always be 0xFF or the entire 32-bit pixel will be set to zero. // We prefer kPremul because we support kPremul, and it is more efficient to use // kPremul directly even when kUnpremul is supported. SkAlphaType alphaType = (transIndex < 256) ? kPremul_SkAlphaType : kOpaque_SkAlphaType; // Return the codec // kIndex is the most natural color type for gifs, so we set this as // the default. SkImageInfo imageInfo = SkImageInfo::Make(size.width(), size.height(), kIndex_8_SkColorType, alphaType); *codecOut = new SkGifCodec(imageInfo, streamDeleter.detach(), gif.detach(), transIndex, frameRect, frameIsSubset); } else { SkASSERT(nullptr != gifOut); streamDeleter.detach(); *gifOut = gif.detach(); } return true; }
void genstmt(NODE *n) { VREG *muuo_ac; if (n == NULL) return; switch (n->Nop) { case N_STATEMENT: { NODE *beg, *next; if (n->Nleft && n->Nleft->Nop == N_DATA) { /* Check for auto inits */ genadata(n->Nleft); /* Yep, do them */ n = n->Nright; /* then move on to real statements */ } for(beg = n; n != NULL; n = n->Nright) { if(n->Nop != N_STATEMENT) int_error("genstmt: bad stmt %N", n); if(n->Nleft == NULL) continue; /* Check out following stmt for possible optimizations */ if(n->Nright && (next = n->Nright->Nleft) != NULL && optgen) { switch(next->Nop) { /* Hack to encourage tail recursion */ case Q_RETURN: /* If next will be RETURN */ if(next->Nright == NULL) { /* and has no return val */ NODE *v; /* Then try to optimize */ if((v = laststmt(n->Nleft)) != NULL && v->Nop == N_FNCALL) v->Nflag |= NF_RETEXPR; } break; /* If next stmt is a GOTO, ensure that any jumps * within current stmt to end of stmt will * instead go directly to object of the GOTO. * Avoids jumping to jumps... * We do a similar hack for BREAK and CONTINUE, * which are similar to GOTOs except that their * destination is kept in variables global to the * code generation routines. */ case Q_CASE: /* Not sure about this one yet */ case N_LABEL: case Q_GOTO: n->Nleft->Nendlab = next->Nxfsym; break; case Q_BREAK: n->Nleft->Nendlab = brklabel; break; case Q_CONTINUE: n->Nleft->Nendlab = looplabel; break; default: ; /* do nothing */ } /* end of Nop switch */ } /* end of next-stmt check */ /* Optimize label usage */ if(n->Nright == NULL /* If this is last stmt in list */ && optgen) n->Nleft->Nendlab = beg->Nendlab; /* Copy from 1st */ genstmt(n->Nleft); } break; } /* end of N_STATEMENT case block */ case Q_CASE: codlabel(n->Nxfsym); /* send forward label */ n->Nleft->Nendlab = n->Nendlab; /* propagate end label */ genstmt (n->Nleft); /* finish rest of body */ break; case N_LABEL: if (n->Nxfsym->Sname[0] == '%' && isdigit(n->Nxfsym->Sname[1])) code_debugcall(n); else codgolab(n->Nxfsym); /* send goto label */ n->Nleft->Nendlab = n->Nendlab; /* propagate end label */ genstmt(n->Nleft); /* finish rest of body */ break; case Q_BREAK: code6(P_JRST, NULL, brklabel); break; case Q_GOTO: code6(P_JRST, NULL, n->Nxfsym); break; case Q_CONTINUE: code6(P_JRST, NULL, looplabel); break; case Q_DO: gdo(n); break; case Q_FOR: gfor(n); break; case Q_IF: gif(n); break; case Q_RETURN: greturn(n); break; case Q_SWITCH: gswitch(n); break; case Q_WHILE: gwhile(n); break; #if SYS_CSI /* Added 1/91 for in-line monitor calls; KAR */ case Q_MUUO: muuo_ac = gmuuo(n); vrfree(muuo_ac); break; #endif case N_EXPRLIST: /* Same as expression stmt */ default: /* None of above, assume expression stmt */ genxrelease(n); /* Generate it and flush any result */ break; } }